diff options
author | Patrick Palka <ppalka@redhat.com> | 2024-02-01 13:17:48 -0500 |
---|---|---|
committer | Patrick Palka <ppalka@redhat.com> | 2024-02-01 13:17:48 -0500 |
commit | 3ba5be16a2be3eaedf2870ca1e25cfe826945948 (patch) | |
tree | 80ffe11525affcc16c60e4849b6cf8d88e467e44 | |
parent | a886a90625a4ba5e1cc3270e69735cc4fe51f19c (diff) | |
download | gcc-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>
-rw-r--r-- | gcc/cp/pt.cc | 7 | ||||
-rw-r--r-- | gcc/cp/tree.cc | 6 | ||||
-rw-r--r-- | gcc/cp/typeck.cc | 4 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/template/ttp42.C | 14 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/template/ttp43.C | 17 |
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); +} |