C++ Logo

std-discussion

Advanced search

Re: Layout compatible classes involving [[no_unique_address]] in the Itanium ABI

From: Jason McKesson <jmckesson_at_[hidden]>
Date: Tue, 13 Oct 2020 16:24:06 -0400
On Tue, Oct 13, 2020 at 2:10 PM Lénárd Szolnoki via Std-Discussion
<std-discussion_at_[hidden]> wrote:
>
> Hi all,
>
> Consider the following example:
>
> #include <type_traits>
> #include <cstddef>
>
> class A1 {
> private:
> int i;
> char ch;
> };
>
> class B1 {
> public:
> [[no_unique_address]] A1 a;
> char ch;
> };
>
> static_assert(std::is_standard_layout_v<B1>);
>
> class A2 {
> public:
> int i;
> char ch;
> };
>
> class B2 {
> public:
> [[no_unique_address]] A2 b2;
> char ch;
> };
>
> static_assert(std::is_standard_layout_v<B1>);
> static_assert(offsetof(B1, ch) != offsetof(B2, ch));
>
> Godbolt: https://godbolt.org/z/1o91bE
>
> Following the standard wording A1 and A2 are layout compatible [1].
> Similarly B1 and B2 are layout compatible. However the ch member in B1
> has different offset than the ch member in B2.

That is not legal. Layout compatible types cannot have offsets for
corresponding member subobjects that are different. That would break
the rules of accessing inactive members of a `union`.

> In the Itanium ABI A1 is not POD for the purpose of layout while A2 is,
> this affects the offset of the ch member.

Can you explain why the Itanium ABI considers `A1` to not be a "POD
for the purpose of layout"? Is it because it has private members?

If so, I don't see how `no_unique_address` matters here; the problem
would still manifest if B1::a and B2::b2 were both not declared with
this qualifier.

> Two possible directions to fix this:
>
> * Modify the standard to disallow [[no_unique_address]] non-empty
> non-static data members to be part of a common initial sequence (or
> maybe only allow as the last element of a common initial sequence).
> * Modify the ABI to disable overlapping of [[no_unique_address]]
> non-empty data members in standard-layout classes.

Again, I'm not sure how this resolves the issue. If there is
overlapping, it should apply equally to `B1::a` and `B2::b2`. Not
unless the ABI is doing something special because `A1` has private
members. And if it is, then *that* is what needs to change.

>
> Personally I would prefer the first option of these two.
>
> I also submitted an issue here:
> https://github.com/itanium-cxx-abi/cxx-abi/issues/108
>
> [1] https://eel.is/c++draft/class#mem.general-22
>
> Regards,
> Lénárd Szolnoki
> --
> Std-Discussion mailing list
> Std-Discussion_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-discussion

Received on 2020-10-13 15:24:19