C++ Logo

std-discussion

Advanced search

Re: Possible defect in definition of standard-layout

From: Lénárd Szolnoki <cpp_at_[hidden]>
Date: Wed, 10 May 2023 19:07:46 +0100
On 10 May 2023 15:17:55 BST, Edward Catmur <ecatmur_at_[hidden]> wrote:
>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.".

I arrived at a similar conclusion. You want to add all bases, direct and indirect, I assume.

>Do you want to file via https://github.com/cplusplus/CWG/issues ?

Yes, I will file it this week.

>>
>>
>>> 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 18:07:51