aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorPatrick Palka <ppalka@redhat.com>2022-01-20 09:25:49 -0500
committerPatrick Palka <ppalka@redhat.com>2022-01-20 09:25:49 -0500
commit09845ad7569bac27c3a1dc7b410d9df764d2ca06 (patch)
tree0a10b62413a6a7f4ad8b225a71a84a0030617967 /gcc
parent2cda2bfa3fd0f2a0122433d2d870843633e2a312 (diff)
downloadgcc-09845ad7569bac27c3a1dc7b410d9df764d2ca06.zip
gcc-09845ad7569bac27c3a1dc7b410d9df764d2ca06.tar.gz
gcc-09845ad7569bac27c3a1dc7b410d9df764d2ca06.tar.bz2
c++: CTAD inside alias template [PR91911, PR103672]
In the first testcase below, when processing the alias template ConstSpanType, transparency of alias template specializations means we replace SpanType<T> with its instantiated definition. But this instantiation lowers the level of the CTAD placeholder for span{T()} from 2 to 1, and so the later instantiation 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. Although we represent CTAD placeholders as template parameters, we never actually want to replace them via tsubst. So this patch adjusts tsubst to handle CTAD placeholders by simply substituting the template and returning a new CTAD placeholder. Moreover, this means that the level of a CTAD placeholder doesn't matter, so we may as well give them all the same level. This patch gives them the special level 0. The change in tsubst_decl removes a likely dead !CHECKING_P safeguard added in 2017, which would otherwise now get triggered for variables with CTAD placeholder types (since their level is 0). PR c++/91911 PR c++/103672 gcc/cp/ChangeLog: * pt.cc (keep_template_parm): Punt on a level 0 template parm. (tsubst_decl) <case VAR_DECL>: Remove !CHECKING_P safeguard. (tsubst) <case TEMPLATE_TYPE_PARM>: Handle CTAD placeholders specially. (make_auto_1): Add defaulted 'level' parameter. (make_template_placeholder): Pass 0 as 'level' to make_auto_1. gcc/testsuite/ChangeLog: * g++.dg/cpp1z/class-deduction101.C: New test. * g++.dg/cpp1z/class-deduction101a.C: New test. * g++.dg/cpp1z/class-deduction101b.C: New test. * g++.dg/cpp1z/class-deduction102.C: New test. * g++.dg/cpp1z/class-deduction102a.C: New test. * g++.dg/cpp1z/class-deduction102b.C: New test. * g++.dg/cpp1z/class-deduction103.C: New test.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/pt.cc60
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/class-deduction101.C17
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/class-deduction101a.C22
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/class-deduction101b.C22
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/class-deduction102.C25
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/class-deduction102a.C27
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/class-deduction102b.C30
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/class-deduction103.C22
8 files changed, 191 insertions, 34 deletions
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 60bc35a..5afcb41 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -10660,7 +10660,7 @@ keep_template_parm (tree t, void* data)
int level;
int index;
template_parm_level_and_index (t, &level, &index);
- if (level > ftpi->max_depth)
+ if (level == 0 || level > ftpi->max_depth)
return 0;
if (TREE_CODE (t) == BOUND_TEMPLATE_TEMPLATE_PARM)
@@ -14799,20 +14799,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
&& VAR_HAD_UNKNOWN_BOUND (t)
&& type != error_mark_node)
type = strip_array_domain (type);
- tree sub_args = args;
- if (tree auto_node = type_uses_auto (type))
- {
- /* Mask off any template args past the variable's context so we
- don't replace the auto with an unrelated argument. */
- int nouter = TEMPLATE_TYPE_LEVEL (auto_node) - 1;
- int extra = TMPL_ARGS_DEPTH (args) - nouter;
- if (extra > 0)
- /* This should never happen with the new lambda instantiation
- model, but keep the handling just in case. */
- gcc_assert (!CHECKING_P),
- sub_args = strip_innermost_template_args (args, extra);
- }
- type = tsubst (type, sub_args, complain, in_decl);
+ type = tsubst (type, args, complain, in_decl);
/* Substituting the type might have recursively instantiated this
same alias (c++/86171). */
if (gen_tmpl && DECL_ALIAS_TEMPLATE_P (gen_tmpl)
@@ -15564,6 +15551,19 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
}
case TEMPLATE_TYPE_PARM:
+ if (template_placeholder_p (t))
+ {
+ tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (t);
+ tmpl = tsubst_copy (tmpl, args, complain, in_decl);
+ if (TREE_CODE (tmpl) == TEMPLATE_TEMPLATE_PARM)
+ tmpl = TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL (tmpl);
+
+ if (tmpl != CLASS_PLACEHOLDER_TEMPLATE (t))
+ return make_template_placeholder (tmpl);
+ else
+ return t;
+ }
+ /* Fall through. */
case TEMPLATE_TEMPLATE_PARM:
case BOUND_TEMPLATE_TEMPLATE_PARM:
case TEMPLATE_PARM_INDEX:
@@ -15737,7 +15737,6 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
of a constrained placeholder. */;
else if (TREE_CODE (t) == TEMPLATE_TYPE_PARM
&& !PLACEHOLDER_TYPE_CONSTRAINTS_INFO (t)
- && !CLASS_PLACEHOLDER_TEMPLATE (t)
&& (arg = TEMPLATE_TYPE_PARM_INDEX (t),
r = TEMPLATE_PARM_DESCENDANTS (arg))
&& (TEMPLATE_PARM_LEVEL (r)
@@ -15756,19 +15755,10 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
TYPE_REFERENCE_TO (r) = NULL_TREE;
if (TREE_CODE (t) == TEMPLATE_TYPE_PARM)
- {
+ if (tree ci = PLACEHOLDER_TYPE_CONSTRAINTS_INFO (t))
/* Propagate constraints on placeholders since they are
only instantiated during satisfaction. */
- if (tree ci = PLACEHOLDER_TYPE_CONSTRAINTS_INFO (t))
- PLACEHOLDER_TYPE_CONSTRAINTS_INFO (r) = ci;
- else if (tree pl = CLASS_PLACEHOLDER_TEMPLATE (t))
- {
- pl = tsubst_copy (pl, args, complain, in_decl);
- if (TREE_CODE (pl) == TEMPLATE_TEMPLATE_PARM)
- pl = TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL (pl);
- CLASS_PLACEHOLDER_TEMPLATE (r) = pl;
- }
- }
+ PLACEHOLDER_TYPE_CONSTRAINTS_INFO (r) = ci;
if (TREE_CODE (r) == TEMPLATE_TEMPLATE_PARM)
/* We have reduced the level of the template
@@ -28492,18 +28482,18 @@ make_args_non_dependent (vec<tree, va_gc> *args)
}
/* Returns a type which represents 'auto' or 'decltype(auto)'. We use a
- TEMPLATE_TYPE_PARM with a level one deeper than the actual template
- parms. If set_canonical is true, we set TYPE_CANONICAL on it. */
+ TEMPLATE_TYPE_PARM with a level one deeper than the actual template parms,
+ by default. If set_canonical is true, we set TYPE_CANONICAL on it. */
static tree
-make_auto_1 (tree name, bool set_canonical)
+make_auto_1 (tree name, bool set_canonical,
+ int level = current_template_depth + 1)
{
tree au = cxx_make_type (TEMPLATE_TYPE_PARM);
TYPE_NAME (au) = build_decl (input_location, TYPE_DECL, name, au);
TYPE_STUB_DECL (au) = TYPE_NAME (au);
TEMPLATE_TYPE_PARM_INDEX (au) = build_template_parm_index
- (0, current_template_depth + 1, current_template_depth + 1,
- TYPE_NAME (au), NULL_TREE);
+ (0, level, level, TYPE_NAME (au), NULL_TREE);
if (set_canonical)
TYPE_CANONICAL (au) = canonical_type_parameter (au);
DECL_ARTIFICIAL (TYPE_NAME (au)) = 1;
@@ -28526,12 +28516,14 @@ make_auto (void)
return make_auto_1 (auto_identifier, true);
}
-/* Return a C++17 deduction placeholder for class template TMPL. */
+/* Return a C++17 deduction placeholder for class template TMPL.
+ There are represented as an 'auto' with the special level 0 and
+ CLASS_PLACEHOLDER_TEMPLATE set. */
tree
make_template_placeholder (tree tmpl)
{
- tree t = make_auto_1 (auto_identifier, false);
+ tree t = make_auto_1 (auto_identifier, false, /*level=*/0);
CLASS_PLACEHOLDER_TEMPLATE (t) = tmpl;
/* Our canonical type depends on the placeholder. */
TYPE_CANONICAL (t) = canonical_type_parameter (t);
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction101.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction101.C
new file mode 100644
index 0000000..379eb96
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction101.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-deduction101a.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction101a.C
new file mode 100644
index 0000000..97869e6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction101a.C
@@ -0,0 +1,22 @@
+// PR c++/91911
+// { dg-do compile { target c++17 } }
+// A variant of class-deduction101.C where SpanType has more levels than
+// ConstSpanType.
+
+template<class T>
+struct span {
+ using value_type = T;
+ span(T);
+};
+
+template<class>
+struct A {
+ template<class T>
+ using SpanType = decltype(span{T()});
+};
+
+template<class T>
+using ConstSpanType = span<const typename A<int>::SpanType<const T>::value_type>;
+
+using type = ConstSpanType<int>;
+using type = span<const int>;
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction101b.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction101b.C
new file mode 100644
index 0000000..a823c9c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction101b.C
@@ -0,0 +1,22 @@
+// PR c++/91911
+// { dg-do compile { target c++17 } }
+// A variant of class-deduction101.C where SpanType has fewer levels than
+// ConstSpanType.
+
+template<class T>
+struct span {
+ using value_type = T;
+ span(T);
+};
+
+template<class T>
+using SpanType = decltype(span{T()});
+
+template<class>
+struct B {
+ template<class T>
+ using ConstSpanType = span<const typename SpanType<T>::value_type>;
+};
+
+using type = B<int>::ConstSpanType<int>;
+using type = span<const int>;
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction102.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction102.C
new file mode 100644
index 0000000..2050478
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction102.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 = CallableTrait<decltype(function{F()})>;
+
+template<class F>
+using ReturnType = typename CallableTraitT<F>::ReturnType;
+
+using type = ReturnType<int(*)()>;
+using type = int;
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction102a.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction102a.C
new file mode 100644
index 0000000..7a4b684
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction102a.C
@@ -0,0 +1,27 @@
+// PR c++/98077
+// { dg-do compile { target c++17 } }
+// A variant of class-deduction102.C where the template placeholder is a template
+// template parameter.
+
+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, template<class> class Tmpl>
+using CallableTraitT = CallableTrait<decltype(Tmpl{F()})>;
+
+template<class F, template<class> class Tmpl>
+using ReturnType = typename CallableTraitT<F, Tmpl>::ReturnType;
+
+using type = ReturnType<int(*)(), function>;
+using type = int;
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction102b.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction102b.C
new file mode 100644
index 0000000..64e3f8c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction102b.C
@@ -0,0 +1,30 @@
+// PR c++/98077
+// { dg-do compile { target c++17 } }
+// A variant of class-deduction102.C where the template placeholder is a template
+// template parameter and ReturnType has more levels than CallableTraitT.
+
+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, template<class> class Tmpl>
+using CallableTraitT = CallableTrait<decltype(Tmpl{F()})>;
+
+template<class>
+struct A {
+ template<class F, template<class> class Tmpl>
+ using ReturnType = typename CallableTraitT<F, Tmpl>::ReturnType;
+};
+
+using type = A<int>::ReturnType<int(*)(), function>;
+using type = int;
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction103.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction103.C
new file mode 100644
index 0000000..a1a3808
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction103.C
@@ -0,0 +1,22 @@
+// PR c++/103672
+// { dg-do compile { target c++17 } }
+
+template<class T>
+struct unique {
+ template<class... Args>
+ T* operator()(Args&&... args);
+};
+
+template<template<class...> class T, class... Args>
+using deduced_type = decltype(T{Args{}...});
+
+template<template<class> class F, template<class...> class T, class... Args>
+auto make(Args&&... args) {
+ return F<deduced_type<T, Args...>>{}(args...);
+}
+
+template<class A, class B>
+struct Foo { Foo(A,B); };
+
+using type = decltype(make<unique, Foo>(1, 2));
+using type = Foo<int, int>*;