]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: bound ttp level lowering [PR109531]
authorPatrick Palka <ppalka@redhat.com>
Mon, 17 Apr 2023 22:52:07 +0000 (18:52 -0400)
committerPatrick Palka <ppalka@redhat.com>
Mon, 17 Apr 2023 22:52:07 +0000 (18:52 -0400)
Here when level lowering the bound ttp TT<typename T::type> via the
substitution T=C, we're neglecting to canonicalize (and thereby strip
of simple typedefs) the substituted template arguments {A<int>} before
determining the new canonical type via hash table lookup.  This leads to
a hash mismatch ICE for the two equivalent types TT<int> and TT<A<int>>
since iterative_hash_template_arg assumes type arguments are already
canonicalized.

We can fix this by canonicalizing or coercing the substituted arguments
directly, but seeing as creation and ordinary substitution of bound ttps
both go through lookup_template_class, which in turn performs the desired
coercion/canonicalization, it seems preferable to make this code path go
through lookup_template_class as well.

PR c++/109531

gcc/cp/ChangeLog:

* pt.cc (tsubst) <case BOUND_TEMPLATE_TEMPLATE_PARM>:
In the level-lowering case just use lookup_template_class
to rebuild the bound ttp.

gcc/testsuite/ChangeLog:

* g++.dg/template/canon-type-20.C: New test.
* g++.dg/template/ttp36.C: New test.

gcc/cp/pt.cc
gcc/testsuite/g++.dg/template/canon-type-20.C [new file with mode: 0644]
gcc/testsuite/g++.dg/template/ttp36.C [new file with mode: 0644]

index fcc8e0d1d571ce4f8887d7b94d57afe8825534a2..e065ace5c55c64bc13e8c154dd0f6e8bf84578d4 100644 (file)
@@ -16232,7 +16232,6 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
          {
          case TEMPLATE_TYPE_PARM:
          case TEMPLATE_TEMPLATE_PARM:
-         case BOUND_TEMPLATE_TEMPLATE_PARM:
            if (cp_type_quals (t))
              {
                r = tsubst (TYPE_MAIN_VARIANT (t), args, complain, in_decl);
@@ -16274,24 +16273,6 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
                       only instantiated during satisfaction.  */
                    PLACEHOLDER_TYPE_CONSTRAINTS_INFO (r) = ci;
 
-               if (code == BOUND_TEMPLATE_TEMPLATE_PARM)
-                 {
-                   tree tinfo = TYPE_TEMPLATE_INFO (t);
-                   /* We might need to substitute into the types of non-type
-                      template parameters.  */
-                   tree tmpl = tsubst (TI_TEMPLATE (tinfo), args,
-                                       complain, in_decl);
-                   if (tmpl == error_mark_node)
-                     return error_mark_node;
-                   tree argvec = tsubst (TI_ARGS (tinfo), args,
-                                         complain, in_decl);
-                   if (argvec == error_mark_node)
-                     return error_mark_node;
-
-                   TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO (r)
-                     = build_template_info (tmpl, argvec);
-                 }
-
                if (TYPE_STRUCTURAL_EQUALITY_P (t))
                  SET_TYPE_STRUCTURAL_EQUALITY (r);
                else
@@ -16299,6 +16280,26 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
              }
            break;
 
+         case BOUND_TEMPLATE_TEMPLATE_PARM:
+           {
+             tree tinfo = TYPE_TEMPLATE_INFO (t);
+             /* We might need to substitute into the types of non-type
+                template parameters.  This also lowers the level of
+                the ttp appropriately.  */
+             tree tmpl = tsubst (TI_TEMPLATE (tinfo), args,
+                                 complain, in_decl);
+             if (tmpl == error_mark_node)
+               return error_mark_node;
+             tree argvec = tsubst (TI_ARGS (tinfo), args,
+                                   complain, in_decl);
+             if (argvec == error_mark_node)
+               return error_mark_node;
+             r = lookup_template_class (tmpl, argvec, in_decl, NULL_TREE,
+                                        /*entering_scope=*/false, complain);
+             r = cp_build_qualified_type (r, cp_type_quals (t), complain);
+             break;
+           }
+
          case TEMPLATE_PARM_INDEX:
            /* OK, now substitute the type of the non-type parameter.  We
               couldn't do it earlier because it might be an auto parameter,
diff --git a/gcc/testsuite/g++.dg/template/canon-type-20.C b/gcc/testsuite/g++.dg/template/canon-type-20.C
new file mode 100644 (file)
index 0000000..211ca10
--- /dev/null
@@ -0,0 +1,18 @@
+// PR c++/109531
+// { dg-do compile { target c++11 } }
+// { dg-additional-options "--param=hash-table-verification-limit=1000" }
+
+template<class T>
+using A = int;
+
+struct B { using type = int; };
+struct C { using type = A<int>; };
+
+template<class T>
+struct D {
+  template<template<class> class TT>
+  TT<typename T::type> f();
+};
+
+template struct D<B>;
+template struct D<C>;
diff --git a/gcc/testsuite/g++.dg/template/ttp36.C b/gcc/testsuite/g++.dg/template/ttp36.C
new file mode 100644 (file)
index 0000000..c329bb4
--- /dev/null
@@ -0,0 +1,12 @@
+// Verify we propagate cv-quals when level-lowering a bound ttp.
+
+template<class T>
+struct B {
+  template<template<class> class TT>
+  void f(TT<T>*);
+
+  template<template<class> class TT>
+  void f(const TT<T>*); // { dg-bogus "cannot be overloaded" }
+};
+
+template struct B<int>;