c++: DR 1914 - Allow duplicate standard attributes.
Following Joseph's change for C to allow duplicate C2x standard attributes <https://gcc.gnu.org/pipermail/gcc-patches/2020-October/557272.html>, this patch does a similar thing for C++. This is DR 1914, to be resolved by <wg21.link/p2156>, 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.
This commit is contained in:
parent
d3fd75d869
commit
04126e46eb
@ -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, "%<fallthrough%> attribute specified multiple "
|
||||
warning (OPT_Wattributes, "attribute %<fallthrough%> specified multiple "
|
||||
"times");
|
||||
/* No attribute-argument-clause shall be present. */
|
||||
else if (TREE_VALUE (t) != NULL_TREE)
|
||||
|
@ -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 %<noreturn%> can appear at most once "
|
||||
"in an attribute-list");
|
||||
else if (is_attribute_p ("deprecated", name)
|
||||
&& lookup_attribute ("deprecated", attributes))
|
||||
error ("attribute %<deprecated%> can appear at most once "
|
||||
"in an attribute-list");
|
||||
else if (is_attribute_p ("nodiscard", name)
|
||||
&& lookup_attribute ("nodiscard", attributes))
|
||||
error ("attribute %<nodiscard%> 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)
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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" }
|
||||
|
45
gcc/testsuite/g++.dg/cpp0x/gen-attrs-72.C
Normal file
45
gcc/testsuite/g++.dg/cpp0x/gen-attrs-72.C
Normal file
@ -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" }
|
||||
}
|
@ -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" }
|
||||
|
@ -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" }
|
||||
|
||||
|
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user