public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r12-7857] c++: hash table ICE with variadic alias [PR105003]
@ 2022-03-28 15:04 Jason Merrill
  0 siblings, 0 replies; only message in thread
From: Jason Merrill @ 2022-03-28 15:04 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:fc50d9a252c89c1bac78192bd0884ff23f2bf48b

commit r12-7857-gfc50d9a252c89c1bac78192bd0884ff23f2bf48b
Author: Jason Merrill <jason@redhat.com>
Date:   Fri Mar 25 13:13:35 2022 -0400

    c++: hash table ICE with variadic alias [PR105003]
    
    For PR104008 we thought it might be enough to keep strip_typedefs from
    removing this alias template specialization, but this PR demonstrates that
    other parts of the compiler also need to know to consider it dependent.
    
    So, this patch changes complex_alias_template_p to no longer consider
    template parameters used when their only use appears in a pack expansion,
    unless they are the parameter packs being expanded.
    
    To do that I also needed to change it to use cp_walk_tree instead of
    for_each_template_parm.  It occurs to me that find_template_parameters
    should probably also use cp_walk_tree, but I'm not messing with that now.
    
            PR c++/105003
            PR c++/104008
            PR c++/102869
    
    gcc/cp/ChangeLog:
    
            * pt.cc (complex_alias_template_r): walk_tree callback, replacing
            uses_all_template_parms_r, complex_pack_expansion_r.
            (complex_alias_template_p): Adjust.
            * tree.cc (strip_typedefs): Revert r12-7710 change.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/cpp0x/variadic-alias6.C: New test.
            * g++.dg/cpp0x/variadic-alias7.C: New test.

Diff:
---
 gcc/cp/pt.cc                                 | 72 ++++++++++++++++++----------
 gcc/cp/tree.cc                               | 13 +----
 gcc/testsuite/g++.dg/cpp0x/variadic-alias6.C | 20 ++++++++
 gcc/testsuite/g++.dg/cpp0x/variadic-alias7.C | 16 +++++++
 4 files changed, 85 insertions(+), 36 deletions(-)

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 678063f6e4c..3df509bbed0 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -6460,10 +6460,7 @@ alias_template_specialization_p (const_tree t,
   return NULL_TREE;
 }
 
-/* An alias template is complex from a SFINAE perspective if a template-id
-   using that alias can be ill-formed when the expansion is not, as with
-   the void_t template.  We determine this by checking whether the
-   expansion for the alias template uses all its template parameters.  */
+/* Data structure for complex_alias_template_*.  */
 
 struct uses_all_template_parms_data
 {
@@ -6471,31 +6468,36 @@ struct uses_all_template_parms_data
   bool *seen;
 };
 
-static int
-uses_all_template_parms_r (tree t, void *data_)
+/* walk_tree callback for complex_alias_template_p.  */
+
+static tree
+complex_alias_template_r (tree *tp, int *walk_subtrees, void *data_)
 {
-  struct uses_all_template_parms_data &data
-    = *(struct uses_all_template_parms_data*)data_;
-  tree idx = get_template_parm_index (t);
+  tree t = *tp;
+  auto &data = *(struct uses_all_template_parms_data*)data_;
 
-  if (TEMPLATE_PARM_LEVEL (idx) == data.level)
-    data.seen[TEMPLATE_PARM_IDX (idx)] = true;
-  return 0;
-}
+  switch (TREE_CODE (t))
+    {
+    case TEMPLATE_TYPE_PARM:
+    case TEMPLATE_PARM_INDEX:
+    case TEMPLATE_TEMPLATE_PARM:
+    case BOUND_TEMPLATE_TEMPLATE_PARM:
+      {
+	tree idx = get_template_parm_index (t);
+	if (TEMPLATE_PARM_LEVEL (idx) == data.level)
+	  data.seen[TEMPLATE_PARM_IDX (idx)] = true;
+      }
 
-/* for_each_template_parm any_fn callback for complex_alias_template_p.  */
+    default:;
+    }
+
+  if (!PACK_EXPANSION_P (t))
+    return 0;
 
