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). :/ > 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