aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorPatrick Palka <ppalka@redhat.com>2024-02-01 13:17:48 -0500
committerPatrick Palka <ppalka@redhat.com>2024-02-01 13:17:48 -0500
commit3ba5be16a2be3eaedf2870ca1e25cfe826945948 (patch)
tree80ffe11525affcc16c60e4849b6cf8d88e467e44 /gcc
parenta886a90625a4ba5e1cc3270e69735cc4fe51f19c (diff)
downloadgcc-3ba5be16a2be3eaedf2870ca1e25cfe826945948.zip
gcc-3ba5be16a2be3eaedf2870ca1e25cfe826945948.tar.gz
gcc-3ba5be16a2be3eaedf2870ca1e25cfe826945948.tar.bz2
c++: ttp TEMPLATE_DECL equivalence [PR112737]
Here during declaration matching we undesirably consider the two TT{42} CTAD expressions to be non-equivalent ultimately because for CTAD placeholder equivalence we compare the TEMPLATE_DECLs via pointer identity, and here the corresponding TEMPLATE_DECLs for TT are different since they're from different scopes. On the other hand, the corresponding TEMPLATE_TEMPLATE_PARMs are deemed equivalent according to cp_tree_equal (since they have the same position and template parameters). This turns out to be the root cause of some of the xtreme-header modules regressions. So this patch relaxes ttp CTAD placeholder equivalence accordingly, by comparing the TEMPLATE_TEMPLATE_PARM instead of the TEMPLATE_DECL. It turns out this issue also affects function template-id equivalence as with g<TT> in the second testcase, so it makes sense to relax TEMPLATE_DECL equivalence more generally in cp_tree_equal. In passing this patch improves ctp_hasher::hash for CTAD placeholders, so that they don't all get the same hash. PR c++/112737 gcc/cp/ChangeLog: * pt.cc (iterative_hash_template_arg) <case TEMPLATE_DECL>: Adjust hashing to match cp_tree_equal. (ctp_hasher::hash): Also hash CLASS_PLACEHOLDER_TEMPLATE. * tree.cc (cp_tree_equal) <case TEMPLATE_DECL>: Return true for ttp TEMPLATE_DECLs if their TEMPLATE_TEMPLATE_PARMs are equivalent. * typeck.cc (structural_comptypes) <case TEMPLATE_TYPE_PARM>: Use cp_tree_equal to compare CLASS_PLACEHOLDER_TEMPLATE. gcc/testsuite/ChangeLog: * g++.dg/template/ttp42.C: New test. * g++.dg/template/ttp43.C: New test. Reviewed-by: Jason Merrill <jason@redhat.com>
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/pt.cc7
-rw-r--r--gcc/cp/tree.cc6
-rw-r--r--gcc/cp/typeck.cc4
-rw-r--r--gcc/testsuite/g++.dg/template/ttp42.C14
-rw-r--r--gcc/testsuite/g++.dg/template/ttp43.C17
5 files changed, 45 insertions, 3 deletions
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 5871cb6..16febb1 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -1816,6 +1816,11 @@ iterative_hash_template_arg (tree arg, hashval_t val)
}
return iterative_hash_template_arg (TREE_TYPE (arg), val);
+ case TEMPLATE_DECL:
+ if (DECL_TEMPLATE_TEMPLATE_PARM_P (arg))
+ return iterative_hash_template_arg (TREE_TYPE (arg), val);
+ break;
+
case TARGET_EXPR:
return iterative_hash_template_arg (TARGET_EXPR_INITIAL (arg), val);
@@ -4499,6 +4504,8 @@ struct ctp_hasher : ggc_ptr_hash<tree_node>
hashval_t val = iterative_hash_object (code, 0);
val = iterative_hash_object (TEMPLATE_TYPE_LEVEL (t), val);
val = iterative_hash_object (TEMPLATE_TYPE_IDX (t), val);
+ if (TREE_CODE (t) == TEMPLATE_TYPE_PARM)
+ val = iterative_hash_template_arg (CLASS_PLACEHOLDER_TEMPLATE (t), val);
if (TREE_CODE (t) == BOUND_TEMPLATE_TEMPLATE_PARM)
val = iterative_hash_template_arg (TYPE_TI_ARGS (t), val);
--comparing_specializations;
diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index 77f57e0..5c8c05d 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -4084,11 +4084,15 @@ cp_tree_equal (tree t1, tree t2)
}
return false;
+ case TEMPLATE_DECL:
+ if (DECL_TEMPLATE_TEMPLATE_PARM_P (t1)
+ && DECL_TEMPLATE_TEMPLATE_PARM_P (t2))
+ return cp_tree_equal (TREE_TYPE (t1), TREE_TYPE (t2));
+ /* Fall through. */
case VAR_DECL:
case CONST_DECL:
case FIELD_DECL:
case FUNCTION_DECL:
- case TEMPLATE_DECL:
case IDENTIFIER_NODE:
case SSA_NAME:
case USING_DECL:
diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
index 4937022..132c55c 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -1573,8 +1573,8 @@ structural_comptypes (tree t1, tree t2, int strict)
return false;
/* If T1 and T2 don't represent the same class template deduction,
they aren't equal. */
- if (CLASS_PLACEHOLDER_TEMPLATE (t1)
- != CLASS_PLACEHOLDER_TEMPLATE (t2))
+ if (!cp_tree_equal (CLASS_PLACEHOLDER_TEMPLATE (t1),
+ CLASS_PLACEHOLDER_TEMPLATE (t2)))
return false;
/* Constrained 'auto's are distinct from parms that don't have the same
constraints. */
diff --git a/gcc/testsuite/g++.dg/template/ttp42.C b/gcc/testsuite/g++.dg/template/ttp42.C
new file mode 100644
index 0000000..da08e85
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/ttp42.C
@@ -0,0 +1,14 @@
+// PR c++/112737
+// { dg-do compile { target c++17 } }
+
+template<template<class> class TT>
+decltype(TT{42}) f(); // #1
+
+template<template<class> class TT>
+decltype(TT{42}) f(); // redeclaration of #1
+
+template<class T> struct A { A(T); };
+
+int main() {
+ f<A>();
+}
diff --git a/gcc/testsuite/g++.dg/template/ttp43.C b/gcc/testsuite/g++.dg/template/ttp43.C
new file mode 100644
index 0000000..afafd32
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/ttp43.C
@@ -0,0 +1,17 @@
+// PR c++/112737
+// { dg-do compile { target c++11 } }
+
+template<template<class> class, class T>
+void g(T);
+
+template<template<class> class TT, class T>
+decltype(g<TT>(T{})) f(T); // #1
+
+template<template<class> class TT, class T>
+decltype(g<TT>(T{})) f(T); // redeclaration of #1
+
+template<class T> struct A;
+
+int main() {
+ f<A>(0);
+}