-static int
-complex_pack_expansion_r (tree t, void *data_)
-{
   /* An alias template with a pack expansion that expands a pack from the
      enclosing class needs to be considered complex, to avoid confusion with
      the same pack being used as an argument to the alias's own template
      parameter (91966).  */
-  if (!PACK_EXPANSION_P (t))
-    return 0;
-  struct uses_all_template_parms_data &data
-    = *(struct uses_all_template_parms_data*)data_;
   for (tree pack = PACK_EXPANSION_PARAMETER_PACKS (t); pack;
        pack = TREE_CHAIN (pack))
     {
@@ -6505,11 +6507,34 @@ complex_pack_expansion_r (tree t, void *data_)
       int idx, level;
       template_parm_level_and_index (parm_pack, &level, &idx);
       if (level < data.level)
-	return 1;
+	return t;
+
+      /* Consider the expanded packs to be used outside the expansion...  */
+      data.seen[idx] = true;
     }
+
+  /* ...but don't walk into the pattern.  Consider PR104008:
+
+     template <typename T, typename... Ts>
+     using IsOneOf = disjunction<is_same<T, Ts>...>;
+
+     where IsOneOf seemingly uses all of its template parameters in its
+     expansion (and does not expand a pack from the enclosing class), so the
+     alias was not marked as complex.  However, if it is used like
+     "IsOneOf<T>", the empty pack for Ts means that T no longer appears in the
+     expansion.  So only Ts is considered used by the pack expansion.  */
+  *walk_subtrees = false;
+
   return 0;
 }
 
+/* An alias template is complex from a SFINAE perspective if a template-id
+   using that alias can be ill-formed when the expansion is not, as with
+   the void_t template.
+
+   Returns 1 if always complex, 0 if not complex, -1 if complex iff any of the
+   template arguments are empty packs.  */
+
 static bool
 complex_alias_template_p (const_tree tmpl)
 {
@@ -6530,8 +6555,7 @@ complex_alias_template_p (const_tree tmpl)
   for (int i = 0; i < len; ++i)
     data.seen[i] = false;
 
-  if (for_each_template_parm (pat, uses_all_template_parms_r, &data,
-			      NULL, true, complex_pack_expansion_r))
+  if (cp_walk_tree_without_duplicates (&pat, complex_alias_template_r, &data))
     return true;
   for (int i = 0; i < len; ++i)
     if (!data.seen[i])
diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index 492921721f2..780a8d89165 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -1778,18 +1778,7 @@ strip_typedefs (tree t, bool *remove_attributes, unsigned int flags)
 	if (TYPE_P (pat))
 	  {
 	    type = strip_typedefs (pat, remove_attributes, flags);
-	    /* Empty packs can thwart our efforts here.  Consider
-
-		template <typename T, typename... Ts>
-		using IsOneOf = disjunction<is_same<T, Ts>...>;
-
-	      where IsOneOf seemingly uses all of its template parameters in
-	      its expansion (and does not expand a pack from the enclosing
-	      class), so the alias is not marked as complex.  However, it may
-	      be used as in "IsOneOf<Ts>", where Ts is an empty parameter pack,
-	      and stripping it down into "disjunction<>" here would exclude the
-	      Ts pack, resulting in an error.  */
-	    if (type != pat && uses_parameter_packs (type))
+	    if (type != pat)
 	      {
 		result = build_distinct_type_copy (t);
 		PACK_EXPANSION_PATTERN (result) = type;
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic-alias6.C b/gcc/testsuite/g++.dg/cpp0x/variadic-alias6.C
new file mode 100644
index 00000000000..c095bc537d7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic-alias6.C
@@ -0,0 +1,20 @@
+// PR c++/105003
+// { dg-do compile { target c++11 } }
+
+template <class T> struct A;
+template <class T, class U> struct B { };
+template <class... Ts> struct C { };
+
+// Fn is not complex, since T is used outside the pack expansion, so the two
+// partial specializations are equivalent.
+template <class T, class... Ts> using Fn = T(Ts...);
+template <class T, class... Ts> struct A<Fn<T,Ts...>*> { };
+template <class T, class... Ts> struct A<T(*)(Ts...)> { }; // { dg-error "redefinition" }
+
+// CB is complex, since T is only used in the pack expansion, so the two
+// partial specializations are functionally equivalent but not equivalent.
+template <class T, class ...Ts> using CB = C<B<T,Ts>...>;
+template <class T, class ...Ts> struct A<CB<T,Ts...>*> { };
+template <class T, class ...Ts> struct A<C<B<T,Ts>...>*> { }; // IFNDR
+A<C<B<int,int>>*> a;		// { dg-error "ambiguous" }
+// { dg-prune-output "incomplete" }
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic-alias7.C b/gcc/testsuite/g++.dg/cpp0x/variadic-alias7.C
new file mode 100644
index 00000000000..41a432a8e41
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic-alias7.C
@@ -0,0 +1,16 @@
+// PR c++/102869
+// { dg-do compile { target c++11 } }
+
+template<int...> struct integer_sequence;
+
+template<int _Num>
+using make_index_sequence = integer_sequence<__integer_pack(_Num)...>;
+
+template<class...> struct Tuple;
+
+template<int... Is> using tuple_t = Tuple<make_index_sequence<Is>...>;
+
+template<int... Is>
+void f() {
+  tuple_t<Is...> t;
+}


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

only message in thread, other threads:[~2022-03-28 15:04 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-03-28 15:04 [gcc r12-7857] c++: hash table ICE with variadic alias [PR105003] Jason Merrill

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