Implement some changes to the currently supported C2x standard
attributes that have been made to the specification since they were
first implemented in GCC, and some consequent changes:
* maybe_unused is now supported on labels. In fact that was already
accidentally supported in GCC as a result of sharing the
implementation with __attribute__ ((unused)), but needed to be
covered in the tests.
* As part of the support for maybe_unused on labels, its
__has_c_attribute value changed.
* The issue of maybe_unused accidentally being already supported on
labels showed up the lack of tests for other standard attributes
being incorrectly applied to labels; add such tests.
* Use of fallthrough or nodiscard attributes on labels already
properly resulted in a pedwarn. For the deprecated attribute,
however, there was only a warning, and the wording "'deprecated'
attribute ignored for 'void'" included an unhelpful "for 'void'".
Arrange for the case of the deprecated attribute on a label to be
checked for separately and result in a pedwarn. As with
inappropriate uses of fallthrough (see commit
6c80b1b56dec2691436f3e2676e3d1b105b01b89), it seems reasonable for
this pedwarn to apply regardless of whether [[]] or __attribute__
was used and regardless of whether C or C++ is being compiled.
* Attributes on case or default labels (the standard syntax supports
attributes on all kinds of labels) were quietly ignored, whether or
not appropriate for use in such a context, because they weren't
passed to decl_attributes at all. (Note where I'm changing the
do_case prototype that such a function is actually only defined in
the C front end, not for C++, despite the declaration being in
c-common.h.)
* A recent change as part of the editorial review in preparation for
the C2x CD ballot has changed the __has_c_attribute value for
fallthrough to 201910 to reflect when that attribute was actually
voted into the working draft.
Bootstrapped with no regressions for x86_64-pc-linux-gnu.
gcc/c-family/
* c-attribs.cc (handle_deprecated_attribute): Check and pedwarn
for LABEL_DECL.
* c-common.cc (c_add_case_label): Add argument ATTRS. Call
decl_attributes.
* c-common.h (do_case, c_add_case_label): Update declarations.
* c-lex.cc (c_common_has_attribute): For C, produce a result of
201910 for fallthrough and 202106 for maybe_unused.
gcc/c/
* c-parser.cc (c_parser_label): Pass attributes to do_case.
* c-typeck.cc (do_case): Add argument ATTRS. Pass it to
c_add_case_label.
gcc/testsuite/
* gcc.dg/c2x-attr-deprecated-2.c, gcc.dg/c2x-attr-fallthrough-2.c,
gcc.dg/c2x-attr-maybe_unused-1.c, gcc.dg/c2x-attr-nodiscard-2.c:
Add tests of attributes on labels.
* gcc.dg/c2x-has-c-attribute-2.c: Update expected results for
maybe_unused and fallthrough.
|| TREE_CODE (decl) == CONST_DECL
|| objc_method_decl (TREE_CODE (decl)))
TREE_DEPRECATED (decl) = 1;
+ else if (TREE_CODE (decl) == LABEL_DECL)
+ {
+ pedwarn (input_location, OPT_Wattributes, "%qE attribute ignored",
+ name);
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
else
warn = 1;
}
CASES is a tree containing all the case ranges processed so far;
COND is the condition for the switch-statement itself.
Returns the CASE_LABEL_EXPR created, or ERROR_MARK_NODE if no
- CASE_LABEL_EXPR is created. */
+ CASE_LABEL_EXPR is created. ATTRS are the attributes to be applied
+ to the label. */
tree
c_add_case_label (location_t loc, splay_tree cases, tree cond,
- tree low_value, tree high_value)
+ tree low_value, tree high_value, tree attrs)
{
tree type;
tree label;
/* Create the LABEL_DECL itself. */
label = create_artificial_label (loc);
+ decl_attributes (&label, attrs, 0);
/* If there was an error processing the switch condition, bail now
before we get more confused. */
/* True iff TYPE is cv decltype(nullptr). */
#define NULLPTR_TYPE_P(TYPE) (TREE_CODE (TYPE) == NULLPTR_TYPE)
-extern tree do_case (location_t, tree, tree);
+extern tree do_case (location_t, tree, tree, tree);
extern tree build_stmt (location_t, enum tree_code, ...);
extern tree build_real_imag_expr (location_t, enum tree_code, tree);
extern int case_compare (splay_tree_key, splay_tree_key);
-extern tree c_add_case_label (location_t, splay_tree, tree, tree, tree);
+extern tree c_add_case_label (location_t, splay_tree, tree, tree, tree,
+ tree = NULL_TREE);
extern bool c_switch_covers_all_cases_p (splay_tree, tree);
extern bool c_block_may_fallthru (const_tree);
}
else
{
- if (is_attribute_p ("deprecated", attr_name)
- || is_attribute_p ("maybe_unused", attr_name)
- || is_attribute_p ("fallthrough", attr_name))
+ if (is_attribute_p ("deprecated", attr_name))
result = 201904;
+ else if (is_attribute_p ("fallthrough", attr_name))
+ result = 201910;
else if (is_attribute_p ("nodiscard", attr_name))
result = 202003;
+ else if (is_attribute_p ("maybe_unused", attr_name))
+ result = 202106;
}
if (result)
attr_name = NULL_TREE;
if (c_parser_next_token_is (parser, CPP_COLON))
{
c_parser_consume_token (parser);
- label = do_case (loc1, exp1, NULL_TREE);
+ label = do_case (loc1, exp1, NULL_TREE, std_attrs);
}
else if (c_parser_next_token_is (parser, CPP_ELLIPSIS))
{
c_parser_consume_token (parser);
exp2 = c_parser_expr_no_commas (parser, NULL).value;
if (c_parser_require (parser, CPP_COLON, "expected %<:%>"))
- label = do_case (loc1, exp1, exp2);
+ label = do_case (loc1, exp1, exp2, std_attrs);
}
else
c_parser_error (parser, "expected %<:%> or %<...%>");
{
c_parser_consume_token (parser);
if (c_parser_require (parser, CPP_COLON, "expected %<:%>"))
- label = do_case (loc1, NULL_TREE, NULL_TREE);
+ label = do_case (loc1, NULL_TREE, NULL_TREE, std_attrs);
}
else
{
return add_stmt (cs->switch_stmt);
}
-/* Process a case label at location LOC. */
+/* Process a case label at location LOC, with attributes ATTRS. */
tree
-do_case (location_t loc, tree low_value, tree high_value)
+do_case (location_t loc, tree low_value, tree high_value, tree attrs)
{
tree label = NULL_TREE;
label = c_add_case_label (loc, c_switch_stack->cases,
SWITCH_STMT_COND (c_switch_stack->switch_stmt),
- low_value, high_value);
+ low_value, high_value, attrs);
if (label == error_mark_node)
label = NULL_TREE;
return label;
/* { dg-options "-std=c2x -pedantic-errors" } */
/* This attribute is not valid in most cases on types other than their
- definitions, or on statements, or as an attribute-declaration. */
+ definitions, or on labels, or on statements, or as an
+ attribute-declaration. */
[[deprecated]]; /* { dg-error "ignored" } */
int a;
[[deprecated]]; /* { dg-error "ignored" } */
[[deprecated]] a = 1; /* { dg-error "ignored" } */
+ [[deprecated]] label: ; /* { dg-error "ignored" } */
+ switch (var)
+ {
+ [[deprecated]] case 1: ; /* { dg-error "ignored" } */
+ [[deprecated]] default: ; /* { dg-error "ignored" } */
+ }
}
case 5:
b += 5;
break;
+ [[fallthrough]] case 6: break; /* { dg-error "ignored" } */
+ [[fallthrough]] default: break; /* { dg-error "ignored" } */
}
[[fallthrough]] return b; /* { dg-error "ignored" } */
+ [[fallthrough]] label: ; /* { dg-error "ignored" } */
+ goto label;
}
[[maybe_unused]] int a;
int b [[__maybe_unused__]];
int c [[maybe_unused]];
+ [[__maybe_unused__]] label1:
c = y;
+ [[maybe_unused]] label2:
return y;
}
enum [[maybe_unused]] eu { E2 };
union u2 { [[maybe_unused]] int a; int b [[maybe_unused]]; } y;
+
+void
+g2 (int x)
+{
+ switch (x)
+ {
+ [[maybe_unused]] case 1: ;
+ [[__maybe_unused__]] case 2: ;
+ [[maybe_unused]] default: ;
+ }
+}
[[nodiscard ("reason")]] int b = 1; /* { dg-error "can only be applied" } */
[[nodiscard]]; /* { dg-error "ignored" } */
[[nodiscard]] a = 1; /* { dg-error "ignored" } */
+ [[nodiscard]] label: ; /* { dg-error "can only be applied" } */
+ switch (var)
+ {
+ [[nodiscard]] case 1: ; /* { dg-error "can only be applied" } */
+ [[nodiscard]] default: ; /* { dg-error "can only be applied" } */
+ }
}
#error "bad result for __nodiscard__"
#endif
-#if __has_c_attribute(maybe_unused) != 201904L
+#if __has_c_attribute(maybe_unused) != 202106L
#error "bad result for maybe_unused"
#endif
-#if __has_c_attribute(__maybe_unused__) != 201904L
+#if __has_c_attribute(__maybe_unused__) != 202106L
#error "bad result for __maybe_unused__"
#endif
#error "bad result for __deprecated__"
#endif
-#if __has_c_attribute (fallthrough) != 201904L
+#if __has_c_attribute (fallthrough) != 201910L
#error "bad result for fallthrough"
#endif
-#if __has_c_attribute (__fallthrough__) != 201904L
+#if __has_c_attribute (__fallthrough__) != 201910L
#error "bad result for __fallthrough__"
#endif