Hi! The standard says that argument-attribute-clause is: attribute-argument-clause: ( balanced-token-seq[opt] ) balanced-token-seq: balanced-token balanced-token-seq balanced-token balanced-token: ( balanced-token-seq[opt] ) [ balanced-token-seq[opt] ] { balanced-token-seq[opt] } any token other than a parenthesis, a bracket, or a brace but the C++ FE parses the attribute arguments always as an expression list with the exception of identifier kept as is in certain cases. That is just fine for all attributes we support right now, but what arguments can have attributes of other compilers or not yet invented attributes and how they should be parsed is unknown, so the only option is IMHO to skip the balanced token set. That is also what the C FE does and what e.g. clang++ seems to do.
I'm not using cp_parser_skip_to_closing_parenthesis in the patch, because cp_parser_skip_to_closing_parenthesis_1 has code to handle ?: specially and I believe given the current grammar and that the argument doesn't have to be necessarily an expression it is wrong, e.g. [[whatever::whatever_else(???)]] could in theory be valid. The primary reason for this change is that OpenMP 5.1 is likely going to have some form of [[omp::... (arguments)]] attributes and the arguments being considered there would be rejected by the current parser. Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2019-11-26 Jakub Jelinek <ja...@redhat.com> PR c++/92648 * parser.c (cp_parser_std_attribute): For unknown attributes, skip balanced token seq instead of trying to parse attribute-argument-clause as expression list. Formatting fix. * g++.dg/cpp0x/gen-attrs-71.C: New test. --- gcc/cp/parser.c.jj 2019-11-22 09:33:08.899909913 +0100 +++ gcc/cp/parser.c 2019-11-25 18:29:06.230699448 +0100 @@ -26629,6 +26629,15 @@ cp_parser_std_attribute (cp_parser *pars /* A GNU attribute that takes an identifier in parameter. */ attr_flag = id_attr; + if (as == NULL) + { + /* For unknown attributes, just skip balanced tokens instead of + trying to parse the arguments. */ + for (size_t n = cp_parser_skip_balanced_tokens (parser, 1) - 1; n; --n) + cp_lexer_consume_token (parser->lexer); + return attribute; + } + vec = cp_parser_parenthesized_expression_list (parser, attr_flag, /*cast_p=*/false, /*allow_expansion_p=*/true, @@ -26637,7 +26646,7 @@ cp_parser_std_attribute (cp_parser *pars arguments = error_mark_node; else { - if (vec->is_empty()) + if (vec->is_empty ()) /* e.g. [[attr()]]. */ error_at (token->location, "parentheses must be omitted if " "%qE attribute argument list is empty", --- gcc/testsuite/g++.dg/cpp0x/gen-attrs-71.C.jj 2019-11-25 18:22:09.486082583 +0100 +++ gcc/testsuite/g++.dg/cpp0x/gen-attrs-71.C 2019-11-25 18:31:14.695730765 +0100 @@ -0,0 +1,7 @@ +// PR c++/92648 +// { dg-do compile { target c++11 } } + +int a [[gnu::no_such_attribute(![!(!)!]!,;;)]]; // { dg-warning "ignored" } +int b [[no_such_namespace::nonexisting_attribute(linear(c, d : 2), reduction(*:e), linear(uval (f)))]]; // { dg-warning "ignored" } +int c [[gnu::nonexisting_attribute()]]; // { dg-warning "ignored" } +int d [[gnu::another_nonexistent_attr(1,"abcd",g+6)]]; // { dg-warning "ignored" } Jakub