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)
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.
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)
--- /dev/null
+// 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" }
+}