From: Marek Polacek Date: Fri, 6 Nov 2020 17:33:53 +0000 (-0500) Subject: c++: DR 1914 - Allow duplicate standard attributes. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=04126e46eb2d829d7b4149d394b667e878912cc8;p=gcc.git c++: DR 1914 - Allow duplicate standard attributes. Following Joseph's change for C to allow duplicate C2x standard attributes , this patch does a similar thing for C++. This is DR 1914, to be resolved by , which is not part of the standard yet, but has wide support so looks like a shoo-in. The duplications now produce warnings instead, but only if the attribute wasn't specified via a macro. gcc/c-family/ChangeLog: DR 1914 * c-common.c (attribute_fallthrough_p): Tweak the warning message. gcc/cp/ChangeLog: DR 1914 * parser.c (cp_parser_check_std_attribute): Return bool. Add a location_t parameter. Return true if the attribute wasn't duplicated. Give a warning instead of an error. Check more attributes. (cp_parser_std_attribute_list): Don't add duplicated attributes to the list. Pass location to cp_parser_check_std_attribute. gcc/testsuite/ChangeLog: DR 1914 * c-c++-common/attr-fallthrough-2.c: Adjust dg-warning. * g++.dg/cpp0x/fallthrough2.C: Likewise. * g++.dg/cpp0x/gen-attrs-60.C: Turn dg-error into dg-warning. * g++.dg/cpp1y/attr-deprecated-2.C: Likewise. * g++.dg/cpp2a/attr-likely2.C: Adjust dg-warning. * g++.dg/cpp2a/nodiscard-once.C: Turn dg-error into dg-warning. * g++.dg/cpp0x/gen-attrs-72.C: New test. --- diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index d4d3228b8f6..29508bca97b 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -5752,9 +5752,10 @@ attribute_fallthrough_p (tree attr) tree t = lookup_attribute ("fallthrough", attr); if (t == NULL_TREE) return false; - /* This attribute shall appear at most once in each attribute-list. */ + /* It is no longer true that "this attribute shall appear at most once in + each attribute-list", but we still give a warning. */ if (lookup_attribute ("fallthrough", TREE_CHAIN (t))) - warning (OPT_Wattributes, "% attribute specified multiple " + warning (OPT_Wattributes, "attribute % specified multiple " "times"); /* No attribute-argument-clause shall be present. */ else if (TREE_VALUE (t) != NULL_TREE) diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index b14b4c90c92..4c819ea1c5d 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -27280,30 +27280,30 @@ cp_parser_std_attribute (cp_parser *parser, tree attr_ns) return attribute; } -/* Check that the attribute ATTRIBUTE appears at most once in the - attribute-list ATTRIBUTES. This is enforced for noreturn (7.6.3), - nodiscard, and deprecated (7.6.5). Note that - carries_dependency (7.6.4) isn't implemented yet in GCC. */ +/* Warn if the attribute ATTRIBUTE appears more than once in the + attribute-list ATTRIBUTES. This used to be enforced for certain + attributes, but the restriction was removed in P2156. Note that + carries_dependency ([dcl.attr.depend]) isn't implemented yet in GCC. + LOC is the location of ATTRIBUTE. Returns true if ATTRIBUTE was not + found in ATTRIBUTES. */ -static void -cp_parser_check_std_attribute (tree attributes, tree attribute) +static bool +cp_parser_check_std_attribute (location_t loc, tree attributes, tree attribute) { + static auto alist = { "noreturn", "deprecated", "nodiscard", "maybe_unused", + "likely", "unlikely", "fallthrough", + "no_unique_address" }; if (attributes) - { - tree name = get_attribute_name (attribute); - if (is_attribute_p ("noreturn", name) - && lookup_attribute ("noreturn", attributes)) - error ("attribute % can appear at most once " - "in an attribute-list"); - else if (is_attribute_p ("deprecated", name) - && lookup_attribute ("deprecated", attributes)) - error ("attribute % can appear at most once " - "in an attribute-list"); - else if (is_attribute_p ("nodiscard", name) - && lookup_attribute ("nodiscard", attributes)) - error ("attribute % can appear at most once " - "in an attribute-list"); - } + for (const auto &a : alist) + if (is_attribute_p (a, get_attribute_name (attribute)) + && lookup_attribute (a, attributes)) + { + if (!from_macro_expansion_at (loc)) + warning_at (loc, OPT_Wattributes, "attribute %qs specified " + "multiple times", a); + return false; + } + return true; } /* Parse a list of standard C++-11 attributes. @@ -27323,14 +27323,17 @@ cp_parser_std_attribute_list (cp_parser *parser, tree attr_ns) while (true) { + location_t loc = cp_lexer_peek_token (parser->lexer)->location; attribute = cp_parser_std_attribute (parser, attr_ns); if (attribute == error_mark_node) break; if (attribute != NULL_TREE) { - cp_parser_check_std_attribute (attributes, attribute); - TREE_CHAIN (attribute) = attributes; - attributes = attribute; + if (cp_parser_check_std_attribute (loc, attributes, attribute)) + { + TREE_CHAIN (attribute) = attributes; + attributes = attribute; + } } token = cp_lexer_peek_token (parser->lexer); if (token->type == CPP_ELLIPSIS) diff --git a/gcc/testsuite/c-c++-common/attr-fallthrough-2.c b/gcc/testsuite/c-c++-common/attr-fallthrough-2.c index be61d5e6666..156b413db7a 100644 --- a/gcc/testsuite/c-c++-common/attr-fallthrough-2.c +++ b/gcc/testsuite/c-c++-common/attr-fallthrough-2.c @@ -34,7 +34,7 @@ fn (int i) __attribute__((fallthrough ("x"))); /* { dg-warning "specified with a parameter" } */ case 7: bar (1); - __attribute__((fallthrough, fallthrough)); /* { dg-warning "attribute specified multiple times" } */ + __attribute__((fallthrough, fallthrough)); /* { dg-warning "specified multiple times" } */ case 8: bar (1); __attribute__((fallthrough)); diff --git a/gcc/testsuite/g++.dg/cpp0x/fallthrough2.C b/gcc/testsuite/g++.dg/cpp0x/fallthrough2.C index f2d0ce1c693..071c2cb09eb 100644 --- a/gcc/testsuite/g++.dg/cpp0x/fallthrough2.C +++ b/gcc/testsuite/g++.dg/cpp0x/fallthrough2.C @@ -14,7 +14,7 @@ f (int i) [[fallthrough]]; case 3: bar (1); - [[gnu::fallthrough, gnu::fallthrough]]; // { dg-warning ".fallthrough. attribute specified multiple times" } + [[gnu::fallthrough, gnu::fallthrough]]; // { dg-warning ".fallthrough. specified multiple times" } case 2: bar (2); } diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-60.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-60.C index cb0c31ec63f..9203d1dd1bd 100644 --- a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-60.C +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-60.C @@ -1,4 +1,4 @@ // PR c++/60365 // { dg-do compile { target c++11 } } -void func [[noreturn, noreturn]] (); // { dg-error "at most once" } +void func [[noreturn, noreturn]] (); // { dg-warning "specified multiple times" } diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-72.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-72.C new file mode 100644 index 00000000000..3c235b5e921 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-72.C @@ -0,0 +1,45 @@ +// DR 1914 - Duplicate standard attributes +// { dg-do compile { target c++11 } } + +#define ATTR_NORETURN [[noreturn, noreturn]] + +[[noreturn, noreturn]] void fn0(); // { dg-warning "specified multiple times" } +ATTR_NORETURN void fn0a(); +[[noreturn]] [[noreturn]] void fn1(); +[[deprecated, deprecated]] void fn2(); // { dg-warning "specified multiple times" } +[[deprecated]] [[deprecated]] void fn3(); +[[maybe_unused]] [[maybe_unused]] int fn4(); +[[maybe_unused, maybe_unused]] int fn5(); // { dg-warning "specified multiple times" } +[[nodiscard]] [[nodiscard]] int fn6(); +[[nodiscard, nodiscard]] int fn7(); // { dg-warning "specified multiple times" } + +struct E { }; +struct A { + [[no_unique_address]] [[no_unique_address]] E e; +}; +struct B { + [[no_unique_address, no_unique_address]] E e; // { dg-warning "specified multiple times" } +}; + +int +f (int n) +{ + switch (n) + { + case 1: + [[fallthrough, fallthrough]]; // { dg-warning "specified multiple times" } + case 2: + [[fallthrough]] [[fallthrough]]; // { dg-warning "specified multiple times" } + case 3: + return 15; + } + + if (n == 10) + [[likely]] [[likely]] return 42; // { dg-warning "ignoring attribute" } + else if (n == 11) + [[unlikely]] [[unlikely]] return 10; // { dg-warning "ignoring attribute" } + else if (n == 12) + [[likely, likely]] return 42; // { dg-warning "specified multiple times" } + else + [[unlikely, unlikely]] return 0; // { dg-warning "specified multiple times" } +} diff --git a/gcc/testsuite/g++.dg/cpp1y/attr-deprecated-2.C b/gcc/testsuite/g++.dg/cpp1y/attr-deprecated-2.C index 12c75c7ba73..ac6c4aecf9b 100644 --- a/gcc/testsuite/g++.dg/cpp1y/attr-deprecated-2.C +++ b/gcc/testsuite/g++.dg/cpp1y/attr-deprecated-2.C @@ -1,4 +1,4 @@ // PR c++/60365 // { dg-do compile { target c++14 } } -void func [[deprecated, deprecated]] (); // { dg-error "at most once" } +void func [[deprecated, deprecated]] (); // { dg-warning "specified multiple times" } diff --git a/gcc/testsuite/g++.dg/cpp2a/attr-likely2.C b/gcc/testsuite/g++.dg/cpp2a/attr-likely2.C index ee178dec9c5..0bc5f1e1ae7 100644 --- a/gcc/testsuite/g++.dg/cpp2a/attr-likely2.C +++ b/gcc/testsuite/g++.dg/cpp2a/attr-likely2.C @@ -4,7 +4,7 @@ bool b; int main() { if (b) - [[likely, likely]] b; // { dg-warning "ignoring" } + [[likely, likely]] b; // { dg-warning "specified multiple times" } else [[unlikely]] [[likely]] b; // { dg-warning "ignoring" } diff --git a/gcc/testsuite/g++.dg/cpp2a/nodiscard-once.C b/gcc/testsuite/g++.dg/cpp2a/nodiscard-once.C index c810fd0daad..c95fa1b0741 100644 --- a/gcc/testsuite/g++.dg/cpp2a/nodiscard-once.C +++ b/gcc/testsuite/g++.dg/cpp2a/nodiscard-once.C @@ -2,7 +2,7 @@ /* { dg-do compile { target c++20 } } */ /* { dg-options "-O -ftrack-macro-expansion=0" } */ -[[nodiscard, nodiscard]] int check1 (void); /* { dg-error "nodiscard\[^\n\r]*can appear at most once" } */ +[[nodiscard, nodiscard]] int check1 (void); // { dg-warning "specified multiple times" } void test (void)