public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r12-6773] c++: CTAD inside alias template [PR91911, PR103672]
@ 2022-01-20 14:26 Patrick Palka
  0 siblings, 0 replies; only message in thread
From: Patrick Palka @ 2022-01-20 14:26 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:09845ad7569bac27c3a1dc7b410d9df764d2ca06

commit r12-6773-g09845ad7569bac27c3a1dc7b410d9df764d2ca06
Author: Patrick Palka <ppalka@redhat.com>
Date:   Thu Jan 20 09:25:49 2022 -0500

    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.

Diff:
---
 gcc/cp/pt.cc                                     | 60 ++++++++++--------------
 gcc/testsuite/g++.dg/cpp1z/class-deduction101.C  | 17 +++++++
 gcc/testsuite/g++.dg/cpp1z/class-deduction101a.C | 22 +++++++++
 gcc/testsuite/g++.dg/cpp1z/class-deduction101b.C | 22 +++++++++
 gcc/testsuite/g++.dg/cpp1z/class-deduction102.C  | 25 ++++++++++
 gcc/testsuite/g++.dg/cpp1z/class-deduction102a.C | 27 +++++++++++
 gcc/testsuite/g++.dg/cpp1z/class-deduction102b.C | 30 ++++++++++++
 gcc/testsuite/g++.dg/cpp1z/class-deduction103.C  | 22 +++++++++
 8 files changed, 191 insertions(+), 34 deletions(-)

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 60bc35a8636..5afcb41eccd 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 00000000000..379eb960da6
--- /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 00000000000..97869e647cc
--- /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 00000000000..a823c9c3816
--- /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 00000000000..20504780d32
--- /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 00000000000..7a4b684b7cf
--- /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 00000000000..64e3f8c7ab0
--- /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 00000000000..a1a3808afdc
--- /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>*;


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2022-01-20 14:26 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-01-20 14:26 [gcc r12-6773] c++: CTAD inside alias template [PR91911, PR103672] Patrick Palka

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).