https://gcc.gnu.org/g:9d5c276dfb5f5812e0fa7b46e84beaca36295c6d
commit r17-482-g9d5c276dfb5f5812e0fa7b46e84beaca36295c6d Author: [email protected] <[email protected]> Date: Wed May 13 00:48:45 2026 -0400 c++/reflection: reject invalid annotation on class [PR123609] Some errors while parsing attributes on class are ignored due to tentative parsing, this patch redo parsing to reject it. PR c++/123609 gcc/cp/ChangeLog: * parser.cc (cp_parser_class_head): Re-parse attributes that caused a tentative parsing failure. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/attr-nodiscard1.C: Adjust expected errors. * g++.dg/reflect/annotations19.C: New test. Co-authored-by: Jason Merrill <[email protected]> Diff: --- gcc/cp/parser.cc | 15 +++++++++++++++ gcc/testsuite/g++.dg/cpp0x/attr-nodiscard1.C | 4 ++-- gcc/testsuite/g++.dg/reflect/annotations19.C | 5 +++++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index c08f4cee920d..c7708f15f39b 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -30295,7 +30295,13 @@ cp_parser_class_head (cp_parser* parser, location_t class_head_start_location = input_location; /* Parse the attributes. */ + /* Save tokens for some unhandled error (PR123609). */ + cp_token_position attribute_error_position = 0; + if (!cp_parser_error_occurred (parser)) + attribute_error_position = cp_lexer_token_position (parser->lexer, false); attributes = cp_parser_attributes_opt (parser); + if (!cp_parser_error_occurred (parser)) + attribute_error_position = 0; /* If the next token is `::', that is invalid -- but sometimes people do try to write: @@ -30437,6 +30443,15 @@ cp_parser_class_head (cp_parser* parser, /* At this point, we're going ahead with the class-specifier, even if some other problem occurs. */ cp_parser_commit_to_tentative_parse (parser); + /* Some errors while parsing attributes are ignored due to tentative parsing, + redo parsing to reject it. */ + if (attribute_error_position) + { + auto current_position = cp_lexer_token_position (parser->lexer, false); + cp_lexer_set_token_position (parser->lexer, attribute_error_position); + cp_parser_attributes_opt (parser); + cp_lexer_set_token_position (parser->lexer, current_position); + } /* Issue the error about the overly-qualified name now. */ if (qualified_p) { diff --git a/gcc/testsuite/g++.dg/cpp0x/attr-nodiscard1.C b/gcc/testsuite/g++.dg/cpp0x/attr-nodiscard1.C index 5abdd380f9d2..5b97d0b61044 100644 --- a/gcc/testsuite/g++.dg/cpp0x/attr-nodiscard1.C +++ b/gcc/testsuite/g++.dg/cpp0x/attr-nodiscard1.C @@ -10,9 +10,9 @@ foo (int n) { struct [[nodiscard]] S1 {}; struct [[nodiscard ("foobar")]] S2 {}; - struct [[nodiscard (0)]] S3 {}; // { dg-error "'nodiscard' attribute argument must be a string constant" } + struct [[nodiscard (0)]] S3 {}; // { dg-error "'nodiscard' attribute argument must be a string constant|expected string-literal" } struct [[nodiscard ("foo", "bar", "baz")]] S4 {}; // { dg-error "wrong number of arguments specified for 'nodiscard' attribute" } - struct [[nodiscard (0, 1, 2)]] S5 {}; // { dg-error "wrong number of arguments specified for 'nodiscard' attribute" } + struct [[nodiscard (0, 1, 2)]] S5 {}; // { dg-error "wrong number of arguments specified for 'nodiscard' attribute|expected string-literal" } auto a = [] [[nodiscard]] () {}; auto b = [] constexpr [[nodiscard]] {}; // { dg-warning "'nodiscard' attribute can only be applied to functions or to class or enumeration types" } diff --git a/gcc/testsuite/g++.dg/reflect/annotations19.C b/gcc/testsuite/g++.dg/reflect/annotations19.C new file mode 100644 index 000000000000..2408aec809c6 --- /dev/null +++ b/gcc/testsuite/g++.dg/reflect/annotations19.C @@ -0,0 +1,5 @@ +// PR c++/123609 +// { dg-do compile { target c++26 } } + +struct [[=]] S {}; // { dg-error "expected primary-expression before ']' token" } +[[=]] int a; // { dg-error "expected primary-expression before ']' token" }
