Here we're failing to communicate to cp_finish_decl from tsubst_expr that we're in a copy-initialization context (via the LOOKUP_ONLYCONVERTING flag), which causes do_class_deduction to always consider explicit deduction guides when performing CTAD for a templated variable initializer.
We could fix this by passing LOOKUP_ONLYCONVERTING appropriately when calling cp_finish_decl from tsubst_expr, but it seems do_class_deduction can determine if we're in a copy-init context by simply inspecting the initializer, and thus render its flags parameter unnecessary, which is what this patch implements. (If we were to fix this in tsubst_expr instead, I think we'd have to inspect the initializer in the same way in order to detect a copy-init context?) Bootstrapped and regtestd on x86_64-pc-linux-gnu, does this look OK for trunk? PR c++/102137 gcc/cp/ChangeLog: * cp-tree.h (do_auto_deduction): Remove flags parameter. * decl.cc (cp_finish_decl): Adjust call to do_auto_deduction. * pt.cc (convert_template_argument): Likewise. (do_class_deduction): Remove flags parameter and instead determine if we're in a copy-init context by inspecting the initializer. (do_auto_deduction): Adjust call to do_class_deduction. gcc/testsuite/ChangeLog: * g++.dg/cpp1z/class-deduction108.C: New test. --- gcc/cp/cp-tree.h | 3 +- gcc/cp/decl.cc | 2 +- gcc/cp/pt.cc | 23 +++++++------ .../g++.dg/cpp1z/class-deduction108.C | 32 +++++++++++++++++++ 4 files changed, 48 insertions(+), 12 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp1z/class-deduction108.C diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index ac723901098..c2ef6544389 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7279,8 +7279,7 @@ extern tree do_auto_deduction (tree, tree, tree, = tf_warning_or_error, auto_deduction_context = adc_unspecified, - tree = NULL_TREE, - int = LOOKUP_NORMAL); + tree = NULL_TREE); extern tree type_uses_auto (tree); extern tree type_uses_auto_or_concept (tree); extern void append_type_to_template_for_access_check (tree, tree, tree, diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index 199ac768d43..152f657e9f2 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -8039,7 +8039,7 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p, outer_targs = DECL_TI_ARGS (decl); type = TREE_TYPE (decl) = do_auto_deduction (type, d_init, auto_node, tf_warning_or_error, adc, - outer_targs, flags); + outer_targs); if (type == error_mark_node) return; if (TREE_CODE (type) == FUNCTION_TYPE) diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index d94d4538faa..66fc8cacdc6 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -8567,8 +8567,7 @@ convert_template_argument (tree parm, can happen in the context of -fnew-ttp-matching. */; else if (tree a = type_uses_auto (t)) { - t = do_auto_deduction (t, arg, a, complain, adc_unify, args, - LOOKUP_IMPLICIT); + t = do_auto_deduction (t, arg, a, complain, adc_unify, args); if (t == error_mark_node) return error_mark_node; } @@ -29832,8 +29831,7 @@ ctad_template_p (tree tmpl) type. */ static tree -do_class_deduction (tree ptype, tree tmpl, tree init, - int flags, tsubst_flags_t complain) +do_class_deduction (tree ptype, tree tmpl, tree init, tsubst_flags_t complain) { /* We should have handled this in the caller. */ if (DECL_TEMPLATE_TEMPLATE_PARM_P (tmpl)) @@ -29881,6 +29879,13 @@ do_class_deduction (tree ptype, tree tmpl, tree init, if (type_dependent_expression_p (init)) return ptype; + bool copy_init_p = true; + if (!init + || TREE_CODE (init) == TREE_LIST + || (BRACE_ENCLOSED_INITIALIZER_P (init) + && CONSTRUCTOR_IS_DIRECT_INIT (init))) + copy_init_p = false; + tree type = TREE_TYPE (tmpl); bool try_list_ctor = false; @@ -29929,7 +29934,7 @@ do_class_deduction (tree ptype, tree tmpl, tree init, /* Prune explicit deduction guides in copy-initialization context (but not copy-list-initialization). */ bool elided = false; - if (!list_init_p && (flags & LOOKUP_ONLYCONVERTING)) + if (!list_init_p && copy_init_p) { for (lkp_iterator iter (cands); !elided && iter; ++iter) if (DECL_NONCONVERTING_P (STRIP_TEMPLATE (*iter))) @@ -30007,7 +30012,7 @@ do_class_deduction (tree ptype, tree tmpl, tree init, } /* [over.match.list]/1: In copy-list-initialization, if an explicit constructor is chosen, the initialization is ill-formed. */ - else if (flags & LOOKUP_ONLYCONVERTING) + else if (copy_init_p) { if (DECL_NONCONVERTING_P (fndecl)) { @@ -30045,7 +30050,7 @@ do_class_deduction (tree ptype, tree tmpl, tree init, /* Replace occurrences of 'auto' in TYPE with the appropriate type deduced from INIT. AUTO_NODE is the TEMPLATE_TYPE_PARM used for 'auto' in TYPE. The CONTEXT determines the context in which auto deduction is performed - and is used to control error diagnostics. FLAGS are the LOOKUP_* flags. + and is used to control error diagnostics. OUTER_TARGS is used during template argument deduction (context == adc_unify) to properly substitute the result. It's also used in the adc_unify and @@ -30058,7 +30063,7 @@ do_class_deduction (tree ptype, tree tmpl, tree init, tree do_auto_deduction (tree type, tree init, tree auto_node, tsubst_flags_t complain, auto_deduction_context context, - tree outer_targs, int flags) + tree outer_targs) { if (init == error_mark_node) return error_mark_node; @@ -30079,7 +30084,7 @@ do_auto_deduction (tree type, tree init, tree auto_node, if (tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (auto_node)) /* C++17 class template argument deduction. */ - return do_class_deduction (type, tmpl, init, flags, complain); + return do_class_deduction (type, tmpl, init, complain); if (init == NULL_TREE || TREE_TYPE (init) == NULL_TREE) /* Nothing we can do with this, even in deduction context. */ diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction108.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction108.C new file mode 100644 index 00000000000..f76671c287a --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction108.C @@ -0,0 +1,32 @@ +// PR c++/102137 +// { dg-do compile { target c++17 } } + +template<class T> +struct A { + A(); + A(int); +}; + +explicit A(int) -> A<int>; +explicit A() -> A<int>; + +template<template<class> class T> +void f() { + T x1 = 0; // { dg-error "deduction|no match" } + T x2 = {0}; // { dg-error "explicit deduction guide" } + T x3(0); + T x4{0}; + T x5; +} + +template<class T> +void g(T t) { + A a1 = t; // { dg-error "deduction|no match" } + A a2 = {t}; // { dg-error "explicit deduction guide" } + A a3(t); + A a4{t}; + A a5; +} + +template void f<A>(); +template void g(int); -- 2.35.1.354.g715d08a9e5