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?

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

Reply via email to