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>();
+}

Reply via email to