On 12/20/19 6:27 PM, Jakub Jelinek wrote:
Hi!
In C++17/2a mode, cp_parser_constructor_declarator_p because of deduction
guides considers constructor_p in more cases and returns true on
typedef struct S { int x; } T;
T (__attribute__((unused)) qux) (T x);
just because constructor arguments may start with __attribute__ keyword
(as the testcase tests, yes, they can, but parenthesized declarator can
too), and so we reject the above declaration, even when it is valid and
accepted in C++98/11/14 modes too.
The testcase shows this causing problems already before, e.g. declaring
methods with parenthesized declarator starting with attribute used to be
considered as constructor and rejected for quite a while.
Fixed thusly, bootstrapped/regtested on x86_64-linux and i686-linux, ok for
trunk?
OK.
2019-12-20 Jakub Jelinek <ja...@redhat.com>
PR c++/92438
* parser.c (cp_parser_constructor_declarator_p): If open paren
is followed by RID_ATTRIBUTE, skip over the attribute tokens and
try to parse type specifier.
* g++.dg/ext/attrib61.C: New test.
--- gcc/cp/parser.c.jj 2019-12-20 17:51:44.979483292 +0100
+++ gcc/cp/parser.c 2019-12-20 19:15:40.011165334 +0100
@@ -28493,7 +28493,15 @@ cp_parser_constructor_declarator_p (cp_p
/* 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)
+ /* GNU attributes can actually appear both at the start of
+ a parameter and parenthesized declarator.
+ S (__attribute__((unused)) int);
+ is a constructor, but
+ S (__attribute__((unused)) foo) (int);
+ is a function declaration. */
+ || (cp_parser_allow_gnu_extensions_p (parser)
+ && cp_next_tokens_can_be_gnu_attribute_p (parser)))
/* A parameter declaration can also begin with [[attribute]]. */
&& !cp_next_tokens_can_be_std_attribute_p (parser))
{
@@ -28501,6 +28509,13 @@ cp_parser_constructor_declarator_p (cp_p
tree pushed_scope = NULL_TREE;
unsigned saved_num_template_parameter_lists;
+ if (cp_next_tokens_can_be_gnu_attribute_p (parser))
+ {
+ unsigned int n = cp_parser_skip_gnu_attributes_opt (parser, 1);
+ while (--n)
+ cp_lexer_consume_token (parser->lexer);
+ }
+
/* Names appearing in the type-specifier should be looked up
in the scope of the class. */
if (current_class_type)
--- gcc/testsuite/g++.dg/ext/attrib61.C.jj 2019-12-20 19:22:30.073916272
+0100
+++ gcc/testsuite/g++.dg/ext/attrib61.C 2019-12-20 19:19:44.325450755 +0100
@@ -0,0 +1,26 @@
+// PR c++/92438
+// { dg-do compile }
+
+typedef struct S { int x; } T;
+T (foo) (T x);
+T __attribute__((unused)) bar (T x);
+struct S (__attribute__((unused)) baz) (T x);
+T (__attribute__((unused)) qux) (T x);
+
+struct U
+{
+ U (__attribute__((unused)) int);
+ U (__attribute__((unused)) corge) (int);
+};
+
+void
+test ()
+{
+ T a, b;
+ a = foo (b);
+ b = bar (a);
+ a = baz (b);
+ b = qux (a);
+ U u (5);
+ U v = u.corge (3);
+}
Jakub