c++: CTAD from initializer list [PR106366]

During CTAD, we currently perform the first phase of overload resolution
from [over.match.list] only if the class template has a list constructor.
But according to [over.match.class.deduct]/4 it should be enough to just
have a guide that looks like a list constructor (which is a more general
criterion in light of user-defined guides).

	PR c++/106366

gcc/cp/ChangeLog:

	* pt.cc (do_class_deduction): Don't consider TYPE_HAS_LIST_CTOR
	when setting try_list_ctor.  Reset args even when try_list_ctor
	is true and there are no list candidates.  Call resolve_args on
	the reset args.  Rename try_list_ctor to try_list_cand.

gcc/testsuite/ChangeLog:

	* g++.dg/cpp1z/class-deduction112.C: New test.
This commit is contained in:
Patrick Palka 2022-07-22 18:42:02 -04:00
parent b585af38a1
commit f77bbc8f86
2 changed files with 29 additions and 16 deletions

View file

@ -30240,7 +30240,7 @@ do_class_deduction (tree ptype, tree tmpl, tree init,
tree type = TREE_TYPE (tmpl);
bool try_list_ctor = false;
bool try_list_cand = false;
bool list_init_p = false;
releasing_vec rv_args = NULL;
@ -30250,8 +30250,8 @@ do_class_deduction (tree ptype, tree tmpl, tree init,
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
try_list_cand = true;
if (CONSTRUCTOR_NELTS (init) == 1
&& !CONSTRUCTOR_IS_DESIGNATED_INIT (init))
{
/* As an exception, the first phase in 16.3.1.7 (considering the
@ -30261,9 +30261,9 @@ do_class_deduction (tree ptype, tree tmpl, tree init,
specialization of C. */
tree elt = CONSTRUCTOR_ELT (init, 0)->value;
if (is_spec_or_derived (TREE_TYPE (elt), tmpl))
try_list_ctor = false;
try_list_cand = false;
}
if (try_list_ctor || is_std_init_list (type))
if (try_list_cand || is_std_init_list (type))
args = make_tree_vector_single (init);
else
args = make_tree_vector_from_ctor (init);
@ -30310,26 +30310,25 @@ do_class_deduction (tree ptype, tree tmpl, tree init,
tree fndecl = error_mark_node;
/* If this is list-initialization and the class has a list constructor, first
/* If this is list-initialization and the class has a list guide, first
try deducing from the list as a single argument, as [over.match.list]. */
tree list_cands = NULL_TREE;
if (try_list_ctor && cands)
for (lkp_iterator iter (cands); iter; ++iter)
{
tree dg = *iter;
if (try_list_cand)
{
tree list_cands = NULL_TREE;
for (tree dg : lkp_range (cands))
if (is_list_ctor (dg))
list_cands = lookup_add (dg, list_cands);
}
if (list_cands)
{
fndecl = perform_dguide_overload_resolution (list_cands, args, tf_none);
if (list_cands)
fndecl = perform_dguide_overload_resolution (list_cands, args, tf_none);
if (fndecl == error_mark_node)
{
/* That didn't work, now try treating the list as a sequence of
arguments. */
release_tree_vector (args);
args = make_tree_vector_from_ctor (init);
args = resolve_args (args, complain);
if (args == NULL)
return error_mark_node;
}
}

View file

@ -0,0 +1,14 @@
// PR c++/106366
// { dg-do compile { target c++17 } }
#include <initializer_list>
template<class T>
struct A { A(...); };
template<typename T>
A(std::initializer_list<T>) -> A<T>;
A a{1,2,3};
using type = decltype(a);
using type = A<int>;