S.Tobias said:
/Trap representation/ is an object representation that does not represent
any value of the object's type.
That's my understanding too, after carefully reading that paragraph.
It seems to say that accessing an object itself through a character
type, does not produce UB.
IMO this conclusion isn't quite right... (read on)
Jack said:
Although, at least one member of the committee said that such things
were allowed to exist under the earlier versions of the standard, even
though they weren't mentioned.
I agree. The current Std didn't even have to define "trap representation";
just mentioning that an object may not have a value is enough.
And the reply I received was essentially what I posted and you quoted
above, and I will copy and paste here again:
[snip]
We're dealing with human language here, not Mathematics. If the Std
explicitly excluded some types from a behaviour, presumably it intended
that the behaviour does not engage those types.
This comment is a misreading. The statements in 6.2.6.1 p5 require
something of all types that aren't character types; the character
types aren't stated as excluded from the requirement, they just aren't
included in the statement.
Now I'll try to take Jack's side.
Although accessing trap representation of a signed char does not
seem to raise UB by itself, I think UB will be invoked anyway
at some point.
Here is my reading. See if this strikes your fancy:
1. Accessing an object with some type not a character type, where the
object holds a trap representation of the type of the object, must
produce undefined behavior.
2. Accessing an object with some type not a character type, where the
object holds a trap representation of the type of the object, but
the access is done through a signed character type or plain character
type if plain char has the same representation as signed char, might
or might not produce undefined behavior, depending on whether the
byte(s) accessed are trap representation for the signed character
type.
3. Accessing an object with some type that is a character type, where
the object holds a trap representation for the type of signed char,
and where the access is done through a signed character type or plain
character type if plain char has the same representation as signed
char, does produce undefined behavior.
4. Accessing an object of any type with any representation whether
trap representation or not, with the access being done through
an unsigned character type, is always defined behavior because
there are never trap representations for unsigned character.
I believe that's the reading most consistent with everything else
said about trap representations (at least that I've found).
I have one more question: in the paragraph under discussion 6.2.6.1p5
it says trap representation can be produced by "a side effect that
modifies [...] the object by an lvalue expression that does
not have character type". So, for an example, how can you produce
a trap representation (in a valid way) in a `long' object with
a `long' lvalue?
Three ways for trap representations to come into existence:
1. Uninitialized variables;
2. Trap representations for other types can be stored byte-by-byte
using 'unsigned char' access; and
3. Trap representations can be generated by exceptional conditions.
See notes 44 and 45, and section 6.5 p5. Notes 44 and 45 are
interesting, because they say "no arithmetic operation on valid
values can generate a trap representation other than as part of
an exceptional condition such as an overflow". Since exceptional
conditions *already* mean undefined behavior, saying they can
produce trap representations which can cause further undefined
behavior really isn't much cause for concern.
Presumably also trap representations could also be produced by, eg,
computing a (legal) value that's an 'unsigned long' and casting it to
'long'. The cast could be done indirectly, eg, casting the address of
the 'unsigned long' variable to '(long *)' and then dereferencing. In
either case, producing the value already required undefined behavior.
I believe there's no way to defined-ly produce a trap representation
for a 'long' object other than (1) or (2) above. (The wording in
6.2.6.1 p5 doesn't say that the operation that caused the store was a
defined operation.)
I guess it's also possible that only part of the object in question
could be modified, making the object as a whole a trap representation.
How this might happen without undefined behavior having already
happened I can't say....