static tree handle_hardbool_attribute (tree *, tree, tree, int, bool *);
static tree handle_retain_attribute (tree *, tree, tree, int, bool *);
static tree handle_fd_arg_attribute (tree *, tree, tree, int, bool *);
+static tree handle_flag_enum_attribute (tree *, tree, tree, int, bool *);
static tree handle_null_terminated_string_arg_attribute (tree *, tree, tree, int, bool *);
/* Helper to define attribute exclusions. */
handle_fd_arg_attribute, NULL},
{ "fd_arg_write", 1, 1, false, true, true, false,
handle_fd_arg_attribute, NULL},
+ { "flag_enum", 0, 0, false, true, false, false,
+ handle_flag_enum_attribute, NULL },
{ "null_terminated_string_arg", 1, 1, false, true, true, false,
handle_null_terminated_string_arg_attribute, NULL}
};
"gnu", { c_common_gnu_attributes }
};
+/* Attributes also recognized in the clang:: namespace. */
+const struct attribute_spec c_common_clang_attributes[] = {
+ { "flag_enum", 0, 0, false, true, false, false,
+ handle_flag_enum_attribute, NULL }
+};
+
+const struct scoped_attribute_specs c_common_clang_attribute_table =
+{
+ "clang", { c_common_clang_attributes }
+};
+
/* Give the specifications for the format attributes, used by C and all
descendants.
return NULL_TREE;
}
+/* Handle the "flag_enum" attribute. */
+
+static tree
+handle_flag_enum_attribute (tree *node, tree ARG_UNUSED (name),
+ tree ARG_UNUSED (args), int ARG_UNUSED (flags),
+ bool *no_add_attrs)
+{
+ if (TREE_CODE (*node) != ENUMERAL_TYPE)
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored on non-enum", name);
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
/* Handle the "null_terminated_string_arg" attribute. */
static tree
/* Attribute table common to the C front ends. */
extern const struct scoped_attribute_specs c_common_gnu_attribute_table;
+extern const struct scoped_attribute_specs c_common_clang_attribute_table;
extern const struct scoped_attribute_specs c_common_format_attribute_table;
/* Pointer to function to lazily generate the VAR_DECL for __FUNCTION__ etc.
TREE_PURPOSE (chain));
}
+ /* Attribute flag_enum means bitwise combinations are OK. */
+ if (lookup_attribute ("flag_enum", TYPE_ATTRIBUTES (type)))
+ return;
+
/* Warn if there are case expressions that don't correspond to
enumerators. This can occur since C and C++ don't enforce
type-checking of assignments to enumeration variables.
{
&std_attribute_table,
&c_common_gnu_attribute_table,
+ &c_common_clang_attribute_table,
&c_common_format_attribute_table
};
&std_attribute_table,
&cxx_gnu_attribute_table,
&c_common_gnu_attribute_table,
+ &c_common_clang_attribute_table,
&c_common_format_attribute_table
};
GCC emits warnings based on this attribute by default; use
@option{-Wno-designated-init} to suppress them.
+@cindex @code{flag_enum} type attribute
+@item flag_enum
+This attribute may be applied to an enumerated type to indicate that
+its enumerators are used in bitwise operations, so e.g. @option{-Wswitch}
+should not warn about a @code{case} that corresponds to a bitwise
+combination of enumerators.
+
@cindex @code{hardbool} type attribute
@item hardbool
@itemx hardbool (@var{false_value})
Warn whenever a @code{switch} statement has an index of enumerated type
and lacks a @code{case} for one or more of the named codes of that
enumeration. (The presence of a @code{default} label prevents this
-warning.) @code{case} labels outside the enumeration range also
-provoke warnings when this option is used (even if there is a
-@code{default} label).
+warning.) @code{case} labels that do not correspond to enumerators also
+provoke warnings when this option is used, unless the enumeration is marked
+with the @code{flag_enum} attribute.
This warning is enabled by @option{-Wall}.
@opindex Wswitch-default
@item -Wswitch-enum
Warn whenever a @code{switch} statement has an index of enumerated type
and lacks a @code{case} for one or more of the named codes of that
-enumeration. @code{case} labels outside the enumeration range also
-provoke warnings when this option is used. The only difference
+enumeration. @code{case} labels that do not correspond to enumerators also
+provoke warnings when this option is used, unless the enumeration is marked
+with the @code{flag_enum} attribute. The only difference
between @option{-Wswitch} and this option is that this option gives a
warning about an omitted enumeration code even if there is a
@code{default} label.
--- /dev/null
+/* { dg-additional-options -Wswitch } */
+
+enum E0 { a0 = 1, b0 = 2 };
+void f0 (enum E0 e) {
+ switch (e) {
+ case !(a0|b0): /* { dg-warning "not in enumerated type" } */
+ case a0|b0: /* { dg-warning "not in enumerated type" } */
+ default:;
+ }
+}
+
+enum __attribute ((flag_enum)) E1 { a1 = 1, b1 = 2 };
+void f1 (enum E1 e) {
+ switch (e) {
+ case !(a1|b1): /* { dg-bogus "not in enumerated type" } */
+ case a1|b1: /* { dg-bogus "not in enumerated type" } */
+ default:;
+ }
+}
+
+enum [[gnu::flag_enum]] E2 { a2 = 1, b2 = 2 };
+void f2 (enum E2 e) {
+ switch (e) {
+ case !(a2|b2): /* { dg-bogus "not in enumerated type" } */
+ case a2|b2: /* { dg-bogus "not in enumerated type" } */
+ default:;
+ }
+}
+
+enum [[clang::flag_enum]] E3 { a3 = 1, b3 = 2 };
+void f3 (enum E3 e) {
+ switch (e) {
+ case !(a3|b3): /* { dg-bogus "not in enumerated type" } */
+ case a3|b3: /* { dg-bogus "not in enumerated type" } */
+ default:;
+ }
+}
* elements @c ECMAScript, @c basic, @c extended, @c awk, @c grep, @c egrep
* %set.
*/
- enum syntax_option_type : unsigned int
+ enum [[gnu::flag_enum]] syntax_option_type : unsigned int
{
_S_icase = 1 << 0,
_S_nosubs = 1 << 1,