C++ Logo

std-discussion

Advanced search

Re: Possible defect in definition of standard-layout

From: Edward Catmur <ecatmur_at_[hidden]>
Date: Wed, 10 May 2023 09:17:55 -0500
On Wed, 10 May 2023 at 05:43, Edward Catmur <ecatmur_at_[hidden]> wrote:

>
>
> On Tue, May 9, 2023, 17:18 Lénárd Szolnoki via Std-Discussion <
> std-discussion_at_[hidden]> wrote:
>
>> Hi,
>>
>> Consider the following code:
>>
>> #include <type_traits>
>>
>> struct A {};
>> struct B : A { char ch; };
>>
>> struct C : A {
>> B b;
>> };
>>
>> static_assert(std::is_standard_layout_v<C>);
>> static_assert(sizeof(C) == 2);
>>
>> In my reading of https://eel.is/c++draft/class.prop#3 C is standard-
>> layout. GCC with libstdc++ agrees.
>>
>> However the offset of a `b` subobject within an object of C is 1
>> instead of 0 as compiled by both gcc and clang, making it definitely
>> not pointer-interconvertible with the parent object, even though it's
>> required to be:
>>
>> https://eel.is/c++draft/basic.compound#4.3
>>
>> Note that there are two subobjects of type A, requiring different
>> addresses, which makes implementing this tricky, if not impossible.
>>
>> Anyway, https://eel.is/c++draft/class.prop#note-2 suggests that Cis not
>> intended to be standard-layout, however C satisfies the corresponding
>> normative wording https://eel.is/c++draft/class.prop#3.7:
>>
>> * M(C): https://eel.is/c++draft/class.prop#3.7.2 applies, M(C) is the
>> union of {B} and M(B)
>> * M(B) same applies, M(B) is union of {char} and M(char)
>> * M(char): empty https://eel.is/c++draft/class.prop#3.7.5
>>
>> Therefore M(C) is {B, char}, none of which is a base of C.
>>
>> Is this a defect, or did I make a mistake somewhere in my reasoning?
>>
>
> Yes, this looks new.
>

Also, certainly it should not be possible for a standard-layout class not
to be pointer-interconvertible with its first data member.

We got the current wording in
> https://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1672 but
> see also
> https://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1813
>
> TBH, it looks like this has been broken since C++11 (when we first allowed
> standard layout class types to have bases).
> https://timsong-cpp.github.io/cppwp/n3337/class#7
>
> Fixing it will be slightly tricky; it's only the early (zero-offset) bases
> of the first data member that (need to) conflict. What do clang and msvc do
> in that case?
>

Specifically, I'm thinking of:

struct A {};
struct D { char d; };
struct E : D, A {};
struct F : A { E e; };

It seems that F::e is still not pointer-interconvertible with F on Itanium
(though it is on MS ABI): https://godbolt.org/z/a9PY9o4c4
So F should also not be standard-layout, which simplifies things a bit; we
can just add to the M(X) the bases of the types added at each stage. And
amend https://eel.is/c++draft/class.prop#note-2 to read "M(X) is the set of
the types of all subobjects other than base classes of X that can be at a
zero offset in X.".

Do you want to file via https://github.com/cplusplus/CWG/issues ?
>
>
>> Cheers,
>> Lénárd
>> --
>> Std-Discussion mailing list
>> Std-Discussion_at_[hidden]
>> https://lists.isocpp.org/mailman/listinfo.cgi/std-discussion
>>
>

Received on 2023-05-10 14:18:09