Skip to content

Commit cf7dae0

Browse files
committed
c++: CTAD and explicit deduction guides for copy-list-init [PR90210]
This PR points out that we accept template<typename T> struct tuple { tuple(T); }; // #1 template<typename T> explicit tuple(T t) -> tuple<T>; // gcc-mirror#2 tuple t = { 1 }; despite the 'explicit' deduction guide in a copy-list-initialization context. That's because in deduction_guides_for we first find the user-defined deduction guide (gcc-mirror#2), and then ctor_deduction_guides_for creates artificial deduction guides: one from the tuple(T) constructor and a copy guide. So we end up with these three guides: (1) template<class T> tuple(T) -> tuple<T> [DECL_NONCONVERTING_P] (2) template<class T> tuple(tuple<T>) -> tuple<T> (3) template<class T> tuple(T) -> tuple<T> Then, in do_class_deduction, we prune this set, and get rid of (1). Then overload resolution selects (3) and we succeed. But [over.match.list]p1 says "In copy-list-initialization, if an explicit constructor is chosen, the initialization is ill-formed." It also goes on to say that this differs from other situations where only converting constructors are considered for copy-initialization. Therefore for list-initialization we consider explicit constructors and complain if one is chosen. E.g. convert_like_internal/ck_user can give an error. So my logic runs that we should not prune the deduction_guides_for guides in a copy-list-initialization context, and only complain if we actually choose an explicit deduction guide. This matches clang++/EDG/msvc++. gcc/cp/ChangeLog: PR c++/90210 * pt.c (do_class_deduction): Don't prune explicit deduction guides in copy-list-initialization. In copy-list-initialization, if an explicit deduction guide was selected, give an error. gcc/testsuite/ChangeLog: PR c++/90210 * g++.dg/cpp1z/class-deduction73.C: New test.
1 parent 660bfe6 commit cf7dae0

File tree

2 files changed

+79
-11
lines changed

2 files changed

+79
-11
lines changed

gcc/cp/pt.c

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28977,13 +28977,15 @@ do_class_deduction (tree ptype, tree tmpl, tree init,
2897728977
tree type = TREE_TYPE (tmpl);
2897828978

2897928979
bool try_list_ctor = false;
28980+
bool list_init_p = false;
2898028981

2898128982
releasing_vec rv_args = NULL;
2898228983
vec<tree,va_gc> *&args = *&rv_args;
2898328984
if (init == NULL_TREE)
2898428985
args = make_tree_vector ();
2898528986
else if (BRACE_ENCLOSED_INITIALIZER_P (init))
2898628987
{
28988+
list_init_p = true;
2898728989
try_list_ctor = TYPE_HAS_LIST_CTOR (type);
2898828990
if (try_list_ctor && CONSTRUCTOR_NELTS (init) == 1)
2898928991
{
@@ -29016,9 +29018,10 @@ do_class_deduction (tree ptype, tree tmpl, tree init,
2901629018
if (cands == error_mark_node)
2901729019
return error_mark_node;
2901829020

29019-
/* Prune explicit deduction guides in copy-initialization context. */
29021+
/* Prune explicit deduction guides in copy-initialization context (but
29022+
not copy-list-initialization). */
2902029023
bool elided = false;
29021-
if (flags & LOOKUP_ONLYCONVERTING)
29024+
if (!list_init_p && (flags & LOOKUP_ONLYCONVERTING))
2902229025
{
2902329026
for (lkp_iterator iter (cands); !elided && iter; ++iter)
2902429027
if (DECL_NONCONVERTING_P (STRIP_TEMPLATE (*iter)))
@@ -29087,18 +29090,42 @@ do_class_deduction (tree ptype, tree tmpl, tree init,
2908729090
--cp_unevaluated_operand;
2908829091
}
2908929092

29090-
if (call == error_mark_node
29091-
&& (complain & tf_warning_or_error))
29093+
if (call == error_mark_node)
2909229094
{
29093-
error ("class template argument deduction failed:");
29095+
if (complain & tf_warning_or_error)
29096+
{
29097+
error ("class template argument deduction failed:");
2909429098

29095-
++cp_unevaluated_operand;
29096-
call = build_new_function_call (cands, &args, complain | tf_decltype);
29097-
--cp_unevaluated_operand;
29099+
++cp_unevaluated_operand;
29100+
call = build_new_function_call (cands, &args,
29101+
complain | tf_decltype);
29102+
--cp_unevaluated_operand;
2909829103

29099-
if (elided)
29100-
inform (input_location, "explicit deduction guides not considered "
29101-
"for copy-initialization");
29104+
if (elided)
29105+
inform (input_location, "explicit deduction guides not considered "
29106+
"for copy-initialization");
29107+
}
29108+
return error_mark_node;
29109+
}
29110+
/* [over.match.list]/1: In copy-list-initialization, if an explicit
29111+
constructor is chosen, the initialization is ill-formed. */
29112+
else if (flags & LOOKUP_ONLYCONVERTING)
29113+
{
29114+
tree fndecl = cp_get_callee_fndecl_nofold (call);
29115+
if (fndecl && DECL_NONCONVERTING_P (fndecl))
29116+
{
29117+
if (complain & tf_warning_or_error)
29118+
{
29119+
// TODO: Pass down location from cp_finish_decl.
29120+
error ("class template argument deduction for %qT failed: "
29121+
"explicit deduction guide selected in "
29122+
"copy-list-initialization", type);
29123+
inform (DECL_SOURCE_LOCATION (fndecl),
29124+
"explicit deduction guide declared here");
29125+
29126+
}
29127+
return error_mark_node;
29128+
}
2910229129
}
2910329130

2910429131
/* If CTAD succeeded but the type doesn't have any explicit deduction
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// PR c++/90210
2+
// { dg-do compile { target c++17 } }
3+
4+
template<typename T> struct tuple { tuple(T); };
5+
template<typename T> explicit tuple(T t) -> tuple<T>;
6+
tuple t = { 1 }; // { dg-error "explicit deduction guide selected" }
7+
tuple t1 = tuple{ 1 };
8+
tuple t2{ 1 };
9+
10+
template<typename T> struct A { A(T, T); };
11+
template<typename T> explicit A(T, T) -> A<int>;
12+
A a = {1, 1}; // { dg-error "explicit deduction guide selected" }
13+
A a1 = A{1, 1};
14+
A a2{1, 1};
15+
16+
template<typename T, typename U>
17+
struct B {
18+
B(T, U);
19+
};
20+
template<typename T, typename U>
21+
B(T, U) -> B<T, typename U::type>; // SFINAEd-out
22+
B b = { 1, 2 }; // OK
23+
B b1 = B{ 1, 2 }; // OK
24+
B b2{ 1, 2 }; // OK
25+
26+
// Overriden implicit default constructor deduction guide:
27+
template<typename T>
28+
struct C { };
29+
explicit C() -> C<int>;
30+
C c = {}; // { dg-error "explicit deduction guide selected" }
31+
C c1 = C{};
32+
C c2{};
33+
34+
// Overriden copy guide:
35+
template<typename T>
36+
struct D { };
37+
template<typename T> explicit D(D<T>) -> D<T>;
38+
D<int> d;
39+
D d1 = {d}; // { dg-error "explicit deduction guide selected" }
40+
D d2 = D{d};
41+
D d3{d};

0 commit comments

Comments
 (0)