public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
From: Jason Merrill <jason@gcc.gnu.org>
To: gcc-cvs@gcc.gnu.org
Subject: [gcc r12-3766] c++: fix template instantiation comparison in redeclarations
Date: Wed, 22 Sep 2021 04:03:21 +0000 (GMT)	[thread overview]
Message-ID: <20210922040321.D3BC43858D39@sourceware.org> (raw)

https://gcc.gnu.org/g:72394d38d929c72cad6cf706a0e790b5934f2bf1

commit r12-3766-g72394d38d929c72cad6cf706a0e790b5934f2bf1
Author: Barrett Adair <barrettellisadair@gmail.com>
Date:   Wed Sep 15 15:26:22 2021 -0500

    c++: fix template instantiation comparison in redeclarations
    
    This change fixes a primordial c++11 frontend defect where function template
    redeclarations with trailing return types that used dependent
    sizeof/alignof/noexcept expressions in template value arguments failed to
    compare as equivalent to the identical primary template declaration. By
    forcing structural AST comparison of the template arguments, we no longer
    require TYPE_CANONICAL to match in this case. The new canon-type-{15..18}.C
    tests failed with all prior GCC versions, where the redeclarations were
    incorrectly reported as ambiguous overloads. The new dependent-name{15,16}.C
    tests are regression tests for sneaky problems encountered during
    development of this fix. Note that this fix does not address the use of parm
    objects' constexpr members as template arguments within a declaration (a
    superficially similar longstanding defect).
    
    gcc/cp/ChangeLog:
    
            * pt.c (find_parm_usage_r): New walk_tree callback to find func
            parms.
            (any_template_arguments_need_structural_equality_p): New special
            case.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/cpp0x/constexpr-52830.C: Remove unwanted dg-ice.
            * g++.dg/template/canon-type-15.C: New test.
            * g++.dg/template/canon-type-16.C: New test.
            * g++.dg/template/canon-type-17.C: New test.
            * g++.dg/template/canon-type-18.C: New test.
            * g++.dg/template/dependent-name15.C: New regression test.
            * g++.dg/template/dependent-name16.C: New regression test.

Diff:
---
 gcc/cp/pt.c                                      | 21 +++++++++++++++++++++
 gcc/testsuite/g++.dg/cpp0x/constexpr-52830.C     |  1 -
 gcc/testsuite/g++.dg/template/canon-type-15.C    |  7 +++++++
 gcc/testsuite/g++.dg/template/canon-type-16.C    |  6 ++++++
 gcc/testsuite/g++.dg/template/canon-type-17.C    |  5 +++++
 gcc/testsuite/g++.dg/template/canon-type-18.C    |  6 ++++++
 gcc/testsuite/g++.dg/template/dependent-name15.C | 18 ++++++++++++++++++
 gcc/testsuite/g++.dg/template/dependent-name16.C | 14 ++++++++++++++
 8 files changed, 77 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 4d42899f28d..048bbc4622d 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -27813,6 +27813,20 @@ dependent_template_arg_p (tree arg)
     return value_dependent_expression_p (arg);
 }
 
+/* Identify any expressions that use function parms.  */
+
+static tree
+find_parm_usage_r (tree *tp, int *walk_subtrees, void*)
+{
+  tree t = *tp;
+  if (TREE_CODE (t) == PARM_DECL)
+    {
+      *walk_subtrees = 0;
+      return t;
+    }
+  return NULL_TREE;
+}
+
 /* Returns true if ARGS (a collection of template arguments) contains
    any types that require structural equality testing.  */
 
@@ -27857,6 +27871,13 @@ any_template_arguments_need_structural_equality_p (tree args)
 	      else if (!TYPE_P (arg) && TREE_TYPE (arg)
 		       && TYPE_STRUCTURAL_EQUALITY_P (TREE_TYPE (arg)))
 		return true;
+	      /* Checking current_function_decl because this structural
+		 comparison is only necessary for redeclaration.  */
+	      else if (!current_function_decl
+		       && dependent_template_arg_p (arg)
+		       && (cp_walk_tree_without_duplicates
+			   (&arg, find_parm_usage_r, NULL)))
+		return true;
 	    }
 	}
     }
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-52830.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-52830.C
index eae0d8c377b..d6057f13497 100644
--- a/gcc/testsuite/g++.dg/cpp0x/constexpr-52830.C
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-52830.C
@@ -1,7 +1,6 @@
 // PR c++/52830
 // { dg-do compile { target c++11 } }
 // { dg-additional-options "-fchecking" }
-// { dg-ice "comptypes" }
 
 template<bool b> struct eif { typedef void type; };
 template<>       struct eif<false> {};
