On 3/1/21 7:59 PM, Marek Polacek wrote:
On Mon, Mar 01, 2021 at 03:08:58PM -0500, Jason Merrill wrote:
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.
Ack. Though I think I also have to use the pattern here:
init = reshape_init (type, init, complain);
otherwise reshape_init returns a TARGET_EXPR and we immediately
crash in collect_ctor_idx_types because that only expects a CONSTRUCTOR.
And what we need to get is the type T -- of the constructor's index.
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.
Right.
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.
So I've tried. I can't actually tsubst the constructor itself, because it
at this point contains an AGGR_INIT_EXPR, which tsubst* can't handle. But
what I could do is
parms = tsubst (parms, DECL_TI_ARGS (tmpl), complain, init);
just after the call to collect_ctor_idx_types. After all, this is what
we care about and create the function template parameters from. So now
T's level is reduced to 1, and the guide we create is
template<class T> G(T)-> E<1>::G<T>
This guide is then chosen in do_class_deduction -> build_new_function_call,
but we crash in fn_type_unification -> instantiate_template (after we've
deduced T to N::S<char, int>) in retrieve_specialization:
gcc_assert (TMPL_ARGS_DEPTH (args)
== (TREE_CODE (tmpl) == TEMPLATE_DECL
? TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (tmpl))
: template_class_depth (DECL_CONTEXT (tmpl))));
args is <1, S> (depth 2), tmpl is our deduction guide, and
DECL_TEMPLATE_PARMS (tmpl) is [1 T] (depth 1).
I'd think args should only be S (depth 1).
:/
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.
I haven't tried this, but I'm not sure if it'd avoid the problem above.
Marek