In this testcase we were folding a bunch of nops within a POINTER_PLUS_EXPR down to a single nop, and then tripping the assert in maybe_constant_value that checks for useless rebuilding of the tree because cp_tree_equal ignores NOPs. The reason for that choice seems to have been so that we can compare template non-type arguments both before and after conversion to match the type of the template parameter, so let's move that code into template_args_equal.

Tested x86_64-pc-linux-gnu, applying to trunk.
commit b912e4bfe602aa82ef49cb4cf331d1bfaddede97
Author: Jason Merrill <ja...@redhat.com>
Date:   Fri Feb 13 17:02:07 2015 -0500

    	PR c++/65054
    	* pt.c (template_args_equal): Look through conversions here.
    	* tree.c (cp_tree_equal): Not here.

diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 2b56cb2..d415dd4 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -3638,7 +3638,6 @@ maybe_constant_value (tree t, tree decl)
 
   r = cxx_eval_outermost_constant_expr (t, true, true, decl);
 #ifdef ENABLE_CHECKING
-  /* cp_tree_equal looks through NOPs, so allow them.  */
   gcc_assert (r == t
 	      || CONVERT_EXPR_P (t)
 	      || TREE_CODE (t) == VIEW_CONVERT_EXPR
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 3317dad..9a00d0d 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -7324,7 +7324,22 @@ template_args_equal (tree ot, tree nt)
   else if (TREE_CODE (ot) == TREE_VEC || TYPE_P (ot))
     return 0;
   else
-    return cp_tree_equal (ot, nt);
+    {
+      /* Try to treat a template non-type argument that has been converted
+	 to the parameter type as equivalent to one that hasn't yet.  */
+      for (enum tree_code code1 = TREE_CODE (ot);
+	   CONVERT_EXPR_CODE_P (code1)
+	     || code1 == NON_LVALUE_EXPR;
+	   code1 = TREE_CODE (ot))
+	ot = TREE_OPERAND (ot, 0);
+      for (enum tree_code code2 = TREE_CODE (nt);
+	   CONVERT_EXPR_CODE_P (code2)
+	     || code2 == NON_LVALUE_EXPR;
+	   code2 = TREE_CODE (nt))
+	nt = TREE_OPERAND (nt, 0);
+
+      return cp_tree_equal (ot, nt);
+    }
 }
 
 /* Returns 1 iff the OLDARGS and NEWARGS are in fact identical sets of
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index c51e42d..c8e6f0c 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -2745,20 +2745,8 @@ cp_tree_equal (tree t1, tree t2)
   if (!t1 || !t2)
     return false;
 
-  for (code1 = TREE_CODE (t1);
-       CONVERT_EXPR_CODE_P (code1)
-	 || code1 == NON_LVALUE_EXPR;
-       code1 = TREE_CODE (t1))
-    t1 = TREE_OPERAND (t1, 0);
-  for (code2 = TREE_CODE (t2);
-       CONVERT_EXPR_CODE_P (code2)
-	 || code2 == NON_LVALUE_EXPR;
-       code2 = TREE_CODE (t2))
-    t2 = TREE_OPERAND (t2, 0);
-
-  /* They might have become equal now.  */
-  if (t1 == t2)
-    return true;
+  code1 = TREE_CODE (t1);
+  code2 = TREE_CODE (t2);
 
   if (code1 != code2)
     return false;
@@ -2996,6 +2984,9 @@ cp_tree_equal (tree t1, tree t2)
     case DYNAMIC_CAST_EXPR:
     case IMPLICIT_CONV_EXPR:
     case NEW_EXPR:
+    CASE_CONVERT:
+    case NON_LVALUE_EXPR:
+    case VIEW_CONVERT_EXPR:
       if (!same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
 	return false;
       /* Now compare operands as usual.  */
diff --git a/gcc/testsuite/g++.dg/expr/ptr-arith1.C b/gcc/testsuite/g++.dg/expr/ptr-arith1.C
new file mode 100644
index 0000000..71e97f7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/expr/ptr-arith1.C
@@ -0,0 +1,7 @@
+// PR c++/65054
+
+const char *
+foo (void)
+{
+  return ((char *const) "abc" + 1);
+}

Reply via email to