diff --git a/gcc/testsuite/g++.dg/template/canon-type-15.C b/gcc/testsuite/g++.dg/template/canon-type-15.C
new file mode 100644
index 00000000000..b001b5c841d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/canon-type-15.C
@@ -0,0 +1,7 @@
+// { dg-do compile { target c++11 } }
+template<unsigned u> struct size_c{ static constexpr unsigned value = u; };
+namespace g {
+template<class T> auto return_size(T t) -> size_c<sizeof(t)>;
+template<class T> auto return_size(T t) -> size_c<sizeof(t)>;
+}
+static_assert(decltype(g::return_size('a'))::value == 1u, "");
diff --git a/gcc/testsuite/g++.dg/template/canon-type-16.C b/gcc/testsuite/g++.dg/template/canon-type-16.C
new file mode 100644
index 00000000000..99361cbac30
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/canon-type-16.C
@@ -0,0 +1,6 @@
+// { dg-do compile { target c++11 } }
+template<bool u> struct bool_c{ static constexpr bool value = u; };
+template<class T> auto noexcepty(T t) -> bool_c<noexcept(t())>;
+template<class T> auto noexcepty(T t) -> bool_c<noexcept(t())>;
+struct foo { void operator()() noexcept; };
+static_assert(decltype(noexcepty(foo{}))::value, "");
diff --git a/gcc/testsuite/g++.dg/template/canon-type-17.C b/gcc/testsuite/g++.dg/template/canon-type-17.C
new file mode 100644
index 00000000000..0555c8d0a42
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/canon-type-17.C
@@ -0,0 +1,5 @@
+// { dg-do compile { target c++11 } }
+template<unsigned u> struct size_c{ static constexpr unsigned value = u; };
+template<class... T> auto return_size(T... t) -> size_c<sizeof...(t)>;
+template<class... T> auto return_size(T... t) -> size_c<sizeof...(t)>;
+static_assert(decltype(return_size('a'))::value == 1u, "");
diff --git a/gcc/testsuite/g++.dg/template/canon-type-18.C b/gcc/testsuite/g++.dg/template/canon-type-18.C
new file mode 100644
index 00000000000..2510181725c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/canon-type-18.C
@@ -0,0 +1,6 @@
+// { dg-do compile { target c++11 } }
+// { dg-options "-Wno-pedantic" }
+template<unsigned u> struct size_c{ static constexpr unsigned value = u; };
+template<class T> auto get_align(T t) -> size_c<alignof(t)>;
+template<class T> auto get_align(T t) -> size_c<alignof(t)>;
+static_assert(decltype(get_align('a'))::value == 1u, "");
diff --git a/gcc/testsuite/g++.dg/template/dependent-name15.C b/gcc/testsuite/g++.dg/template/dependent-name15.C
new file mode 100644
index 00000000000..1c34bc704f9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/dependent-name15.C
@@ -0,0 +1,18 @@
+// { dg-do compile { target c++11 } }
+template <int N> struct A { static void foo(){} };
+template <> struct A<sizeof(char)> { using foo = int; };
+
+template <class T> void f(T t1) { 
+    A<sizeof(t1)>::foo();
+}
+
+template <class T> void g(T t2) { 
+    /* if the comparing_specializations check breaks in cp_tree_equal
+    case PARM_DECL, the error will incorrectly report A<sizeof (t1)> */
+    A<sizeof(t2)>::foo(); // { dg-error "dependent-name .A<sizeof .t2.>::foo" }
+}
+
+void h() {
+    f(0);
+    g('0');
+}
diff --git a/gcc/testsuite/g++.dg/template/dependent-name16.C b/gcc/testsuite/g++.dg/template/dependent-name16.C
new file mode 100644
index 00000000000..ef8c4f23077
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/dependent-name16.C
@@ -0,0 +1,14 @@
+// { dg-do compile { target c++11 } }
+template <int N> struct A { static void foo(){} };
+template <> struct A<sizeof(char)> { using foo = int; };
+
+template<class T1> auto f(T1 t1) -> decltype(A<sizeof(t1)>::foo());
+
+/* if the comparing_specializations check breaks in cp_tree_equal
+case PARM_DECL, the error will incorrectly report A<sizeof (t1)> */
+template<class T2> auto g(T2 t2) -> decltype(A<sizeof(t2)>::foo()); // { dg-error "dependent-name .A<sizeof .t2.>::foo" }
+
+void h() {
+    f(0);
+    g('0'); // { dg-error "no matching function" }
+}


                 reply	other threads:[~2021-09-22  4:03 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

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=20210922040321.D3BC43858D39@sourceware.org \
    --to=jason@gcc.gnu.org \
    --cc=gcc-cvs@gcc.gnu.org \
    /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).