On 3/1/21 2:54 PM, Marek Polacek wrote:
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.

Yeah, I was only thinking to use the pattern for the aggregate check.

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.

It looks fine to me.

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.

Sure, because E<1>::G<T> has been partially instantiated, so the T has been reduced from level 2 to 1.

You'll need to do a similar partial instantiation for building the deduction guide, either as part of the deduction guide rewriting or on the constructor before rewriting.

It might also work to do something tricky like giving the E template parameter a default argument of 1, but that seems like it would need more invention.

Jason

Reply via email to