c++: recognize class-scope non-template dguides [PR79501]
authorPatrick Palka <ppalka@redhat.com>
Wed, 11 Aug 2021 19:59:22 +0000 (15:59 -0400)
committerPatrick Palka <ppalka@redhat.com>
Wed, 11 Aug 2021 19:59:22 +0000 (15:59 -0400)
It looks like we still don't recognize class-scope non-template
deduction guides even after r12-2260.   This is because deduction guides
are tagged as such in cp_parser_init_declarator after calling
cp_parser_declarator, but in cp_parser_member_declaration we call
cp_parser_declarator directly.

So let's tag them in cp_parser_member_declaration as well.

PR c++/79501

gcc/cp/ChangeLog:

* parser.c (maybe_adjust_declarator_for_dguide): New, split
out from ...
(cp_parser_init_declarator): ... here.
(cp_parser_member_declaration): Use it.

gcc/testsuite/ChangeLog:

* g++.dg/cpp1z/class-deduction98.C: New test.

gcc/cp/parser.c
gcc/testsuite/g++.dg/cpp1z/class-deduction98.C [new file with mode: 0644]

index 87e8d37..b5e117d 100644 (file)
@@ -22078,6 +22078,37 @@ warn_about_ambiguous_parse (const cp_decl_specifier_seq *decl_specifiers,
     }
 }
 
+/* If DECLARATOR with DECL_SPECS is a function declarator that has
+   the form of a deduction guide, tag it as such.  CTOR_DTOR_OR_CONV_P
+   has the same meaning as in cp_parser_declarator.  */
+
+static void
+cp_parser_maybe_adjust_declarator_for_dguide (cp_parser *parser,
+                                             cp_decl_specifier_seq *decl_specs,
+                                             cp_declarator *declarator,
+                                             int *ctor_dtor_or_conv_p)
+{
+  if (cxx_dialect >= cxx17
+      && *ctor_dtor_or_conv_p <= 0
+      && !decl_specs->type
+      && !decl_specs->any_type_specifiers_p
+      && function_declarator_p (declarator))
+    {
+      cp_declarator *id = get_id_declarator (declarator);
+      tree name = id->u.id.unqualified_name;
+      parser->scope = id->u.id.qualifying_scope;
+      tree tmpl = cp_parser_lookup_name_simple (parser, name, id->id_loc);
+      if (tmpl
+         && (DECL_CLASS_TEMPLATE_P (tmpl)
+             || DECL_TEMPLATE_TEMPLATE_PARM_P (tmpl)))
+       {
+         id->u.id.unqualified_name = dguide_name (tmpl);
+         id->u.id.sfk = sfk_deduction_guide;
+         *ctor_dtor_or_conv_p = 1;
+       }
+    }
+}
+
 /* Declarators [gram.dcl.decl] */
 
 /* Parse an init-declarator.
@@ -22254,25 +22285,13 @@ cp_parser_init_declarator (cp_parser* parser,
 
   if (function_declarator_p (declarator))
     {
-      /* Handle C++17 deduction guides.  */
-      if (!decl_specifiers->type
-         && !decl_specifiers->any_type_specifiers_p
-         && ctor_dtor_or_conv_p <= 0
-         && cxx_dialect >= cxx17)
-       {
-         cp_declarator *id = get_id_declarator (declarator);
-         tree name = id->u.id.unqualified_name;
-         parser->scope = id->u.id.qualifying_scope;
-         tree tmpl = cp_parser_lookup_name_simple (parser, name, id->id_loc);
-         if (tmpl
-             && (DECL_CLASS_TEMPLATE_P (tmpl)
-                 || DECL_TEMPLATE_TEMPLATE_PARM_P (tmpl)))
-           {
-             id->u.id.unqualified_name = dguide_name (tmpl);
-             id->u.id.sfk = sfk_deduction_guide;
-             ctor_dtor_or_conv_p = 1;
-           }
-       }
+      /* Handle C++17 deduction guides.  Note that class-scope
+        non-template deduction guides are instead handled in
+        cp_parser_member_declaration.  */
+      cp_parser_maybe_adjust_declarator_for_dguide (parser,
+                                                   decl_specifiers,
+                                                   declarator,
+                                                   &ctor_dtor_or_conv_p);
 
       if (!member_p && !cp_parser_error_occurred (parser))
        warn_about_ambiguous_parse (decl_specifiers, declarator);
@@ -26956,6 +26975,12 @@ cp_parser_member_declaration (cp_parser* parser)
                  goto out;
                }
 
+             /* Handle class-scope non-template C++17 deduction guides.  */
+             cp_parser_maybe_adjust_declarator_for_dguide (parser,
+                                                           &decl_specifiers,
+                                                           declarator,
+                                                           &ctor_dtor_or_conv_p);
+
              if (declares_class_or_enum & 2)
                cp_parser_check_for_definition_in_return_type
                                            (declarator, decl_specifiers.type,
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction98.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction98.C
new file mode 100644 (file)
index 0000000..bee0ce4
--- /dev/null
@@ -0,0 +1,10 @@
+// PR c++/79501
+// { dg-do compile { target c++17 } }
+
+template<class T>
+struct A {
+  template<class U> struct B { template<class V> B(V); };
+  B(T) -> B<T>;
+};
+
+A<int>::B b(0);