In this PR, we are wrongly parsing a constructor if its first parameter begins with a C++11 attribute, e.g.:
struct S { S([[maybe_unused]] int a) { } }; If the GNU attribute format is used instead, there's no problem. C++11-style attribute on a later parameter is fine also. The problem is in cp_parser_constructor_declarator_p, in particular the code that checks whether we're dealing with something like "S (f) (int);", which is not a constructor. We're checking if what comes after the first '(' is either ')', "...", of a parameter decl. A parameter decl can start with the "attribute" keyword, which cp_lexer_next_token_is_decl_specifier_keyword recognizes, but a parameter decl can also start with a C++11-style attribute, which we forgot to realize. The first test uses -Wunused-parameter in order to check that the attribute is in effect. And I also noticed that we don't issue a pedwarn about maybe_unused (C++17 attribute) in C++14: PR 91382. Bootstrapped/regtested on x86_64-linux, ok for trunk? I think this should also go into 9.3. 2019-08-06 Marek Polacek <pola...@redhat.com> PR c++/81429 - wrong parsing of constructor with C++11 attribute. * parser.c (cp_parser_constructor_declarator_p): Handle the scenario when a parameter declaration begins with [[attribute]]. * g++.dg/cpp0x/gen-attrs-68.C: New test. * g++.dg/cpp0x/gen-attrs-69.C: New test. diff --git gcc/cp/parser.c gcc/cp/parser.c index 79da7b52eb9..b8996c707b6 100644 --- gcc/cp/parser.c +++ gcc/cp/parser.c @@ -27855,7 +27855,9 @@ cp_parser_constructor_declarator_p (cp_parser *parser, cp_parser_flags flags, /* A parameter declaration begins with a decl-specifier, which is either the "attribute" keyword, a storage class specifier, or (usually) a type-specifier. */ - && !cp_lexer_next_token_is_decl_specifier_keyword (parser->lexer)) + && !cp_lexer_next_token_is_decl_specifier_keyword (parser->lexer) + /* A parameter declaration can also begin with [[attribute]]. */ + && !cp_next_tokens_can_be_std_attribute_p (parser)) { tree type; tree pushed_scope = NULL_TREE; diff --git gcc/testsuite/g++.dg/cpp0x/gen-attrs-68.C gcc/testsuite/g++.dg/cpp0x/gen-attrs-68.C new file mode 100644 index 00000000000..6bede0659db --- /dev/null +++ gcc/testsuite/g++.dg/cpp0x/gen-attrs-68.C @@ -0,0 +1,40 @@ +// PR c++/81429 - wrong parsing of constructor with C++11 attribute. +// { dg-do compile { target c++11 } } +// { dg-additional-options "-Wunused-parameter -Wno-pedantic" } + +void fn1([[maybe_unused]] int a) { } +void fn2(int a [[maybe_unused]]) { } +void fn3(__attribute__((unused)) int a) { } +void fn4(int a __attribute__((unused))) { } + +struct S1 { + S1([[maybe_unused]] int a) { } +}; + +struct S2 { + S2([[maybe_unused]] int f, [[maybe_unused]] int a) { } +}; + +struct S3 { + S3(int a [[maybe_unused]]) { } +}; + +struct S4 { + S4(int f [[maybe_unused]], int a [[maybe_unused]]) { } +}; + +struct S5 { + S5(__attribute__((unused)) int a) { } +}; + +struct S6 { + S6(__attribute__((unused)) int f, __attribute__((unused)) int a) { } +}; + +struct S7 { + S7(int a __attribute__((unused))) { } +}; + +struct S8 { + S8(int f __attribute__((unused)), int a __attribute__((unused))) { } +}; diff --git gcc/testsuite/g++.dg/cpp0x/gen-attrs-69.C gcc/testsuite/g++.dg/cpp0x/gen-attrs-69.C new file mode 100644 index 00000000000..43173dbbdf4 --- /dev/null +++ gcc/testsuite/g++.dg/cpp0x/gen-attrs-69.C @@ -0,0 +1,40 @@ +// PR c++/81429 - wrong parsing of constructor with C++11 attribute. +// { dg-do compile { target c++11 } } +// { dg-additional-options "-Wno-pedantic" } + +void fn1([[maybe_unused]] int); +void fn2(int a [[maybe_unused]]); +void fn3(__attribute__((unused)) int); +void fn4(int __attribute__((unused))); + +struct S1 { + S1([[maybe_unused]] int); +}; + +struct S2 { + S2([[maybe_unused]] int, [[maybe_unused]] int); +}; + +struct S3 { + S3(int a [[maybe_unused]]); +}; + +struct S4 { + S4(int a [[maybe_unused]], int b [[maybe_unused]]); +}; + +struct S5 { + S5(__attribute__((unused)) int); +}; + +struct S6 { + S6(__attribute__((unused)) int, __attribute__((unused)) int); +}; + +struct S7 { + S7(int __attribute__((unused))); +}; + +struct S8 { + S8(int __attribute__((unused)), int __attribute__((unused))); +};