Patchwork C++ PATCH for c++/51489 (pointer subtraction in constant expression)

login
register
mail settings
Submitter Jason Merrill
Date Dec. 19, 2011, 5:56 a.m.
Message ID <4EEED1FF.5000101@redhat.com>
Download mbox | patch
Permalink /patch/132156/
State New
Headers show

Comments

Jason Merrill - Dec. 19, 2011, 5:56 a.m.
DR 1313 removes the blanket prohibition on pointer subtraction in 
constant expressions and replaces it with a prohibition on operations 
with undefined behavior, so this testcase ought to work.  It wasn't 
working because our internal representation of pointer subtraction 
involves converting the pointers to ptrdiff_t before subtracting, and 
such a conversion is prohibited (previously specifically, now as a 
reinterpret_cast).  There's currently no good way to distinguish between 
a user-written cast and the compiler-generated one, so I've moved the 
check to cxx_eval_outermost_constant_expr for now.

Tested x86_64-pc-linux-gnu, applying to trunk.

Patch

commit 502ce5b614044439f19eaec7c7241e414015a314
Author: Jason Merrill <jason@redhat.com>
Date:   Sun Dec 18 06:15:09 2011 -0500

    	PR c++/51489
    	* semantics.c (cxx_eval_outermost_constant_expr): Check for
    	conversion from pointer to integer here.
    	(cxx_eval_constant_expression) [NOP_EXPR]: Not here.

diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index ab9227f..a6462fc 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -7703,17 +7703,6 @@  cxx_eval_constant_expression (const constexpr_call *call, tree t,
 	tree oldop = TREE_OPERAND (t, 0);
 	tree op = oldop;
 	tree to = TREE_TYPE (t);
-	tree source = TREE_TYPE (op);
-        if (TYPE_PTR_P (source) && ARITHMETIC_TYPE_P (to)
-	    && !(TREE_CODE (op) == COMPONENT_REF
-		 && TYPE_PTRMEMFUNC_P (TREE_TYPE (TREE_OPERAND (op, 0)))))
-          {
-            if (!allow_non_constant)
-              error ("conversion of expression %qE of pointer type "
-                     "cannot yield a constant expression", op);
-	    *non_constant_p = true;
-	    return t;
-          }
 	op = cxx_eval_constant_expression (call, TREE_OPERAND (t, 0),
 					   allow_non_constant, addr,
 					   non_constant_p);
@@ -7802,6 +7791,20 @@  cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant)
       non_constant_p = true;
     }
 
+  /* Technically we should check this for all subexpressions, but that
+     runs into problems with our internal representation of pointer
+     subtraction and the 5.19 rules are still in flux.  */
+  if (CONVERT_EXPR_CODE_P (TREE_CODE (r))
+      && ARITHMETIC_TYPE_P (TREE_TYPE (r))
+      && TREE_CODE (TREE_OPERAND (r, 0)) == ADDR_EXPR)
+    {
+      if (!allow_non_constant)
+	error ("conversion from pointer type %qT "
+	       "to arithmetic type %qT in a constant-expression",
+	       TREE_TYPE (TREE_OPERAND (r, 0)), TREE_TYPE (r));
+      non_constant_p = true;
+    }
+
   if (non_constant_p && !allow_non_constant)
     return error_mark_node;
   else if (non_constant_p && TREE_CONSTANT (t))
@@ -8109,25 +8112,10 @@  potential_constant_expression_1 (tree t, bool want_rval, tsubst_flags_t flags)
     case NOP_EXPR:
     case CONVERT_EXPR:
     case VIEW_CONVERT_EXPR:
-      /* -- an array-to-pointer conversion that is applied to an lvalue
-            that designates an object with thread or automatic storage
-            duration;  FIXME not implemented as it breaks constexpr arrays;
-	    need to fix the standard
-         -- a type conversion from a pointer or pointer-to-member type
-            to a literal type.  */
+      /* -- a reinterpret_cast.  FIXME not implemented, and this rule
+	 may change to something more specific to type-punning (DR 1312).  */
       {
         tree from = TREE_OPERAND (t, 0);
-        tree source = TREE_TYPE (from);
-        tree target = TREE_TYPE (t);
-        if (TYPE_PTR_P (source) && ARITHMETIC_TYPE_P (target)
-	    && !(TREE_CODE (from) == COMPONENT_REF
-		 && TYPE_PTRMEMFUNC_P (TREE_TYPE (TREE_OPERAND (from, 0)))))
-          {
-            if (flags & tf_error)
-              error ("conversion of expression %qE of pointer type "
-                     "cannot yield a constant expression", from);
-            return false;
-          }
         return (potential_constant_expression_1
 		(from, TREE_CODE (t) != VIEW_CONVERT_EXPR, flags));
       }
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-ptrsub.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-ptrsub.C
new file mode 100644
index 0000000..bccec73
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-ptrsub.C
@@ -0,0 +1,14 @@ 
+// PR c++/51489
+// DR 1313
+// { dg-options "-std=c++0x" }
+
+struct array
+{
+  constexpr array() :x(0) {}
+  constexpr int const* begin() { return &x; }
+  int x;
+};
+constexpr array aa;
+constexpr auto b = aa.begin();
+static_assert(b-b == 0, "compiles just fine");
+static_assert(aa.begin()-aa.begin() == 0, "compiler thinks it's not a constant expression");