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>; // #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 (#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.
This commit is contained in:
parent
660bfe61d4
commit
cf7dae0173
49
gcc/cp/pt.c
49
gcc/cp/pt.c
|
@ -28977,6 +28977,7 @@ do_class_deduction (tree ptype, tree tmpl, tree init,
|
|||
tree type = TREE_TYPE (tmpl);
|
||||
|
||||
bool try_list_ctor = false;
|
||||
bool list_init_p = false;
|
||||
|
||||
releasing_vec rv_args = NULL;
|
||||
vec<tree,va_gc> *&args = *&rv_args;
|
||||
|
@ -28984,6 +28985,7 @@ do_class_deduction (tree ptype, tree tmpl, tree init,
|
|||
args = make_tree_vector ();
|
||||
else if (BRACE_ENCLOSED_INITIALIZER_P (init))
|
||||
{
|
||||
list_init_p = true;
|
||||
try_list_ctor = TYPE_HAS_LIST_CTOR (type);
|
||||
if (try_list_ctor && CONSTRUCTOR_NELTS (init) == 1)
|
||||
{
|
||||
|
@ -29016,9 +29018,10 @@ do_class_deduction (tree ptype, tree tmpl, tree init,
|
|||
if (cands == error_mark_node)
|
||||
return error_mark_node;
|
||||
|
||||
/* Prune explicit deduction guides in copy-initialization context. */
|
||||
/* Prune explicit deduction guides in copy-initialization context (but
|
||||
not copy-list-initialization). */
|
||||
bool elided = false;
|
||||
if (flags & LOOKUP_ONLYCONVERTING)
|
||||
if (!list_init_p && (flags & LOOKUP_ONLYCONVERTING))
|
||||
{
|
||||
for (lkp_iterator iter (cands); !elided && iter; ++iter)
|
||||
if (DECL_NONCONVERTING_P (STRIP_TEMPLATE (*iter)))
|
||||
|
@ -29087,18 +29090,42 @@ do_class_deduction (tree ptype, tree tmpl, tree init,
|
|||
--cp_unevaluated_operand;
|
||||
}
|
||||
|
||||
if (call == error_mark_node
|
||||
&& (complain & tf_warning_or_error))
|
||||
if (call == error_mark_node)
|
||||
{
|
||||
error ("class template argument deduction failed:");
|
||||
if (complain & tf_warning_or_error)
|
||||
{
|
||||
error ("class template argument deduction failed:");
|
||||
|
||||
++cp_unevaluated_operand;
|
||||
call = build_new_function_call (cands, &args, complain | tf_decltype);
|
||||
--cp_unevaluated_operand;
|
||||
++cp_unevaluated_operand;
|
||||
call = build_new_function_call (cands, &args,
|
||||
complain | tf_decltype);
|
||||
--cp_unevaluated_operand;
|
||||
|
||||
if (elided)
|
||||
inform (input_location, "explicit deduction guides not considered "
|
||||
"for copy-initialization");
|
||||
if (elided)
|
||||
inform (input_location, "explicit deduction guides not considered "
|
||||
"for copy-initialization");
|
||||
}
|
||||
return error_mark_node;
|
||||
}
|
||||
/* [over.match.list]/1: In copy-list-initialization, if an explicit
|
||||
constructor is chosen, the initialization is ill-formed. */
|
||||
else if (flags & LOOKUP_ONLYCONVERTING)
|
||||
{
|
||||
tree fndecl = cp_get_callee_fndecl_nofold (call);
|
||||
if (fndecl && DECL_NONCONVERTING_P (fndecl))
|
||||
{
|
||||
if (complain & tf_warning_or_error)
|
||||
{
|
||||
// TODO: Pass down location from cp_finish_decl.
|
||||
error ("class template argument deduction for %qT failed: "
|
||||
"explicit deduction guide selected in "
|
||||
"copy-list-initialization", type);
|
||||
inform (DECL_SOURCE_LOCATION (fndecl),
|
||||
"explicit deduction guide declared here");
|
||||
|
||||
}
|
||||
return error_mark_node;
|
||||
}
|
||||
}
|
||||
|
||||
/* If CTAD succeeded but the type doesn't have any explicit deduction
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
// PR c++/90210
|
||||
// { dg-do compile { target c++17 } }
|
||||
|
||||
template<typename T> struct tuple { tuple(T); };
|
||||
template<typename T> explicit tuple(T t) -> tuple<T>;
|
||||
tuple t = { 1 }; // { dg-error "explicit deduction guide selected" }
|
||||
tuple t1 = tuple{ 1 };
|
||||
tuple t2{ 1 };
|
||||
|
||||
template<typename T> struct A { A(T, T); };
|
||||
template<typename T> explicit A(T, T) -> A<int>;
|
||||
A a = {1, 1}; // { dg-error "explicit deduction guide selected" }
|
||||
A a1 = A{1, 1};
|
||||
A a2{1, 1};
|
||||
|
||||
template<typename T, typename U>
|
||||
struct B {
|
||||
B(T, U);
|
||||
};
|
||||
template<typename T, typename U>
|
||||
B(T, U) -> B<T, typename U::type>; // SFINAEd-out
|
||||
B b = { 1, 2 }; // OK
|
||||
B b1 = B{ 1, 2 }; // OK
|
||||
B b2{ 1, 2 }; // OK
|
||||
|
||||
// Overriden implicit default constructor deduction guide:
|
||||
template<typename T>
|
||||
struct C { };
|
||||
explicit C() -> C<int>;
|
||||
C c = {}; // { dg-error "explicit deduction guide selected" }
|
||||
C c1 = C{};
|
||||
C c2{};
|
||||
|
||||
// Overriden copy guide:
|
||||
template<typename T>
|
||||
struct D { };
|
||||
template<typename T> explicit D(D<T>) -> D<T>;
|
||||
D<int> d;
|
||||
D d1 = {d}; // { dg-error "explicit deduction guide selected" }
|
||||
D d2 = D{d};
|
||||
D d3{d};
|
Loading…
Reference in New Issue