On 6/24/21 4:45 PM, Patrick Palka wrote:
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.
This makes sense, but what happens if SpanType is a member template, so
that the levels of it and ConstSpanType don't match? Or the other way
around?
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;