public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: Patrick Palka <ppalka@redhat.com>
To: Jason Merrill <jason@redhat.com>
Cc: Patrick Palka <ppalka@redhat.com>, gcc-patches@gcc.gnu.org
Subject: Re: [PATCH] c++: ttp CTAD equivalence [PR112737]
Date: Wed, 31 Jan 2024 16:03:04 -0500 (EST)	[thread overview]
Message-ID: <619f5b57-9598-762c-7e38-a9e6c98a6401@idea> (raw)
In-Reply-To: <673370b1-e7bc-4d8c-8d09-748d20c0bbb7@redhat.com>

On Wed, 31 Jan 2024, Jason Merrill wrote:

> 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?

I was hoping cp_tree_equal would never be called for a ttp TEMPLATE_DECL
after this patch, and so it wouldn't matter either way, but it turns out
to matter for a function template-id:

  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 { A(T); };

  int main() {
    f<A>(0);
  }

Here we represent TT in g<TT> as a TEMPLATE_DECL because it's not until
coercion that convert_template_argument turns it into a
TEMPLATE_TEMPLATE_PARM, but of course we can't coerce until the call is
non-dependent and we know which function we're calling.  (So TT within
a class, variable or alias template-id would be represented as a
TEMPLATE_TEMPLATE_PARM since we can do coercion ahead of time in that
case.)

So indeed it seems desirable to handle this in cp_tree_equal... like so?
Bootstrap and regtest nearly finished.

-- >8 --

	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/ttp42a.C: New test.
---
 gcc/cp/pt.cc                           |  9 +++++++++
 gcc/cp/tree.cc                         |  6 +++++-
 gcc/cp/typeck.cc                       |  4 ++--
 gcc/testsuite/g++.dg/template/ttp42.C  | 14 ++++++++++++++
 gcc/testsuite/g++.dg/template/ttp42a.C | 18 ++++++++++++++++++
 5 files changed, 48 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/template/ttp42.C
 create mode 100644 gcc/testsuite/g++.dg/template/ttp42a.C

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 5871cb668d0..ca454758ca7 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -1816,6 +1816,13 @@ 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);
+      else
+	/* Hash it like any other declaration.  */
+	break;
+
     case TARGET_EXPR:
       return iterative_hash_template_arg (TARGET_EXPR_INITIAL (arg), val);
 
@@ -4499,6 +4506,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 77f57e0f9ac..5c8c05dc168 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 a15eda3f5f8..87109e63138 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 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>();
+}
diff --git a/gcc/testsuite/g++.dg/template/ttp42a.C b/gcc/testsuite/g++.dg/template/ttp42a.C
new file mode 100644
index 00000000000..e890deda3a3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/ttp42a.C
@@ -0,0 +1,18 @@
+// PR c++/112737
+// A version of ttp42.C using a function template-id instead of ttp CTAD.
+// { 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 { A(T); };
+
+int main() {
+  f<A>(0);
+}
-- 
2.43.0.493.gbc7ee2e5e1


  reply	other threads:[~2024-01-31 21:03 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-01-31 17:12 Patrick Palka
2024-01-31 19:23 ` Jason Merrill
2024-01-31 21:03   ` Patrick Palka [this message]
2024-01-31 21:04     ` Patrick Palka
2024-02-01  2:51     ` Jason Merrill

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=619f5b57-9598-762c-7e38-a9e6c98a6401@idea \
    --to=ppalka@redhat.com \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=jason@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).