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

Message ID CAARDWz8R_=B80YcQR+omBF1ygWFhkNomm4TGBu+dGszPdkqRgw@mail.gmail.com
State Superseded
Headers
Series [v4] c++: Fix cp_tree_equal for template value args using dependent sizeof/alignof/noexcept expressions |

Commit Message

Barrett Adair Sept. 17, 2021, 4:44 p.m. UTC
  I think the patch is in good shape now, thanks for the help.

canon-type*.C fail with trunk and pass with patch, dependent-name*.C are
regression tests that pass with both. I removed the dg-ice from
constexpr-52830.C. I didn't dig much into the churn history there, but the
test code looks valid to me and clang agrees.

I also returned the copyright assignment form yesterday to assign@gnu.org.
  

Comments

Jason Merrill Sept. 20, 2021, 9:12 p.m. UTC | #1
On 9/17/21 12:44, Barrett Adair wrote:
> I think the patch is in good shape now, thanks for the help.
> 
> canon-type*.C fail with trunk and pass with patch, dependent-name*.C are 
> regression tests that pass with both. I removed the dg-ice from 
> constexpr-52830.C. I didn't dig much into the churn history there, but 
> the test code looks valid to me and clang agrees.
> 
> I also returned the copyright assignment form yesterday to 
> assign@gnu.org <mailto:assign@gnu.org>.

> +/* Identify any expressions that use function parms */

A comment should end with a period and two spaces.

> +static tree
> +find_parm_usage_r (tree tp, int *walk_subtrees, void)
> +{
> +  tree t = *tp;
> +  if (PACK_EXPANSION_P (t) || (TREE_CODE (t) == PARM_DECL))

PACK_EXPANSION_P is wrong here; a pack expansion might not involve a 
function parameter (pack) at all.  And walk_tree should already recurse 
into the pattern of a pack expansion, so handling them specifically here 
shouldn't be necessary.

> +	      else if (!current_function_decl

This needs a comment about why we're checking current_function_decl 
(because we only need structural comparison for redeclaration comparisons)

> +		       && dependent_template_arg_p (arg)
> +		       && cp_walk_tree_without_duplicates (&arg,
> +		            find_parm_usage_r, NULL))

Here the second line of args needs to line up with the args on the 
previous line.  When that's too far to the right, like here, I tend to 
write e.g.

 > +		       && (cp_walk_tree_without_duplicates
 > +		           (&arg, find_parm_usage_r, NULL)))

Jason
  

Patch

From 9bea055c84d307ade7095fa2cdf7432b42ee0897 Mon Sep 17 00:00:00 2001
From: Barrett Adair <barrettellisadair@gmail.com>
Date: Wed, 15 Sep 2021 15:26:22 -0500
Subject: [PATCH] Fix template instantiation comparison outside function body

---
 gcc/cp/pt.c                                    | 18 ++++++++++++++++++
 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, 74 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 224dd9ebd2b..597422045d3 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -27766,6 +27766,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 (PACK_EXPANSION_P (t) || (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.  */
 
@@ -27810,6 +27823,11 @@  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;
+	      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