On Sat, Jan 22, 2022 at 1:48 AM Jakub Jelinek via Gcc-patches <gcc-patches@gcc.gnu.org> wrote: > > Hi! > > The following patch is infrastructure support for at least 3 different > options that need changes: > 1) PR104158 talks about a regression with the -fsanitizer-coverage= > option; in GCC 11 and older and on trunk prior to r12-1177, this > option behaved similarly to -f{,no-}sanitizer{,-recover}= options, > namely that the option allows negative and argument of the option > is a list of strings, each of them has some enumerator and > -fsanitize-coverage= enabled those bits in the underlying > flag_sanitize_coverage, while -fno-sanitize-coverage= disabled them. > So, -fsanitize-coverage=trace-pc,trace-cmp was equivalent to > -fsanitize-coverage=trace-pc -fsanitize-coverage=trace-cmp and both > set flag_sanitize_coverage to > (SANITIZE_COV_TRACE_PC | SANITIZE_COV_TRACE_CMP) > Also, e.g. > -fsanitize-coverage=trace-pc,trace-cmp -fno-sanitize-coverage=trace-pc > would in the end set flag_sanitize_coverage to > SANITIZE_COV_TRACE_CMP (first set both bits, then subtract one) > The r12-1177 change, I think done to improve argument misspelling > diagnostic, changed the option incompatibly in multiple ways, > -fno-sanitize-coverage= is now rejected, only a single argument > is allowed, not multiple and > -fsanitize-coverage=trace-pc -fsanitize-coverage=trace-cmp > enables just SANITIZE_COV_TRACE_CMP and not both (each option > overrides the previous value) > 2) Thomas Koenig wants to extend Fortran -fconvert= option for the > ppc64le real(kind=16) swapping support; currently the option > accepts -fconvert={native,swap,big-endian,little-endian} and the > intent is to add support for -fconvert=r16_ibm and -fconvert=r16_ieee > (that alone is just normal Enum), but also to handle > -fconvert=swap,r16_ieee or -fconvert=r16_ieee,big-endian but not > -fconvert=big-endian,little-endian - the > native/swap/big-endian/little-endian are one mutually exclusive set > and r16_ieee/r16_ibm another one. > See https://gcc.gnu.org/pipermail/gcc-patches/2022-January/587943.html > and thread around that. > 3) Similarly Marek Polacek wants to extend the -Wbidi-chars= option, > such that it will handle not just the current > -Wbidi-chars={none,bidirectional,any}, but also -Wbidi-chars=ucn > and bidirectional,ucn and ucn,any etc. Again two separate sets, > one none/bidirectional/any and another one ucn. > See https://gcc.gnu.org/pipermail/gcc-patches/2022-January/588960.html > > The following patch adds framework for this and I'll post incremental > patches for 1) and 2). > As I've tried to document, such options are marked by additional > EnumSet property on the option and in that case all the EnumValues > in the Enum referenced from it must use a new Set property with set > number (initially I wanted just mark last enumerator in each mutually > exclusive set, but optionlist is sorted and so it doesn't really work > well). So e.g. for the Fortran -fconvert=, one specifies: > fconvert= > Fortran RejectNegative Joined Enum(gfc_convert) EnumSet Var(flag_convert) > Init(GFC_FLAG_CONVERT_NATIVE) > -fconvert=<big-endian|little-endian|native|swap|r16_ieee|r16_ibm> The > endianness used for unformatted files. > > Enum > Name(gfc_convert) Type(enum gfc_convert) UnknownError(Unrecognized option to > endianness value: %qs) > > EnumValue > Enum(gfc_convert) String(big-endian) Value(GFC_FLAG_CONVERT_BIG) Set(1) > > EnumValue > Enum(gfc_convert) String(little-endian) Value(GFC_FLAG_CONVERT_LITTLE) Set(1) > > EnumValue > Enum(gfc_convert) String(native) Value(GFC_FLAG_CONVERT_NATIVE) Set(1) > > EnumValue > Enum(gfc_convert) String(swap) Value(GFC_FLAG_CONVERT_SWAP) Set(1) > > EnumValue > Enum(gfc_convert) String(r16_ieee) Value(GFC_FLAG_CONVERT_R16_IEEE) Set(2) > > EnumValue > Enum(gfc_convert) String(r16_ibm) Value(GFC_FLAG_CONVERT_R16_IBM) Set(2) > > and this says to the option handling code that > 1) if only one arg is specified to one instance of the option, it can be any > of those 6 > 2) if two args are specified, one has to be from the first 4 and another > from the last 2, in any order > 3) at most 2 args may be specified (there are just 2 sets) > > There is a requirement on the Value values checked in self-test, the > values from one set ored together must be disjunct from values from > another set ored together. In the Fortran case, the first 4 are 0-3 > so mask is 3, and the last 2 are 4 and 8, so mask is 12. > When say -fconvert=big-endian is specified, it sets the first set > to GFC_FLAG_CONVERT_BIG (2) but doesn't modify whatever value the > other set had, so e.g. > -fconvert=big-endian -fconvert=r16_ieee > -fconvert=r16_ieee -fconvert=big-endian > -fconvert=r16_ieee,big_endian > -fconvert=big_endian,r16_ieee > all behave the same. > > Also, with the EnumSet support, it is now possible to allow > not specifying RejectNegative - we can set some set's value and > then clear it and set it again to some other value etc.
Nice. > I think with the 2) patch I achieve what we want for Fortran, for 1) > the only behavior from gcc 11 is that > -fsanitize-coverage=trace-cmp,trace-cmp is now rejected. But -fsanitize-coverage=trace-cmp -fsanitize-coverage=trace-cmp is not? What's the semantics of -fconvert=big-endian -fconvert=little-endian,r16_ieeee? Does the latter replace big-endian with little-endian but add r16_ieeee? I suppose we could interpret -fFOO=BAR,BAZ as -fFOO=BAR -fFOO=BAZ thus process items left-to-right? It's at least odd if -fFOO=BAR,BAZ behaves differently from -fFOO=BAR -fFOO=BAZ (possibly dependent on whether BAR and BAZ are in the same Set or not) > This is mainly from the desire to disallow > -fconvert=big-endian,little-endian or -Wbidi-chars=bidirectional,any > etc. where it would be confusing to users what exactly it means. > But it is the only from these options that actually acts as an Enum > bit set, each enumerator can be specified with all the others. > So one option would be stop requiring the EnumSet implies Set properties > must be specified and just require that either they are specified on all > EnumValues, or on none of them; the latter case would be for > -fsanitize-coverage= and the non-Set case would mean that all the > EnumValues need to have disjoint Value bitmasks and that they can > be all specified and unlike the Set case also repeated. > Thoughts on this? > > Bootstrapped/regtested on x86_64-linux and i686-linux, ok > for trunk (or with changes discussed above)? I think it's OK as-is, exact semantics of splitting/combining arguments can be easily adjusted as followups if we agree on something. Thanks, Richard. > > 2022-01-21 Jakub Jelinek <ja...@redhat.com> > > PR sanitizer/104158 > * opt-functions.awk (var_set): Handle EnumSet property. > * optc-gen.awk: Don't disallow RejectNegative if EnumSet is > specified. > * opt-read.awk: Handle Set property. > * opts.h (CL_ENUM_SET_SHIFT, CL_ERR_ENUM_SET_ARG): Define. > (struct cl_decoded_option): Mention enum in value description. > Add mask member. > (set_option): Add mask argument defaulted to 0. > * opts.cc (test_enum_sets): New function. > (opts_cc_tests): Call it. > * opts-common.cc (enum_arg_to_value): Change return argument > from bool to int, on success return index into the cl_enum_arg > array, on failure -1. Add len argument, if non-0, use strncmp > instead of strcmp. > (opt_enum_arg_to_value): Adjust caller. > (decode_cmdline_option): Handle EnumSet represented as > CLVC_ENUM with non-zero var_value. Initialize decoded->mask. > (decode_cmdline_options_to_array): CLear opt_array[0].mask. > (handle_option): Pass decoded->mask to set_options last argument. > (generate_option): Clear decoded->mask. > (generate_option_input_file): Likewise. > (cmdline_handle_error): Handle CL_ERR_ENUM_SET_ARG. > (set_option): Add mask argument, use it for CLVC_ENUM. > (control_warning_option): Adjust enum_arg_to_value caller. > * doc/options.texi: Document Set and EnumSet properties. > > --- gcc/opt-functions.awk.jj 2022-01-11 23:11:22.797284435 +0100 > +++ gcc/opt-functions.awk 2022-01-21 13:21:11.566273837 +0100 > @@ -297,7 +297,10 @@ function var_set(flags) > } > if (flag_set_p("Enum.*", flags)) { > en = opt_args("Enum", flags); > - return enum_index[en] ", CLVC_ENUM, 0" > + if (flag_set_p("EnumSet", flags)) > + return enum_index[en] ", CLVC_ENUM, 1" > + else > + return enum_index[en] ", CLVC_ENUM, 0" > } > if (var_type(flags) == "const char *") > return "0, CLVC_STRING, 0" > --- gcc/optc-gen.awk.jj 2022-01-18 11:58:59.741979785 +0100 > +++ gcc/optc-gen.awk 2022-01-21 16:54:17.380312546 +0100 > @@ -348,6 +348,7 @@ for (i = 0; i < n_opts; i++) { > alias_data = "NULL, NULL, N_OPTS" > if (flag_set_p("Enum.*", flags[i])) { > if (!flag_set_p("RejectNegative", flags[i]) \ > + && !flag_set_p("EnumSet", flags[i]) \ > && opts[i] ~ "^[Wfgm]") > print "#error Enum allowing negative form" > } > --- gcc/opt-read.awk.jj 2022-01-11 23:11:22.798284420 +0100 > +++ gcc/opt-read.awk 2022-01-21 15:38:42.804583033 +0100 > @@ -97,10 +97,14 @@ BEGIN { > enum_name = opt_args_non_empty("Enum", props) > string = opt_args_non_empty("String", props) > value = opt_args_non_empty("Value", props) > + set = opt_args("Set", props) > val_flags = "0" > val_flags = val_flags \ > test_flag("Canonical", props, "| > CL_ENUM_CANONICAL") \ > test_flag("DriverOnly", props, "| > CL_ENUM_DRIVER_ONLY") > + if (set != "") > + val_flags = val_flags "| ((" set \ > + ") << CL_ENUM_SET_SHIFT)" > enum_data[enum_name] = enum_data[enum_name] \ > " { " quote string quote ", " value ", " val_flags > \ > " },\n" > --- gcc/opts.h.jj 2022-01-11 23:11:22.801284378 +0100 > +++ gcc/opts.h 2022-01-21 17:32:29.007277641 +0100 > @@ -170,6 +170,7 @@ extern const unsigned int cl_lang_count; > /* Flags for an enumerated option argument. */ > #define CL_ENUM_CANONICAL (1 << 0) /* Canonical for this value. */ > #define CL_ENUM_DRIVER_ONLY (1 << 1) /* Only accepted in the driver. */ > +#define CL_ENUM_SET_SHIFT 2 /* Shift for enum set. */ > > /* Structure describing an enumerated option argument. */ > > @@ -226,6 +227,7 @@ extern const unsigned int cl_enums_count > #define CL_ERR_NEGATIVE (1 << 6) /* Negative form of option > not permitted (together > with OPT_SPECIAL_unknown). */ > +#define CL_ERR_ENUM_SET_ARG (1 << 7) /* Bad argument of enumerated set. > */ > > /* Structure describing the result of decoding an option. */ > > @@ -260,9 +262,14 @@ struct cl_decoded_option > > /* For a boolean option, 1 for the true case and 0 for the "no-" > case. For an unsigned integer option, the value of the > - argument. 1 in all other cases. */ > + argument. For enum the value of the enumerator corresponding > + to argument string. 1 in all other cases. */ > HOST_WIDE_INT value; > > + /* For EnumSet the value mask. Variable should be changed to > + value | (prev_value & ~mask). */ > + HOST_WIDE_INT mask; > + > /* Any flags describing errors detected in this option. */ > int errors; > }; > @@ -374,7 +381,8 @@ extern bool get_option_state (struct gcc > extern void set_option (struct gcc_options *opts, > struct gcc_options *opts_set, > int opt_index, HOST_WIDE_INT value, const char *arg, > - int kind, location_t loc, diagnostic_context *dc); > + int kind, location_t loc, diagnostic_context *dc, > + HOST_WIDE_INT = 0); > extern void *option_flag_var (int opt_index, struct gcc_options *opts); > bool handle_generated_option (struct gcc_options *opts, > struct gcc_options *opts_set, > --- gcc/opts.cc.jj 2022-01-20 11:30:45.595577895 +0100 > +++ gcc/opts.cc 2022-01-21 19:44:56.770505499 +0100 > @@ -3709,12 +3709,56 @@ test_get_option_html_page () > #endif > } > > +/* Verify EnumSet 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) > + { > + const struct cl_enum *e = &cl_enums[cl_options[i].var_enum]; > + unsigned HOST_WIDE_INT used_sets = 0; > + unsigned HOST_WIDE_INT mask = 0; > + unsigned highest_set = 0; > + for (unsigned j = 0; e->values[j].arg; ++j) > + { > + unsigned set = e->values[j].flags >> CL_ENUM_SET_SHIFT; > + /* 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 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. */ > + if (highest_set == HOST_BITS_PER_WIDE_INT) > + ASSERT_TRUE (used_sets == HOST_WIDE_INT_M1U); > + else > + ASSERT_TRUE (used_sets == (HOST_WIDE_INT_1U << highest_set) - 1); > + for (unsigned int j = 1; j <= highest_set; ++j) > + { > + unsigned HOST_WIDE_INT this_mask = 0; > + for (unsigned k = 0; e->values[k].arg; ++k) > + { > + unsigned set = e->values[j].flags >> CL_ENUM_SET_SHIFT; > + if (set == j) > + this_mask |= e->values[j].value; > + } > + ASSERT_TRUE ((mask & this_mask) == 0); > + mask |= this_mask; > + } > + } > +} > + > /* Run all of the selftests within this file. */ > > void > opts_cc_tests () > { > test_get_option_html_page (); > + test_enum_sets (); > } > > } // namespace selftest > --- gcc/opts-common.cc.jj 2022-01-18 11:58:59.741979785 +0100 > +++ gcc/opts-common.cc 2022-01-21 19:24:25.498717656 +0100 > @@ -289,26 +289,29 @@ enum_arg_ok_for_language (const struct c > return (lang_mask & CL_DRIVER) || !(enum_arg->flags & CL_ENUM_DRIVER_ONLY); > } > > -/* Look up ARG in ENUM_ARGS for language LANG_MASK, returning true and > - storing the value in *VALUE if found, and returning false without > +/* Look up ARG in ENUM_ARGS for language LANG_MASK, returning the cl_enum_arg > + index and storing the value in *VALUE if found, and returning -1 without > modifying *VALUE if not found. */ > > -static bool > +static int > enum_arg_to_value (const struct cl_enum_arg *enum_args, > - const char *arg, HOST_WIDE_INT *value, > + const char *arg, size_t len, HOST_WIDE_INT *value, > unsigned int lang_mask) > { > unsigned int i; > > for (i = 0; enum_args[i].arg != NULL; i++) > - if (strcmp (arg, enum_args[i].arg) == 0 > + if ((len > + ? (strncmp (arg, enum_args[i].arg, len) == 0 > + && enum_args[i].arg[len] == '\0') > + : strcmp (arg, enum_args[i].arg) == 0) > && enum_arg_ok_for_language (&enum_args[i], lang_mask)) > { > *value = enum_args[i].value; > - return true; > + return i; > } > > - return false; > + return -1; > } > > /* Look up ARG in the enum used by option OPT_INDEX for language > @@ -324,8 +327,8 @@ opt_enum_arg_to_value (size_t opt_index, > gcc_assert (option->var_type == CLVC_ENUM); > > HOST_WIDE_INT wideval; > - if (enum_arg_to_value (cl_enums[option->var_enum].values, arg, > - &wideval, lang_mask)) > + if (enum_arg_to_value (cl_enums[option->var_enum].values, arg, 0, > + &wideval, lang_mask) >= 0) > { > *value = wideval; > return true; > @@ -534,7 +537,7 @@ decode_cmdline_option (const char *const > { > size_t opt_index; > const char *arg = 0; > - HOST_WIDE_INT value = 1; > + HOST_WIDE_INT value = 1, mask = 0; > unsigned int result = 1, i, extra_args, separate_args = 0; > int adjust_len = 0; > size_t total_len; > @@ -808,8 +811,56 @@ decode_cmdline_option (const char *const > { > const struct cl_enum *e = &cl_enums[option->var_enum]; > > - gcc_assert (value == 1); > - if (enum_arg_to_value (e->values, arg, &value, lang_mask)) > + gcc_assert (option->var_value || value == 1); > + if (option->var_value) > + { > + const char *p = arg; > + HOST_WIDE_INT sum_value = 0; > + unsigned HOST_WIDE_INT used_sets = 0; > + do > + { > + const char *q = strchr (p, ','); > + HOST_WIDE_INT this_value = 0; > + if (q && q == p) > + { > + errors |= CL_ERR_ENUM_SET_ARG; > + break; > + } > + int idx = enum_arg_to_value (e->values, p, q ? q - p : 0, > + &this_value, lang_mask); > + if (idx < 0) > + { > + 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); > + > + 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; > + if (q == NULL) > + break; > + p = q + 1; > + } > + while (1); > + if (value == 1) > + value = sum_value; > + else > + gcc_checking_assert (value == 0); > + } > + else if (enum_arg_to_value (e->values, arg, 0, &value, lang_mask) >= 0) > { > const char *carg = NULL; > > @@ -825,6 +876,7 @@ decode_cmdline_option (const char *const > decoded->opt_index = opt_index; > decoded->arg = arg; > decoded->value = value; > + decoded->mask = mask; > decoded->errors = errors; > decoded->warn_message = warn_message; > > @@ -958,6 +1010,7 @@ decode_cmdline_options_to_array (unsigne > opt_array[0].canonical_option[2] = NULL; > opt_array[0].canonical_option[3] = NULL; > opt_array[0].value = 1; > + opt_array[0].mask = 0; > opt_array[0].errors = 0; > num_decoded_options = 1; > > @@ -1167,13 +1220,14 @@ handle_option (struct gcc_options *opts, > size_t opt_index = decoded->opt_index; > const char *arg = decoded->arg; > HOST_WIDE_INT value = decoded->value; > + HOST_WIDE_INT mask = decoded->mask; > const struct cl_option *option = &cl_options[opt_index]; > void *flag_var = option_flag_var (opt_index, opts); > size_t i; > > if (flag_var) > set_option (opts, (generated_p ? NULL : opts_set), > - opt_index, value, arg, kind, loc, dc); > + opt_index, value, arg, kind, loc, dc, mask); > > for (i = 0; i < handlers->num_handlers; i++) > if (option->flags & handlers->handlers[i].mask) > @@ -1222,6 +1276,7 @@ generate_option (size_t opt_index, const > decoded->warn_message = NULL; > decoded->arg = arg; > decoded->value = value; > + decoded->mask = 0; > decoded->errors = (option_ok_for_language (option, lang_mask) > ? 0 > : CL_ERR_WRONG_LANG); > @@ -1260,6 +1315,7 @@ generate_option_input_file (const char * > decoded->canonical_option[2] = NULL; > decoded->canonical_option[3] = NULL; > decoded->value = 1; > + decoded->mask = 0; > decoded->errors = 0; > } > > @@ -1342,6 +1398,74 @@ cmdline_handle_error (location_t loc, co > return true; > } > > + if (errors & CL_ERR_ENUM_SET_ARG) > + { > + const struct cl_enum *e = &cl_enums[option->var_enum]; > + const char *p = arg; > + unsigned HOST_WIDE_INT used_sets = 0; > + const char *second_opt = NULL; > + size_t second_opt_len = 0; > + errors = 0; > + do > + { > + const char *q = strchr (p, ','); > + HOST_WIDE_INT this_value = 0; > + if (q && q == p) > + { > + arg = ""; > + errors = CL_ERR_ENUM_ARG; > + break; > + } > + int idx = enum_arg_to_value (e->values, p, q ? q - p : 0, > + &this_value, lang_mask); > + if (idx < 0) > + { > + if (q == NULL) > + q = strchr (p, '\0'); > + char *narg = XALLOCAVEC (char, (q - p) + 1); > + memcpy (narg, p, q - p); > + narg[q - p] = '\0'; > + arg = narg; > + errors = CL_ERR_ENUM_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) > + { > + if (q == NULL) > + q = strchr (p, '\0'); > + if (second_opt == NULL) > + { > + used_sets = HOST_WIDE_INT_1U << (set - 1); > + second_opt = p; > + second_opt_len = q - p; > + p = arg; > + continue; > + } > + char *args = XALLOCAVEC (char, (q - p) + 1 + second_opt_len + > 1); > + memcpy (args, p, q - p); > + args[q - p] = '\0'; > + memcpy (args + (q - p) + 1, second_opt, second_opt_len); > + args[(q - p) + 1 + second_opt_len] = '\0'; > + error_at (loc, "invalid argument in option %qs", opt); > + if (strcmp (args, args + (q - p) + 1) == 0) > + inform (loc, "%qs specified multiple times in the same > option", > + args); > + else > + inform (loc, "%qs is mutually exclusive with %qs and cannot > be" > + " specified together", args, args + (q - p) + 1); > + return true; > + } > + used_sets |= HOST_WIDE_INT_1U << (set - 1); > + if (q == NULL) > + break; > + p = q + 1; > + } > + while (1); > + } > + > if (errors & CL_ERR_ENUM_ARG) > { > const struct cl_enum *e = &cl_enums[option->var_enum]; > @@ -1441,7 +1565,8 @@ read_cmdline_option (struct gcc_options > void > set_option (struct gcc_options *opts, struct gcc_options *opts_set, > int opt_index, HOST_WIDE_INT value, const char *arg, int kind, > - location_t loc, diagnostic_context *dc) > + location_t loc, diagnostic_context *dc, > + HOST_WIDE_INT mask /* = 0 */) > { > const struct cl_option *option = &cl_options[opt_index]; > void *flag_var = option_flag_var (opt_index, opts); > @@ -1550,7 +1675,10 @@ set_option (struct gcc_options *opts, st > { > const struct cl_enum *e = &cl_enums[option->var_enum]; > > - e->set (flag_var, value); > + if (mask) > + e->set (flag_var, value | (e->get (flag_var) & ~mask)); > + else > + e->set (flag_var, value); > if (set_flag_var) > e->set (set_flag_var, 1); > } > @@ -1767,7 +1895,8 @@ control_warning_option (unsigned int opt > { > const struct cl_enum *e = &cl_enums[option->var_enum]; > > - if (enum_arg_to_value (e->values, arg, &value, lang_mask)) > + if (enum_arg_to_value (e->values, arg, 0, &value, > + lang_mask) >= 0) > { > const char *carg = NULL; > > --- gcc/doc/options.texi.jj 2022-01-18 11:58:59.472983628 +0100 > +++ gcc/doc/options.texi 2022-01-21 19:08:15.162270676 +0100 > @@ -132,6 +132,21 @@ be accepted by the driver. This is used > @option{-march=native} that are processed by the driver so that > @samp{gcc -v} shows how the options chosen depended on the system on > which the compiler was run. > + > +@item Set(@var{number}) > +This property is optional, required for enumerations used in > +@code{EnumSet} options. @var{number} should be decimal number between > +1 and 64 inclusive and divides the enumeration into a set of > +sets of mutually exclusive arguments. Arguments with the same > +@var{number} can't be specified together in the same option, but > +arguments with different @var{number} can. @var{value} needs to be > +chosen such that a mask of all @var{value} values from the same set > +@var{number} bitwise ored doesn't overlap with masks for other sets. > +When @code{-foption=arg_from_set1,arg_from_set4} and > +@code{-fno-option=arg_from_set3} are used, the effect is that previous > +value of the @code{Var} will get bits from set 1 and 4 masks cleared, > +ored @code{Value} of @code{arg_from_set1} and @code{arg_from_set4} > +and then will get bits from set 3 mask cleared. > @end table > > @item > @@ -396,6 +411,16 @@ with the corresponding @samp{Enum} recor > converted to the integer specified in the corresponding > @samp{EnumValue} record before being passed to option handlers. > > +@item EnumSet > +Must be used together with the @code{Enum(@var{name})} property. > +Corresponding @samp{Enum} record must use @code{Set} properties. > +The option's argument is either a string from the set like for > +@code{Enum(@var{name})}, but with a slightly different behavior that > +the whole @code{Var} isn't overwritten, but only the bits in all the > +enumeration values with the same set bitwise ored together. > +Or option's argument can be a comma separated list of strings where > +each string is from a different @code{Set(@var{number})}. > + > @item Defer > The option should be stored in a vector, specified with @code{Var}, > for later processing. > > Jakub >