In the first testcase below, during parsing of the alias template ConstSpanType, transparency of alias template specializations means we replace SpanType<T> with SpanType's substituted definition. But this substitution lowers the level of the CTAD placeholder for span(T()) from 2 to 1, and so the later instantiantion of ConstSpanType<int> erroneously substitutes this CTAD placeholder with the template argument at level 1 index 0, i.e. with int, before we get a chance to perform the CTAD.
In light of this, it seems we should avoid level lowering when substituting through through the type-id of a dependent alias template specialization. To that end this patch makes lookup_template_class_1 pass tf_partial to tsubst in this situation. Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for trunk? PR c++/91911 gcc/cp/ChangeLog: * pt.c (lookup_template_class_1): When looking up a dependent alias template specialization, pass tf_partial to tsubst. gcc/testsuite/ChangeLog: * g++.dg/cpp1z/class-deduction92.C: New test. --- gcc/cp/pt.c | 7 +++++- .../g++.dg/cpp1z/class-deduction92.C | 17 +++++++++++++ .../g++.dg/cpp1z/class-deduction93.C | 25 +++++++++++++++++++ 3 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/g++.dg/cpp1z/class-deduction92.C create mode 100644 gcc/testsuite/g++.dg/cpp1z/class-deduction93.C diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index f73c7471a33..23c5f515716 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -9954,7 +9954,12 @@ lookup_template_class_1 (tree d1, tree arglist, tree in_decl, tree context, template-arguments for the template-parameters in the type-id of the alias template. */ - t = tsubst (TREE_TYPE (gen_tmpl), arglist, complain, in_decl); + /* When substituting a dependent alias template specialization, + we pass tf_partial to avoid lowering the level of any 'auto' + in its type-id which might correspond to CTAD placeholders. */ + t = tsubst (TREE_TYPE (gen_tmpl), arglist, + complain | (is_dependent_type * tf_partial), + in_decl); /* Note that the call above (by indirectly calling register_specialization in tsubst_decl) registers the TYPE_DECL representing the specialization of the alias diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction92.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction92.C new file mode 100644 index 00000000000..ae3c55508b2 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction92.C @@ -0,0 +1,17 @@ +// PR c++/91911 +// { dg-do compile { target c++17 } } + +template<class T> +struct span { + using value_type = T; + span(T); +}; + +template<class T> +using SpanType = decltype(span(T())); + +template<class T> +using ConstSpanType = span<const typename SpanType<T>::value_type>; + +using type = ConstSpanType<int>; +using type = span<const int>; diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction93.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction93.C new file mode 100644 index 00000000000..eebc986832e --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction93.C @@ -0,0 +1,25 @@ +// PR c++/98077 +// { dg-do compile { target c++17 } } + +template<class R> +struct function { + template<class T> function(T) { } + using type = R; +}; + +template<class T> function(T) -> function<decltype(T()())>; + +template<class T> +struct CallableTrait; + +template<class R> +struct CallableTrait<function<R>> { using ReturnType = R; }; + +template<class F> +using CallableTraitT = decltype(function{F()}); + +template<class F> +using ReturnType = typename CallableTraitT<F>::type; + +using type = ReturnType<int(*)()>; +using type = int; -- 2.32.0.93.g670b81a890