https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65892

Melissa <myriachan at gmail dot com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |myriachan at gmail dot com

--- Comment #12 from Melissa <myriachan at gmail dot com> ---
This is broken in C++ as well, and in C++, the rules are much more clear that
GCC isn't following them.

Quoting the C++ Standard, revision 4296 (post-C++14?):

16. The "common initial sequence" of two standard-layout struct (Clause 9)
types is the longest sequence of non-static data members and bit-fields in
declaration order, starting with the first such entity in each of the structs,
such that the corresponding entries have layout-compatible types and either
neither entity is a bit-field or both are bit-fields with the same width.

19. In a standard-layout union with an active member (9.5) of struct type T1,
it is permitted to read a non-static data member m of another union member of
struct type T2 provided m is part of the common initial sequence of T1 and T2.


A C++ conversion of the original example is below.  I asked about the word
"read" on the C++ Standard Discussion (std-discussion) mailing list, because it
probably should also allow writing if it allows reads.  As a result, I modified
the below to only *read* in an aliasing way, to fully comply with the written
word of the Standard.


#include <cassert>

struct t1 { int m; };
struct t2 { int m; };

union U {
    t1 s1;
    t2 s2;
};

int f (t1 *p1, t2 *p2)
{
    // union U visible here, p1->m and p2->m may alias
    // p1 is the active member; read from p2 per [class.mem]/19.

    if (p2->m < 0)
        p1->m = -p1->m;

    return p2->m;
}

int main (void)
{
    union U u = { { -1 } };

    int n = f (&u.s1, &u.s2);

    assert (1 == n);

    return 0;
}

Reply via email to