diff mbox series

[v6] c++: Fix cp_tree_equal for template value args using dependent sizeof/alignof/noexcept expressions

Message ID CAARDWz8nWTdSg_=0YctyB5WKqWRU-MbWpurgjQvA-4pnw=h-KQ@mail.gmail.com
State New
Headers show
Series [v6] c++: Fix cp_tree_equal for template value args using dependent sizeof/alignof/noexcept expressions | expand

Commit Message

Barrett Adair Sept. 22, 2021, 1:19 a.m. UTC
This revision adds description and ChangeLog entries.

Thanks,
Barrett

Comments

Jason Merrill Sept. 22, 2021, 4:06 a.m. UTC | #1
On 9/21/21 21:19, Barrett Adair wrote:
> This revision adds description and ChangeLog entries.

Applied, thanks!  I wrapped some too-long lines in the commit message 
and tweaked the whitespace in the code slightly.

Jason
diff mbox series

Patch

From d256074a17f16ce5a90653e1d907a8dbc105aa43 Mon Sep 17 00:00:00 2001
From: Barrett Adair <barrettellisadair@gmail.com>
Date: Wed, 15 Sep 2021 15:26:22 -0500
Subject: [PATCH] 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.
---
 gcc/cp/pt.c                                   | 20 +++++++++++++++++++
 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 ++++++
 .../g++.dg/template/dependent-name15.C        | 18 +++++++++++++++++
 .../g++.dg/template/dependent-name16.C        | 14 +++++++++++++
 8 files changed, 76 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/template/canon-type-15.C
 create mode 100644 gcc/testsuite/g++.dg/template/canon-type-16.C
 create mode 100644 gcc/testsuite/g++.dg/template/canon-type-17.C
 create mode 100644 gcc/testsuite/g++.dg/template/canon-type-18.C
 create mode 100644 gcc/testsuite/g++.dg/template/dependent-name15.C
 create mode 100644 gcc/testsuite/g++.dg/template/dependent-name16.C

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 4d42899f28d..5ba771db678 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -27813,6 +27813,19 @@  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 +27870,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" }
+}
-- 
2.30.2