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

2016-03-01 Thread Jason Merrill

On 12/19/2011 12:56 AM, Jason Merrill wrote:

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.


This fix worked for pointer arithmetic based on a static array, but not 
for a local array in a constexpr function.  The fix is a simple matter 
of not insisting that the ptrdiff_t operands be constant themselves.


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


commit 9537133530fe9a6f6a9c0e61d9bbe7332a106c3c
Author: Jason Merrill 
Date:   Tue Mar 1 02:01:46 2016 -0500

	PR c++/51489

	* constexpr.c (cxx_eval_binary_expression): Don't VERIFY_CONSTANT
	the operands.

diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index a21997a..bcb129f 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -1612,15 +1612,14 @@ cxx_eval_binary_expression (const constexpr_ctx *ctx, tree t,
   tree lhs, rhs;
   lhs = cxx_eval_constant_expression (ctx, orig_lhs, /*lval*/false,
   non_constant_p, overflow_p);
-  /* Don't VERIFY_CONSTANT if this might be dealing with a pointer to
- a local array in a constexpr function.  */
-  bool ptr = POINTER_TYPE_P (TREE_TYPE (lhs));
-  if (!ptr)
-VERIFY_CONSTANT (lhs);
+  /* Don't VERIFY_CONSTANT here, it's unnecessary and will break pointer
+ subtraction.  */
+  if (*non_constant_p)
+return t;
   rhs = cxx_eval_constant_expression (ctx, orig_rhs, /*lval*/false,
   non_constant_p, overflow_p);
-  if (!ptr)
-VERIFY_CONSTANT (rhs);
+  if (*non_constant_p)
+return t;
 
   location_t loc = EXPR_LOCATION (t);
   enum tree_code code = TREE_CODE (t);
@@ -1653,6 +1652,9 @@ cxx_eval_binary_expression (const constexpr_ctx *ctx, tree t,
 }
   else if (cxx_eval_check_shift_p (loc, ctx, code, type, lhs, rhs))
 *non_constant_p = true;
+  /* Don't VERIFY_CONSTANT if this might be dealing with a pointer to
+ a local array in a constexpr function.  */
+  bool ptr = POINTER_TYPE_P (TREE_TYPE (lhs));
   if (!ptr)
 VERIFY_CONSTANT (r);
   return r;
diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-array4.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-array4.C
new file mode 100644
index 000..fc01047
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-array4.C
@@ -0,0 +1,12 @@
+// { dg-do compile { target c++14 } }
+
+constexpr bool g()
+{
+  int ar[4] = { 1, 2, 3, 4 };
+  auto e1 = ar;
+  auto e4 = ar+3;
+  return (e4-e1) == 3;
+}
+
+#define SA(X) static_assert((X),#X)
+SA(g());


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

2011-12-18 Thread Jason Merrill
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.
commit 502ce5b614044439f19eaec7c7241e414015a314
Author: Jason Merrill ja...@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 000..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);