Ping. On Sat, Sep 19, 2020 at 05:33:36PM -0400, Marek Polacek via Gcc-patches wrote: > 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++. > > Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk? > > 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. > --- > gcc/cp/pt.c | 49 ++++++++++++++----- > .../g++.dg/cpp1z/class-deduction73.C | 41 ++++++++++++++++ > 2 files changed, 79 insertions(+), 11 deletions(-) > create mode 100644 gcc/testsuite/g++.dg/cpp1z/class-deduction73.C > > diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c > index cfe5ff4a94f..9bcb743dc1d 100644 > --- a/gcc/cp/pt.c > +++ b/gcc/cp/pt.c > @@ -28929,6 +28929,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; > @@ -28936,6 +28937,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) > { > @@ -28967,9 +28969,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))) > @@ -29038,18 +29041,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; > + } > } > > return cp_build_qualified_type (TREE_TYPE (call), cp_type_quals (ptype)); > diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction73.C > b/gcc/testsuite/g++.dg/cpp1z/class-deduction73.C > new file mode 100644 > index 00000000000..b37ddedd1bf > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction73.C > @@ -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}; > > base-commit: 4a5ff2b56bfea0b3e154a15e809c5c42dc3b9e9f > -- > 2.26.2 >
Marek