}
/* For unknown attributes, just skip balanced tokens instead of
- trying to parse the arguments. */
+ trying to parse the arguments. Set TREE_VALUE (attribute) to
+ error_mark_node to distinguish skipped arguments from attributes
+ with no arguments. */
for (size_t n = cp_parser_skip_balanced_tokens (parser, 1) - 1; n; --n)
cp_lexer_consume_token (parser->lexer);
+ TREE_VALUE (attribute) = error_mark_node;
return attribute;
}
if (attribute == NULL_TREE)
error_at (token->location,
"expected attribute before %<...%>");
- else
+ else if (TREE_VALUE (attribute) == NULL_TREE)
+ {
+ error_at (token->location, "attribute with no arguments "
+ "contains no parameter packs");
+ return error_mark_node;
+ }
+ else if (TREE_VALUE (attribute) != error_mark_node)
{
tree pack = make_pack_expansion (TREE_VALUE (attribute));
if (pack == error_mark_node)
--- /dev/null
+// PR c++/109756
+// { dg-do compile { target c++11 } }
+// { dg-options "-Wno-attributes" }
+
+template <int ...args>
+[[noreturn...]] // { dg-error "attribute with no arguments contains no parameter packs" }
+[[deprecated...]] // { dg-error "attribute with no arguments contains no parameter packs" }
+[[nodiscard...]] // { dg-error "attribute with no arguments contains no parameter packs" }
+int foo (int x)
+{
+ switch (x)
+ {
+ case 1:
+ [[likely...]]; // { dg-error "attribute with no arguments contains no parameter packs" }
+ [[fallthrough...]]; // { dg-error "attribute with no arguments contains no parameter packs" }
+ case 2:
+ [[unlikely...]]; // { dg-error "attribute with no arguments contains no parameter packs" }
+
+ break;
+ default:
+ break;
+ }
+ struct T {};
+ struct S { [[no_unique_address...]] T t; }; // { dg-error "attribute with no arguments contains no parameter packs" }
+ for (;;)
+ ;
+}
+
+int a = foo <1, 2, 3> (4);