@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
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.
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
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;
{
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;
{
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;
decoded->opt_index = opt_index;
decoded->arg = arg;
decoded->value = value;
+ decoded->mask = mask;
decoded->errors = errors;
decoded->warn_message = warn_message;
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;
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)
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);
decoded->canonical_option[2] = NULL;
decoded->canonical_option[3] = NULL;
decoded->value = 1;
+ decoded->mask = 0;
decoded->errors = 0;
}
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];
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);
{
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);
}
{
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;
/* 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. */
#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. */
/* 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;
};
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,