This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
C++ PATCH for c++/51489 (pointer subtraction in constant expression)
- From: Jason Merrill <jason at redhat dot com>
- To: gcc-patches List <gcc-patches at gcc dot gnu dot org>
- Date: Mon, 19 Dec 2011 00:56:15 -0500
- Subject: C++ PATCH for c++/51489 (pointer subtraction in constant expression)
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 <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");