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 <ja...@redhat.com> 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 0000000..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());