Select what to sanitize.
fsanitize-coverage=
-Common Joined Enum(sanitize_coverage) Var(flag_sanitize_coverage) EnumSet
+Common Joined Enum(sanitize_coverage) Var(flag_sanitize_coverage) EnumBitSet
Select type of coverage sanitization.
Enum
Name(sanitize_coverage) Type(int)
EnumValue
-Enum(sanitize_coverage) String(trace-pc) Value(SANITIZE_COV_TRACE_PC) Set(1)
+Enum(sanitize_coverage) String(trace-pc) Value(SANITIZE_COV_TRACE_PC)
EnumValue
-Enum(sanitize_coverage) String(trace-cmp) Value(SANITIZE_COV_TRACE_CMP) Set(2)
+Enum(sanitize_coverage) String(trace-cmp) Value(SANITIZE_COV_TRACE_CMP)
fasan-shadow-offset=
Common Joined RejectNegative Var(common_deferred_options) Defer
Or option's argument can be a comma separated list of strings where
each string is from a different @code{Set(@var{number})}.
+@item EnumBitSet
+Must be used together with the @code{Enum(@var{name})} property.
+Similar to @samp{EnumSet}, but corresponding @samp{Enum} record must
+not use @code{Set} properties, each @code{EnumValue} should have
+@code{Value} that is a power of 2, each value is treated as its own
+set and its value as the set's mask, so there are no mutually
+exclusive arguments.
+
@item Defer
The option should be stored in a vector, specified with @code{Var},
for later processing.
if (flag_set_p("Enum.*", flags)) {
en = opt_args("Enum", flags);
if (flag_set_p("EnumSet", flags))
- return enum_index[en] ", CLVC_ENUM, 1"
+ return enum_index[en] ", CLVC_ENUM, CLEV_SET"
+ else if (flag_set_p("EnumBitSet", flags))
+ return enum_index[en] ", CLVC_ENUM, CLEV_BITSET"
else
- return enum_index[en] ", CLVC_ENUM, 0"
+ return enum_index[en] ", CLVC_ENUM, CLEV_NORMAL"
}
if (var_type(flags) == "const char *")
return "0, CLVC_STRING, 0"
if (flag_set_p("Enum.*", flags[i])) {
if (!flag_set_p("RejectNegative", flags[i]) \
&& !flag_set_p("EnumSet", flags[i]) \
+ && !flag_set_p("EnumBitSet", flags[i]) \
&& opts[i] ~ "^[Wfgm]")
print "#error Enum allowing negative form"
}
{
const struct cl_enum *e = &cl_enums[option->var_enum];
- gcc_assert (option->var_value || value == 1);
- if (option->var_value)
+ gcc_assert (option->var_value != CLEV_NORMAL || value == 1);
+ if (option->var_value != CLEV_NORMAL)
{
const char *p = arg;
HOST_WIDE_INT sum_value = 0;
break;
}
- unsigned set = e->values[idx].flags >> CL_ENUM_SET_SHIFT;
- gcc_checking_assert (set >= 1 && set <= HOST_BITS_PER_WIDE_INT);
- if ((used_sets & (HOST_WIDE_INT_1U << (set - 1))) != 0)
+ HOST_WIDE_INT this_mask = 0;
+ if (option->var_value == CLEV_SET)
{
- errors |= CL_ERR_ENUM_SET_ARG;
- break;
+ unsigned set = e->values[idx].flags >> CL_ENUM_SET_SHIFT;
+ gcc_checking_assert (set >= 1
+ && set <= HOST_BITS_PER_WIDE_INT);
+ if ((used_sets & (HOST_WIDE_INT_1U << (set - 1))) != 0)
+ {
+ errors |= CL_ERR_ENUM_SET_ARG;
+ break;
+ }
+ used_sets |= HOST_WIDE_INT_1U << (set - 1);
+
+ for (int i = 0; e->values[i].arg != NULL; i++)
+ if (set == (e->values[i].flags >> CL_ENUM_SET_SHIFT))
+ this_mask |= e->values[i].value;
+ }
+ else
+ {
+ gcc_assert (option->var_value == CLEV_BITSET
+ && ((e->values[idx].flags >> CL_ENUM_SET_SHIFT)
+ == 0));
+ this_mask = this_value;
}
- used_sets |= HOST_WIDE_INT_1U << (set - 1);
-
- HOST_WIDE_INT this_mask = 0;
- for (int i = 0; e->values[i].arg != NULL; i++)
- if (set == (e->values[i].flags >> CL_ENUM_SET_SHIFT))
- this_mask |= e->values[i].value;
sum_value |= this_value;
mask |= this_mask;
break;
}
+ if (option->var_value == CLEV_BITSET)
+ {
+ if (q == NULL)
+ break;
+ p = q + 1;
+ continue;
+ }
+
unsigned set = e->values[idx].flags >> CL_ENUM_SET_SHIFT;
gcc_checking_assert (set >= 1 && set <= HOST_BITS_PER_WIDE_INT);
if ((used_sets & (HOST_WIDE_INT_1U << (set - 1))) != 0)
#endif
}
-/* Verify EnumSet requirements. */
+/* Verify EnumSet and EnumBitSet requirements. */
static void
test_enum_sets ()
{
for (unsigned i = 0; i < cl_options_count; ++i)
- if (cl_options[i].var_type == CLVC_ENUM && cl_options[i].var_value)
+ if (cl_options[i].var_type == CLVC_ENUM
+ && cl_options[i].var_value != CLEV_NORMAL)
{
const struct cl_enum *e = &cl_enums[cl_options[i].var_enum];
unsigned HOST_WIDE_INT used_sets = 0;
for (unsigned j = 0; e->values[j].arg; ++j)
{
unsigned set = e->values[j].flags >> CL_ENUM_SET_SHIFT;
+ if (cl_options[i].var_value == CLEV_BITSET)
+ {
+ /* For EnumBitSet Set shouldn't be used and Value should
+ be a power of two. */
+ ASSERT_TRUE (set == 0);
+ ASSERT_TRUE (pow2p_hwi (e->values[j].value));
+ continue;
+ }
/* Test that enumerators referenced in EnumSet have all
Set(n) on them within the valid range. */
ASSERT_TRUE (set >= 1 && set <= HOST_BITS_PER_WIDE_INT);
highest_set = MAX (set, highest_set);
used_sets |= HOST_WIDE_INT_1U << (set - 1);
}
+ if (cl_options[i].var_value == CLEV_BITSET)
+ continue;
/* If there is just one set, no point to using EnumSet. */
ASSERT_TRUE (highest_set >= 2);
/* Test that there are no gaps in between the sets. */
CLVC_DEFER
};
+/* Values for var_value member of CLVC_ENUM. */
+enum cl_enum_var_value {
+ /* Enum without EnumSet or EnumBitSet. */
+ CLEV_NORMAL,
+
+ /* EnumSet. */
+ CLEV_SET,
+
+ /* EnumBitSet. */
+ CLEV_BITSET
+};
+
struct cl_option
{
/* Text of the option, including initial '-'. */
/* PR sanitizer/104158 */
/* { dg-do compile } */
/* { dg-options "-fsanitize-coverage=trace-cmp,trace-cmp -fdump-tree-optimized" } */
-/* { dg-error "invalid argument in option '-fsanitize-coverage=trace-cmp,trace-cmp'" "" { target *-*-* } 0 } */
-/* { dg-message "'trace-cmp' specified multiple times in the same option" "" { target *-*-* } 0 } */
+/* { dg-final { scan-tree-dump "__sanitizer_cov_trace_cmp" "optimized" } } */
+/* { dg-final { scan-tree-dump-not "__sanitizer_cov_trace_pc" "optimized" } } */
+
+int
+foo (int a, int b)
+{
+ return a == b;
+}