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 <[email protected]>
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)));
+};