On 06/01/2016 10:49 PM, Martin Sebor wrote:
On 06/01/2016 01:20 PM, Jason Merrill wrote:
On 06/01/2016 02:44 PM, Martin Sebor wrote:
The new code in cxx_eval_component_reference diagnoses the following
problem that's not detected otherwise:
struct S { const S *s; };
constexpr S s = { 0 };
constexpr const void *p = &s.s->s;
Note that this falls under core issue 1530, which has not been
resolved.
I don't quite see the relevance of this issue. It's concerned
with storage in which an object will exist at some point in
the future when its lifetime begins or where it existed in
the past before its lifetime ended. There is no object or
storage at s.s above because s.s is null.
True. Unfortunately there isn't any wording about what you can do with
the result of indirecting a null pointer or pointer to one-past-the-end
of an array. There was some proposed for issue 232, but that hasn't
been a high priority. What do you see in the standard currently that
makes it undefined?
In N4567, expr.ref, the E1->E2 expression which is equivalent
to (*E1).E2, the closest match is paragraph 4.2:
If E2 is a non-static data member and the type of E1 is "cq1
vq1 X", and the type of E2 is "cq2 vq2 T", the expression
designates the named member of the object designated by the
first expression.
There is no object, so 4.2 doesn't apply, and since there is
no other bullet that would apply, the behavior is undefined.
OK, I'll buy that.
+ if (code == POINTER_PLUS_EXPR && !*non_constant_p
+ && tree_int_cst_equal (lhs, null_pointer_node))
+ {
+ if (!ctx->quiet)
+ error ("arithmetic involving a null pointer in %qE", lhs);
+ return t;
+ }
+ if (TREE_CODE (whole) == INDIRECT_REF
+ && integer_zerop (TREE_OPERAND (whole, 0))
+ && !ctx->quiet)
+ error ("dereferencing a null pointer in %qE", orig_whole);
+ if (TREE_CODE (t) == INTEGER_CST
+ && TREE_CODE (TREE_TYPE (t)) == POINTER_TYPE
+ && !integer_zerop (t))
+ {
+ if (!ctx->quiet)
+ error ("arithmetic involving a null pointer in %qE", t);
+ }
These places should all set *non_constant_p, and the second should
return t after doing so. OK with that change.
Thanks. I've made the change, but I haven't managed to come up
with a test to exercise it. IIUC, the purpose setting
non_constant_p while the quiet flag is set is to determine without
causing errors that expressions are not valid constant expressions
by passing them to __builtin_constant_p, correct?
No, __builtin_constant_p allows more things than C++ constant
expressions. The purpose of setting *non_constant_p is to cause
maybe_constant_value to return its argument unchanged.
Jason