On Thu, Feb 25, 2021 at 10:45:29PM -0500, Jason Merrill via Gcc-patches wrote:
> On 2/25/21 5:41 PM, Marek Polacek wrote:
> > On Thu, Feb 25, 2021 at 10:59:49AM -0500, Jason Merrill wrote:
> > > On 2/12/21 6:12 PM, Marek Polacek wrote:
> > > > We represent deduction guides with FUNCTION_DECLs, but they are built
> > > > without DECL_CONTEXT
> > > 
> > > Hmm, that seems wrong: "A deduction-guide shall be declared in the
> > > same scope as the corresponding class template and, for a member class
> > > template, with the same access."  But it probably isn't necessary to 
> > > change
> > > this:
> > > 
> > > > leading to an ICE in type_dependent_expression_p
> > > > on the assert that the type of a function template with no dependent
> > > > (innermost!) template arguments must be non-dependent.  Consider the
> > > > attached class-deduction79.C: we create a deduction guide:
> > > > 
> > > >     template<class T> G(T)-> E<Z>::G<T>
> > > > 
> > > > we deduce T and create a partial instantiation:
> > > > 
> > > >     G(T) -> E<Z>::G<T> [with T = int]
> > > > 
> > > > And then do_class_deduction wants to create a CALL_EXPR from the above
> > > > using build_new_function_call -> build_over_call which calls mark_used
> > > > -> maybe_instantiate_noexcept -> type_dependent_expression_p.
> > > > 
> > > > There, the innermost template arguments are non-dependent (<int>), but
> > > > the fntype is dependent -- the return type is a TYPENAME_TYPE, and
> > > > since we have no DECL_CONTEXT, this check holds:
> > > > 
> > > >     /* Otherwise, if the function decl isn't from a dependent scope, it 
> > > > can't be
> > > >        type-dependent.  Checking this is important for functions with 
> > > > auto return
> > > >        type, which looks like a dependent type.  */
> > > >     if (TREE_CODE (expression) == FUNCTION_DECL
> > > >         && !(DECL_CLASS_SCOPE_P (expression)
> > > >              && dependent_type_p (DECL_CONTEXT (expression)))
> > > > 
> > > > whereupon we ICE.
> > > > 
> > > > Experiments with setting DECL_CONTEXT didn't pan out.
> > > 
> > > In c8 of the PR it looks like you were using the class itself as
> > > DECL_CONTEXT; the quote above says that the right context is the enclosing
> > > scope of the class.
> > 
> > Sadly, using CP_TYPE_CONTEXT (type) would result in a crash in
> > retrieve_specialization:
> > 
> >    /* There should be as many levels of arguments as there are
> >       levels of parameters.  */
> >    gcc_assert (TMPL_ARGS_DEPTH (args)
> >                == (TREE_CODE (tmpl) == TEMPLATE_DECL
> >                    ? TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (tmpl))
> >                    : template_class_depth (DECL_CONTEXT (tmpl))));
> 
> Yeah, probably simpler not to bother.
> 
> > > > So perhaps we
> > > > just want to skip the assert for deduction guides, because they are
> > > > a little special.  Better ideas solicited.
> > > 
> > > In c3 you mention that one of the variants broke with r269093; this is
> > > because my change to check CLASSTYPE_TEMPLATE_INSTANTIATION is false for 
> > > the
> > > template pattern itself (E<Z>).
> > 
> > And the original test started with my r11-1713 because using TREE_TYPE
> > directly instead of decltype (which is a non-deduced context) means we
> > can deduced from the argument.
> > > But I think probably the right answer is to defer this deduction until the
> > > enclosing scope is non-dependent, i.e. (untested)
> > 
> > Thanks.  That mostly works, except the new class-deduction-aggr[89].C
> > tests.  Consider 8:
> > 
> > namespace N {
> > template <typename, typename> struct S {
> >    template <typename T, typename U> S(T, U);
> > };
> > } // namespace N
> > template <int> struct E {
> >    template <typename T> struct G { T t; };
> >    void fn() { G{N::S<char, int>{'a', 1}}; }
> > };
> > 
> > void
> > g ()
> > {
> >    E<1> e;
> >    e.fn ();
> > }
> > 
> > With your patch, when in do_class_deduction when processing_template_decl,
> > we just return.  When we call do_class_deduction again when p_t_d is 0,
> > maybe_aggr_guide returns early here:
> > 
> >    if (!CP_AGGREGATE_TYPE_P (type))
> >      return NULL_TREE
> > 
> > because G is not complete (and rightly so, we didn't instantiate it).  So
> > we aren't able to deduce the template parameters.  I'm not sure if I should
> > pursue this direction further.  :(
> 
> I think so; we just need to test CP_AGGREGATE_TYPE_P on the original
> template pattern instead of the instantiation E<1>::G.

I'm sorry, I've got stuck again.

Yes, using the original template pattern helps us get past the
CP_AGGREGATE_TYPE_P check.

However, using TREE_TYPE (DECL_TI_TEMPLATE (tmpl)) as the type of the deduction 
guide
means the guide will be "template<class T> G(T)-> E<<anonymous> >::G<T>" which
results in

  class-deduction-aggr8.C:11:15: error: invalid use of dependent type 'typename 
E<<anonymous> >::G<N::S<char, int> >'

which makes sense I guess: when we defer building up the guide until
we've instantiated E<1>, finding the dependent type E<> is not expected.

But creating the guide with "struct E<1>::G<T>" as its type seems
wrong; I'm not even sure if a guide like

  template<class T> G(T)-> E<1>::G<T>

makes sense.  In any case the deduction fails (when we call
build_new_function_call in do_class_deduction), because we've got
a mismatch: the template parameter T has level 1, but the template
function parameter has level 2.

Marek

Reply via email to