T
Tim Rentsch
Harald van Dijk said:Harald said:[snip]Consider:
1. Examples in the Rationale show that some expressions with
undefined behavior still can be valid ICE's and not run afoul
of 6.6p4;Yes, but those examples are undefined in non-constant expressions for
other reasons than 6.5p5.
That doesn't matter. Undefined behavior is undefined behavior;
there aren't different kinds of UB (per 4p2).
4p2 doesn't say that undefined behaviour with constraint violation is
equivalent to undefined behaviour without constraint violation. Some
forms of undefined behaviour in non-constant expressions violate a
constraint in constant expressions, others don't.
The rules for UB and CV's are very clear: if there is a
constraint violation, there must be at least one diagnostic
message issued, whether there is UB or not; if there isn't a
constraint violation, UB allows an implementation complete
freedom to do whatever it wants. I don't see any basis for your
assertion. There is nothing magical about 6.5p5; it's just a
shorthand way of identifying numerous circumstances that have
undefined behavior, and nothing more than that.
I understand. There are multiple implementations that do define it as
an extension.
(Just curious - can you name some? I'm a little surprised that
they would actually document it.)
If the same wording in 6.5p5 can only logically be taken to refer to
the mathematical value, I assume it also refers to the mathematical
value in 6.6p4.
But it isn't the same wording. It's true some words are the
same, but others aren't. If what was meant in 6.6p4 were the
same condition as in 6.5p5, normally we would expect the earlier
defined term ('exceptional condition') to be used in the later
paragraph. It isn't.
Just to be clear: I'm not claiming any sort of absolute truth
here. I believe the most natural readings for 6.5p5 and 6.6p4
are talking about different things, more specifically one being
mathematical and the other being defined by C semantics. That
doesn't mean other people might not read them differently (and
I mean reasonable and rational people, not insane ones .
Unsigned types are reduced modulo 2**N. Taking UINT_MAX+1, the
mathematical result of (UINT_MAX+1) modulo (UINT_MAX+1) is zero, which
is within the range of unsigned int.
This strikes me as a tautological statement that doesn't
address the point of my comment. Can you rephrase it
so there is a clearer relationship?
I do not believe either 6.5p5 or 6.6p4 applies or is intended to apply
to pointer arithmetic.
Leaving aside 6.5p5 for the moment, I don't see any reason
why 6.6p4 would not apply to pointer arithmetic (in cases
where the condition holds).
Do you know of an implementation that treats it
that way -- that diagnoses
a.c:
int array[1];
b.c:
extern int array[];
int pointer = array + 20;
as a constraint violation?
No, because the result of evaluating 'array + 20' is in the
range of representable values for its type. It might not be
a very useful value, but it is a representable value. (And
if it is _not_ in the range of representable values, then
6.6p4 requires a diagnostic message -- doesn't it?)
I believe this is simply undefined
behaviour because of 6.5.6p8, both in constant and in non-constant
expressions.
It surely is undefined behavior, but if 6.6p4 is not violated
then it must also be in the range of representable values for
that pointer type.
Surely 6.6p5 is meant to
[ 6.5p5? ]
Yes (my brain corrected that typo, but my fingers didn't...)
The only difference in the wording is that 6.5p5 allows for cases
where the result is not mathematically defined.
That is a difference, but it is not the only difference.
The wording "in the
range of representable values for its type" is identical between 6.5p5
and 6.6p4, so how could it mean two different things?
The surrounding text is different.
Besides, 6.6p4
makes more sense to me when reading it as referring to the
mathematical value than otherwise.
My counter-example is floating-point, where X*Y can
be mathematically out-of-range, but under evaluation
rules might be +INF, which is representable. (I am
not an expert, but I believe such things are allowed
as CE's when IEEE floating-point is in effect.)
Unless 6.6p4 is intended to apply to 0/0 -- of which I am now unsure,
as already stated:
*If* the implementation defines 0/0 as 1/!__has_entered_main(), *and*
documents it as such, it may technically be permitted. It is a silly
implementation that only attempts to stretch the rules, and I will not
take such an implementation any more seriously than I would one that
diagnoses every program with only "hello".
I agree it's a silly implementation. Imagining silly
implementations is sometimes useful to explore the
boundaries of what the Standard allows.
I do not believe there is any inconsistency, either in your
interpretation or in mine.
I'm not sure I understand what you're saying.
[...]
1. Undefined behavior always means an out-of-range value
(for any type);
This is not something I have claimed, or you have claimed. If you do
believe this, or believe that I do, then [snip]
I don't, for either one. The statement (1.) above is meant to be
a natural generalization (put that in quotes if you prefer) of
examples in the DR's. That's a problem generically with many
DR's - they only give examples, and don't actually clarify
what the rules are more generally, except by having to guess.