On 1/31/24 12:12, Patrick Palka wrote:
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk?
-- >8 --
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 (which uses
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 (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.
We don't have this ttp equivalence issue in other contexts because either
the TEMPLATE_TEMPLATE_PARM is used instead of the TEMPLATE_DECL already
(e.g. when a ttp is used as a targ), or the equivalence logic is relaxed
(e.g. for bound ttps), it seems.
So this patch relaxes ttp CTAD placeholder equivalence accordingly, by
comparing the TEMPLATE_TEMPLATE_PARM instead of the TEMPLATE_DECL. The
ctp_hasher doesn't need to be adjusted since it currently doesn't include
CLASS_PLACEHOLDER_TEMPLATE in the hash anyway.
Maybe put this handling in cp_tree_equal and call it from here? Does
iterative_hash_template_arg need something similar?
PR c++/112737
gcc/cp/ChangeLog:
* typeck.cc (structural_comptypes) <case TEMPLATE_TYPE_PARM>:
If CLASS_PLACEHOLDER_TEMPLATE is a ttp, compare its
TEMPLATE_TEMPLATE_PARM instead of its TEMPLATE_DECL.
gcc/testsuite/ChangeLog:
* g++.dg/template/ttp42: New test.
---
gcc/cp/typeck.cc | 20 +++++++++++++++++---
gcc/testsuite/g++.dg/template/ttp42.C | 14 ++++++++++++++
2 files changed, 31 insertions(+), 3 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/template/ttp42.C
diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
index a15eda3f5f8..be82877e35c 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -1573,9 +1573,23 @@ 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))
- return false;
+ if (CLASS_PLACEHOLDER_TEMPLATE (t1) || CLASS_PLACEHOLDER_TEMPLATE (t2))
+ {
+ tree tmpl1 = CLASS_PLACEHOLDER_TEMPLATE (t1);
+ tree tmpl2 = CLASS_PLACEHOLDER_TEMPLATE (t2);
+ if (!tmpl1 || !tmpl2)
+ return false;
+ if (DECL_TEMPLATE_TEMPLATE_PARM_P (tmpl1)
+ != DECL_TEMPLATE_TEMPLATE_PARM_P (tmpl2))
+ return false;
+ if (DECL_TEMPLATE_TEMPLATE_PARM_P (tmpl1)
+ /* Treat two CTAD placeholders that use equivalent ttps
+ from different scopes as equivalent by comparing their
+ TEMPLATE_TEMPLATE_PARMs instead of their TEMPLATE_DECLs. */
+ ? !same_type_p (TREE_TYPE (tmpl1), TREE_TYPE (tmpl2))
+ : tmpl1 != tmpl2)
+ return false;
+ }
/* Constrained 'auto's are distinct from parms that don't have the same
constraints. */
if (!equivalent_placeholder_constraints (t1, t2))
diff --git a/gcc/testsuite/g++.dg/template/ttp42.C
b/gcc/testsuite/g++.dg/template/ttp42.C
new file mode 100644
index 00000000000..da08e857fc5
--- /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>();
+}