Boost logo

Boost :

Subject: Re: [boost] [config] RFC PR 82
From: Agustín K-ballo Bergé (kaballo86_at_[hidden])
Date: 2015-11-25 11:25:15


On 11/25/2015 12:46 PM, Andrey Semashev wrote:
> On 2015-11-25 18:32, Alexander Lauser wrote:
>>
>>
>> Am 25. November 2015 01:02:25 MEZ, schrieb Gavin Lambert
>> <gavinl_at_[hidden]>:
>>> On 25/11/2015 10:03, Andrey Semashev wrote:
>>>> On 2015-11-24 23:54, Agustín K-ballo Bergé wrote:
>>>>> On 11/24/2015 5:20 PM, Andrey Semashev wrote:
>>>>>>>> Ditto BOOST_HAS_UNION_TYPE_PUNNING_TRICK (doesn't any
>>>>>>>> compiler
>>> support
>>>>>>>> this?).
>>>>>>>
>>>>>>> 'I'm all with you on this one' but since 'it is not in the
>>> standard'
>>>>>>> language purists will probably complain if it is used
>>>>>>> unconditionally...
>>>>>>
>>>>>> To some extent this is guaranteed by [class.union]/1 in
>>>>>> C++11.
>>>>>
>>>>> No, it isn't.
>>>>
>>>> Why? Reading different members of the standard layout union
>>>> within
>>> the
>>>> common initial sequence is enough to implement a bitwise_cast.
>>>
>>> I don't have a standard reference handy, but I'm pretty sure that
>>> reading from a different member of a union than was written to is
>>> still
>>>
>>> explicitly UB -- although for practical reasons *most* compilers
>>> will generate the expected result provided that the two types have
>>> the same initial alignment.
> >
>> http://en.cppreference.com/w/cpp/language/union have an example that
>> explicitly states what Gavin claimed. Not sure about the reliability
>> of that site, though.
>
> That sounds like self contradiction to me. The page says it's well
> defined to examine the common subsequence of standard-layout union
> members but at the same time it's UB to read from them. What's the
> difference?

The wording is convoluted, maybe it becomes clearer with some examples.
Consider:

     int bitcast(float x) {
       union { float from; int to; };
       from = x;
       return to;
     }

The write to `from` above is a dead store, nowhere else in the function
is there a read from it or from anything "compatible" with it. A
compiler is allowed to rewrite this function as follows:

     int bitcast(float x) {
       int to;
       return to;
     }

Furthermore, the value of `to` is unspecified, so the whole function
might simply turn into returning a trap-representation.

Some compilers provide the C11 semantics instead, as a conforming
extension (C11 semantics are a valid form of undefined behavior). On
those compilers, the function would essentially have the following effects:

     int bitcast(float x) {
       int to;
       std::memcpy(&to, &x, sizeof(int));
       return to;
     }

The common initial sequence standard escape hatch does not apply there,
it applies only in very limited scenarios (even less than one would
think it does, due to wording), like the following:

     union {
       struct { int which; int value; } first;
       struct { int which; float value; } second;
     } u;
     switch (u.first.which) { // OK if either first or second is active
     case 0: print(u.first.value); break; // UB if first not active
     case 1: print(u.second.value); break; // UB if second not active
     }

Regards,

-- 
Agustín K-ballo Bergé.-
http://talesofcpp.fusionfenix.com

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk