The standard has the following to say about the common initial sequence, [class.mem.general] paragraphs 23 through 26:

The common initial sequence of two standard-layout struct ([class.prop]) 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 corresponding entities have layout-compatible types ([basic.types]), either both entities are declared with the no_­unique_­address attribute ([dcl.attr.nouniqueaddr]) or neither is, and either both entities are bit-fields with the same width or neither is a bit-field.

Two standard-layout struct ([class.prop]) types are layout-compatible classes if their common initial sequence comprises all members and bit-fields of both classes ([basic.types]).

Two standard-layout unions are layout-compatible if they have the same number of non-static data members and corresponding non-static data members (in any order) have layout-compatible types ([basic.types.general]).

In a standard-layout union with an active member 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; the behavior is as if the corresponding member of T1 were nominated.

There is no requirement that corresponding non-static members have the same alignment, so it appears that these two structs are layout-compatible, for example:

struct A {
    int i;
    char c;
};

struct B {
    int i;
    alignas(8) char c;
};

However, typically, A will be laid out as iiiic... while B will be laid out as iiii....c....... .

GCC actually reports that these two types are not layout-compatible, but nothing in the standard says that they're not. I think this is a defect in the standard and it should say that corresponding entities must have the same alignment. Otherwise, I don't see how paragraph 26 could make sense: it is not reasonable to expect that if a union has members of types A and B, and one of those members is active, we can read c from the other one, considering that the offsets are different.

If I'm right, it's sort of surprising that the GCC developers haven't already reported an issue. Maybe it's been reported already and it's on a version of the CWG issues list that hasn't been made public yet? Hopefully someone on this list can tell me whether that's the case. If not, I will submit this as a core issue according to the instructions here: https://isocpp.org/std/submit-issue
--
Brian Bi