On 8/9/21 1:16 PM, Patrick Palka wrote:
It looks like we still don't recognize class-scope non-template
deduction guides even after r12-2260. This is because deduction guides
are handled in cp_parser_init_declarator after calling
cp_parser_declarator, but in the class-scope non-template case we call
cp_parser_declarator directly from cp_parser_member_declaration.
This patch makes us handle deduction guides in cp_parser_member_declaration
as well.
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk?
PR c++/79501
gcc/cp/ChangeLog:
* parser.c (cp_parser_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 | 54 +++++++++++++------
.../g++.dg/cpp1z/class-deduction98.C | 10 ++++
2 files changed, 49 insertions(+), 15 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/cpp1z/class-deduction98.C
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index d4da25ca703..04fdeec32ab 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -21869,6 +21869,30 @@ warn_about_ambiguous_parse (const
cp_decl_specifier_seq *decl_specifiers,
}
}
+/* If the function declarator DECLARATOR names a class template, adjust
+ it to name its deduction guides and return true. Otherwise return false.
*/
+
+static bool
+cp_parser_maybe_adjust_declarator_for_dguide (cp_parser *parser,
+ cp_declarator *declarator)
+{
+ gcc_assert (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;
+ return true;
+ }
+ return false;
+}
+
/* Declarators [gram.dcl.decl] */
/* Parse an init-declarator.
@@ -22045,25 +22069,16 @@ cp_parser_init_declarator (cp_parser* parser,
if (function_declarator_p (declarator))
{
- /* Handle C++17 deduction guides. */
+ /* Handle C++17 deduction guides. Note that class-scope
+ non-template deduction guides are handled in
+ cp_parser_member_declaration. */
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;
- }
- }
+ if (cp_parser_maybe_adjust_declarator_for_dguide (parser,
+ declarator))
+ ctor_dtor_or_conv_p = 1;
if (!member_p && !cp_parser_error_occurred (parser))
warn_about_ambiguous_parse (decl_specifiers, declarator);
@@ -26719,6 +26734,15 @@ cp_parser_member_declaration (cp_parser* parser)
cp_lexer_consume_token (parser->lexer);
goto out;
}
+ /* Handle class-scope non-template C++17 deduction guides. */
+ if (function_declarator_p (declarator)
+ && !decl_specifiers.type
+ && !decl_specifiers.any_type_specifiers_p
+ && ctor_dtor_or_conv_p <= 0
+ && cxx_dialect >= cxx17)
Looks like you could factor more of the tests into the new function.
+ if (cp_parser_maybe_adjust_declarator_for_dguide (parser,
+ declarator))
+ ctor_dtor_or_conv_p = 1;
if (declares_class_or_enum & 2)
cp_parser_check_for_definition_in_return_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
index 00000000000..bee0ce433ee
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction98.C
@@ -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);