From 192961ff27503085946caaa92b2f57d291258858 Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Tue, 19 Nov 2019 00:21:49 +0000 Subject: [PATCH] Change some bad uses of C2x attributes into pedwarns. Certain bad uses of C2x standard attributes (that is, attributes inside [[]] with only a name but no namespace specified) are constraint violations, and so should be diagnosed with a pedwarn (or error) where GCC currently uses a warning. This patch implements this in some cases (not yet for attributes used on types, nor for some bad uses of fallthrough attributes). Specifically, this applies to unknown standard attributes (taking care not to pedwarn for nodiscard, which is known but not implemented for C), and to all currently implemented standard attributes in attribute declarations (including when mixed with fallthrough) and on statements. Bootstrapped with no regressions on x86_64-pc-linux-gnu. gcc/c: * c-decl.c (c_warn_unused_attributes): Use pedwarn not warning for standard attributes. * c-parser.c (c_parser_std_attribute): Take argument for_tm. Use pedwarn for unknown standard attributes and return error_mark_node for them. gcc/c-family: * c-common.c (attribute_fallthrough_p): In C, use pedwarn not warning for standard attributes mixed with fallthrough attributes. gcc/testsuite: * gcc.dg/c2x-attr-fallthrough-5.c, gcc.dg/c2x-attr-syntax-5.c: New tests. * gcc.dg/c2x-attr-deprecated-2.c, gcc.dg/c2x-attr-deprecated-4.c, gcc.dg/c2x-attr-fallthrough-2.c, gcc.dg/c2x-attr-maybe_unused-2.c, gcc.dg/c2x-attr-maybe_unused-4.c: Expect errors in place of some warnings. From-SVN: r278428 --- gcc/c-family/ChangeLog | 5 ++ gcc/c-family/c-common.c | 10 ++- gcc/c/ChangeLog | 8 ++ gcc/c/c-decl.c | 10 ++- gcc/c/c-parser.c | 78 +++++++++++-------- gcc/testsuite/ChangeLog | 9 +++ gcc/testsuite/gcc.dg/c2x-attr-deprecated-2.c | 6 +- gcc/testsuite/gcc.dg/c2x-attr-deprecated-4.c | 2 +- gcc/testsuite/gcc.dg/c2x-attr-fallthrough-2.c | 2 +- gcc/testsuite/gcc.dg/c2x-attr-fallthrough-5.c | 30 +++++++ .../gcc.dg/c2x-attr-maybe_unused-2.c | 6 +- .../gcc.dg/c2x-attr-maybe_unused-4.c | 2 +- gcc/testsuite/gcc.dg/c2x-attr-syntax-5.c | 56 +++++++++++++ 13 files changed, 180 insertions(+), 44 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/c2x-attr-fallthrough-5.c create mode 100644 gcc/testsuite/gcc.dg/c2x-attr-syntax-5.c diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index c7420f647d8..e1b437bf92e 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,8 @@ +2019-11-19 Joseph Myers + + * c-common.c (attribute_fallthrough_p): In C, use pedwarn not + warning for standard attributes mixed with fallthrough attributes. + 2019-11-15 Joseph Myers * c-attribs.c (handle_fallthrough_attribute): Remove static. diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index 48811994f38..f779acc0387 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -5702,7 +5702,15 @@ attribute_fallthrough_p (tree attr) { tree name = get_attribute_name (t); if (!is_attribute_p ("fallthrough", name)) - warning (OPT_Wattributes, "%qE attribute ignored", name); + { + if (!c_dialect_cxx () && get_attribute_namespace (t) == NULL_TREE) + /* The specifications of standard attributes in C mean + this is a constraint violation. */ + pedwarn (input_location, OPT_Wattributes, "%qE attribute ignored", + get_attribute_name (t)); + else + warning (OPT_Wattributes, "%qE attribute ignored", name); + } } return true; } diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index 0658ea0d2a6..fff7dc6328a 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,11 @@ +2019-11-19 Joseph Myers + + * c-decl.c (c_warn_unused_attributes): Use pedwarn not warning for + standard attributes. + * c-parser.c (c_parser_std_attribute): Take argument for_tm. Use + pedwarn for unknown standard attributes and return error_mark_node + for them. + 2019-11-18 Matthew Malcomson * c-parser.c (c_parser_parse_rtl_body): Always call diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c index cb6169c4642..746339d12ed 100644 --- a/gcc/c/c-decl.c +++ b/gcc/c/c-decl.c @@ -4516,8 +4516,14 @@ void c_warn_unused_attributes (tree attrs) { for (tree t = attrs; t != NULL_TREE; t = TREE_CHAIN (t)) - warning (OPT_Wattributes, "%qE attribute ignored", - get_attribute_name (t)); + if (get_attribute_namespace (t) == NULL_TREE) + /* The specifications of standard attributes mean this is a + constraint violation. */ + pedwarn (input_location, OPT_Wattributes, "%qE attribute ignored", + get_attribute_name (t)); + else + warning (OPT_Wattributes, "%qE attribute ignored", + get_attribute_name (t)); } /* Called when a declaration is seen that contains no names to declare. diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index 2efa23424ff..03194b438f2 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -4803,7 +4803,7 @@ c_parser_balanced_token_sequence (c_parser *parser) */ static tree -c_parser_std_attribute (c_parser *parser) +c_parser_std_attribute (c_parser *parser, bool for_tm) { c_token *token = c_parser_peek_token (parser); tree ns, name, attribute; @@ -4834,39 +4834,53 @@ c_parser_std_attribute (c_parser *parser) attribute = build_tree_list (build_tree_list (ns, name), NULL_TREE); /* Parse the arguments, if any. */ - if (c_parser_next_token_is_not (parser, CPP_OPEN_PAREN)) - return attribute; - location_t open_loc = c_parser_peek_token (parser)->location; - matching_parens parens; - parens.consume_open (parser); const attribute_spec *as = lookup_attribute_spec (TREE_PURPOSE (attribute)); - if ((as && as->max_length == 0) - /* Special-case the transactional-memory attribute "outer", - which is specially handled but not registered as an - attribute, to avoid allowing arbitrary balanced token - sequences as arguments. */ - || is_attribute_p ("outer", name)) - { - error_at (open_loc, "%qE attribute does not take any arguments", name); - parens.skip_until_found_close (parser); + if (c_parser_next_token_is_not (parser, CPP_OPEN_PAREN)) + goto out; + { + location_t open_loc = c_parser_peek_token (parser)->location; + matching_parens parens; + parens.consume_open (parser); + if ((as && as->max_length == 0) + /* Special-case the transactional-memory attribute "outer", + which is specially handled but not registered as an + attribute, to avoid allowing arbitrary balanced token + sequences as arguments. */ + || is_attribute_p ("outer", name)) + { + error_at (open_loc, "%qE attribute does not take any arguments", name); + parens.skip_until_found_close (parser); + return error_mark_node; + } + if (as) + { + bool takes_identifier + = (ns != NULL_TREE + && strcmp (IDENTIFIER_POINTER (ns), "gnu") == 0 + && attribute_takes_identifier_p (name)); + bool require_string + = (ns == NULL_TREE + && strcmp (IDENTIFIER_POINTER (name), "deprecated") == 0); + TREE_VALUE (attribute) + = c_parser_attribute_arguments (parser, takes_identifier, + require_string, false); + } + else + c_parser_balanced_token_sequence (parser); + parens.require_close (parser); + } + out: + if (ns == NULL_TREE && !for_tm && !as && !is_attribute_p ("nodiscard", name)) + { + /* An attribute with standard syntax and no namespace specified + is a constraint violation if it is not one of the known + standard attributes (of which nodiscard is the only one + without a handler in GCC). Diagnose it here with a pedwarn + and then discard it to prevent a duplicate warning later. */ + pedwarn (input_location, OPT_Wattributes, "%qE attribute ignored", + name); return error_mark_node; } - if (as) - { - bool takes_identifier - = (ns != NULL_TREE - && strcmp (IDENTIFIER_POINTER (ns), "gnu") == 0 - && attribute_takes_identifier_p (name)); - bool require_string - = (ns == NULL_TREE - && strcmp (IDENTIFIER_POINTER (name), "deprecated") == 0); - TREE_VALUE (attribute) - = c_parser_attribute_arguments (parser, takes_identifier, - require_string, false); - } - else - c_parser_balanced_token_sequence (parser); - parens.require_close (parser); return attribute; } @@ -4898,7 +4912,7 @@ c_parser_std_attribute_specifier (c_parser *parser, bool for_tm) c_parser_consume_token (parser); continue; } - tree attribute = c_parser_std_attribute (parser); + tree attribute = c_parser_std_attribute (parser, for_tm); if (attribute != error_mark_node) { bool duplicate = false; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index f05382c87a7..d258749ef5b 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,12 @@ +2019-11-19 Joseph Myers + + * gcc.dg/c2x-attr-fallthrough-5.c, gcc.dg/c2x-attr-syntax-5.c: New + tests. + * gcc.dg/c2x-attr-deprecated-2.c, gcc.dg/c2x-attr-deprecated-4.c, + gcc.dg/c2x-attr-fallthrough-2.c, gcc.dg/c2x-attr-maybe_unused-2.c, + gcc.dg/c2x-attr-maybe_unused-4.c: Expect errors in place of some + warnings. + 2019-11-18 Paolo Carlini * g++.dg/cpp0x/addressof2.C: Test locations too. diff --git a/gcc/testsuite/gcc.dg/c2x-attr-deprecated-2.c b/gcc/testsuite/gcc.dg/c2x-attr-deprecated-2.c index 2d47606cce8..0f0b1749ae4 100644 --- a/gcc/testsuite/gcc.dg/c2x-attr-deprecated-2.c +++ b/gcc/testsuite/gcc.dg/c2x-attr-deprecated-2.c @@ -5,7 +5,7 @@ /* This attribute is not valid in most cases on types other than their definitions, or on statements, or as an attribute-declaration. */ -[[deprecated]]; /* { dg-warning "ignored" } */ +[[deprecated]]; /* { dg-error "ignored" } */ int [[deprecated]] var; /* { dg-warning "ignored" } */ /* { dg-message "that appertains to a type-specifier" "appertains" { target *-*-* } .-1 } */ @@ -20,6 +20,6 @@ void f (void) { int a; - [[deprecated]]; /* { dg-warning "ignored" } */ - [[deprecated]] a = 1; /* { dg-warning "ignored" } */ + [[deprecated]]; /* { dg-error "ignored" } */ + [[deprecated]] a = 1; /* { dg-error "ignored" } */ } diff --git a/gcc/testsuite/gcc.dg/c2x-attr-deprecated-4.c b/gcc/testsuite/gcc.dg/c2x-attr-deprecated-4.c index ce6615b4ba1..f1848a20cd5 100644 --- a/gcc/testsuite/gcc.dg/c2x-attr-deprecated-4.c +++ b/gcc/testsuite/gcc.dg/c2x-attr-deprecated-4.c @@ -6,7 +6,7 @@ [[__deprecated__, deprecated("message")]] int b; /* { dg-error "can appear at most once" } */ int c [[deprecated("message"), deprecated]]; /* { dg-error "can appear at most once" } */ [[deprecated, deprecated]]; /* { dg-error "can appear at most once" } */ -/* { dg-warning "ignored" "ignored" { target *-*-* } .-1 } */ +/* { dg-error "ignored" "ignored" { target *-*-* } .-1 } */ /* Separate attribute lists in the same attribute specifier sequence, with the same attribute in them, are OK. */ diff --git a/gcc/testsuite/gcc.dg/c2x-attr-fallthrough-2.c b/gcc/testsuite/gcc.dg/c2x-attr-fallthrough-2.c index e396a60ea0c..33e3ec28227 100644 --- a/gcc/testsuite/gcc.dg/c2x-attr-fallthrough-2.c +++ b/gcc/testsuite/gcc.dg/c2x-attr-fallthrough-2.c @@ -31,5 +31,5 @@ f (int a) b += 5; break; } - [[fallthrough]] return b; /* { dg-warning "ignored" } */ + [[fallthrough]] return b; /* { dg-error "ignored" } */ } diff --git a/gcc/testsuite/gcc.dg/c2x-attr-fallthrough-5.c b/gcc/testsuite/gcc.dg/c2x-attr-fallthrough-5.c new file mode 100644 index 00000000000..c614ceba205 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-attr-fallthrough-5.c @@ -0,0 +1,30 @@ +/* Test C2x fallthrough attribute: mixtures with other attributes. */ +/* { dg-do compile } */ +/* { dg-options "-std=c2x -pedantic-errors" } */ + +/* Use of other standard attributes together with "fallthrough" goes + through a different path to diagnosing ignored attributes from that + used in attribute declarations without "fallthrough". Verify that + such ignored attributes result in a pedwarn (for use in a context + not permitted in the constraints for those attributes) in this case + as well. */ + +int +f (int a) +{ + switch (a) + { + case 1: + a++; + [[fallthrough, deprecated]]; /* { dg-error "attribute ignored" } */ + case 2: + a++; + [[maybe_unused]] [[fallthrough]]; /* { dg-error "attribute ignored" } */ + case 3: + a++; + [[__nodiscard__, fallthrough]]; /* { dg-error "attribute ignored" } */ + case 4: + a++; + } + return a; +} diff --git a/gcc/testsuite/gcc.dg/c2x-attr-maybe_unused-2.c b/gcc/testsuite/gcc.dg/c2x-attr-maybe_unused-2.c index 9b5055bad48..7f06581f949 100644 --- a/gcc/testsuite/gcc.dg/c2x-attr-maybe_unused-2.c +++ b/gcc/testsuite/gcc.dg/c2x-attr-maybe_unused-2.c @@ -5,7 +5,7 @@ /* This attribute is not valid in most cases on types other than their definitions, or on statements, or as an attribute-declaration. */ -[[maybe_unused]]; /* { dg-warning "ignored" } */ +[[maybe_unused]]; /* { dg-error "ignored" } */ int [[maybe_unused]] var; /* { dg-warning "ignored" } */ /* { dg-message "that appertains to a type-specifier" "appertains" { target *-*-* } .-1 } */ @@ -20,6 +20,6 @@ void f (void) { int a; - [[maybe_unused]]; /* { dg-warning "ignored" } */ - [[maybe_unused]] a = 1; /* { dg-warning "ignored" } */ + [[maybe_unused]]; /* { dg-error "ignored" } */ + [[maybe_unused]] a = 1; /* { dg-error "ignored" } */ } diff --git a/gcc/testsuite/gcc.dg/c2x-attr-maybe_unused-4.c b/gcc/testsuite/gcc.dg/c2x-attr-maybe_unused-4.c index ae7e1dcd0b7..300c0dae73c 100644 --- a/gcc/testsuite/gcc.dg/c2x-attr-maybe_unused-4.c +++ b/gcc/testsuite/gcc.dg/c2x-attr-maybe_unused-4.c @@ -6,7 +6,7 @@ [[__maybe_unused__, maybe_unused]] int b; /* { dg-error "can appear at most once" } */ int c [[maybe_unused, maybe_unused]]; /* { dg-error "can appear at most once" } */ [[maybe_unused, maybe_unused]]; /* { dg-error "can appear at most once" } */ -/* { dg-warning "ignored" "ignored" { target *-*-* } .-1 } */ +/* { dg-error "ignored" "ignored" { target *-*-* } .-1 } */ /* Separate attribute lists in the same attribute specifier sequence, with the same attribute in them, are OK. */ diff --git a/gcc/testsuite/gcc.dg/c2x-attr-syntax-5.c b/gcc/testsuite/gcc.dg/c2x-attr-syntax-5.c new file mode 100644 index 00000000000..37a24112f63 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-attr-syntax-5.c @@ -0,0 +1,56 @@ +/* Test C2x attribute syntax. Test unknown standard attributes + diagnosed with a pedwarn. */ +/* { dg-do compile } */ +/* { dg-options "-std=c2x -pedantic-errors" } */ + +[[unknown_attribute]]; /* { dg-error "attribute ignored" } */ + +[[unknown_attribute]] extern int a; /* { dg-error "attribute ignored" } */ +extern int [[unknown_attribute(123)]] a; /* { dg-error "attribute ignored" } */ +extern int a [[unknown_attribute("")]]; /* { dg-error "attribute ignored" } */ + +int f () [[unknown_attribute]]; /* { dg-error "attribute ignored" } */ +int f (void) [[unknown_attribute(1)]]; /* { dg-error "attribute ignored" } */ +int g ([[unknown_attribute]] int a); /* { dg-error "attribute ignored" } */ +int g (int [[unknown_attribute]] a); /* { dg-error "attribute ignored" } */ +int g (int a [[unknown_attribute]]); /* { dg-error "attribute ignored" } */ +int g ([[unknown_attribute]] int); /* { dg-error "attribute ignored" } */ +int g (int [[unknown_attribute]]); /* { dg-error "attribute ignored" } */ +int g (int) [[unknown_attribute]]; /* { dg-error "attribute ignored" } */ + +int *[[unknown_attribute]] p; /* { dg-error "attribute ignored" } */ +int b[3] [[unknown_attribute]]; /* { dg-error "attribute ignored" } */ + +int h (int () [[unknown_attribute]]); /* { dg-error "attribute ignored" } */ + +struct [[unknown_attribute]] s; /* { dg-error "attribute ignored" } */ +union [[unknown_attribute]] u; /* { dg-error "attribute ignored" } */ + +struct [[unknown_attribute]] s2 { int a; }; /* { dg-error "attribute ignored" } */ +union [[unknown_attribute(x)]] u2 { int a; }; /* { dg-error "attribute ignored" } */ + +struct s3 { [[unknown_attribute]] int a; }; /* { dg-error "attribute ignored" } */ +struct s4 { int [[unknown_attribute]] a; }; /* { dg-error "attribute ignored" } */ +union u3 { [[unknown_attribute]] int a; }; /* { dg-error "attribute ignored" } */ +union u4 { int [[unknown_attribute]] a; }; /* { dg-error "attribute ignored" } */ + +int z = sizeof (int [[unknown_attribute]]); /* { dg-error "attribute ignored" } */ + +enum [[unknown_attribute]] { E1 }; /* { dg-error "attribute ignored" } */ +enum { E2 [[unknown_attribute]] }; /* { dg-error "attribute ignored" } */ +enum { E3 [[unknown_attribute]] = 4 }; /* { dg-error "attribute ignored" } */ + +void +func (void) [[unknown_attribute]] { /* { dg-error "attribute ignored" } */ + [[unknown_attribute]] int var; /* { dg-error "attribute ignored" } */ + [[unknown_attribute]] { } /* { dg-error "attribute ignored" } */ + [[unknown_attribute(!)]]; /* { dg-error "attribute ignored" } */ + [[unknown_attribute]] var = 1; /* { dg-error "attribute ignored" } */ + [[unknown_attribute]] x: var = 2; /* { dg-error "attribute ignored" } */ + for ([[unknown_attribute]] int zz = 1; zz < 10; zz++) ; /* { dg-error "attribute ignored" } */ +} + +/* nodiscard is not yet implemented, but is a standard attribute, so + its use is not a constraint violation and should only receive a + warning. */ +[[nodiscard]] int ndfunc (void); /* { dg-warning "attribute directive ignored" } */ -- 2.30.2