Skip to content

CWG2736 [class.prop]/3.7 standard layout class with same empty base class type in complete object and first member #317

Description

@leni536

Full name of submitter: Lénárd Szolnoki

Reference (section label): [class.prop]/3.7

has no element of the set $M(\mathtt{S})$ of types as a base class, where for any type X, $M(\mathtt{X})$ is defined as follows.

  • If X is a non-union class type with no non-static data members, the set $M(\mathtt{X})$ is empty.
  • If X is a non-union class type with a non-static data member of type $\mathtt{X}_0$ that is either of zero size or is the first non-static data member of X (where said member may be an anonymous union), the set $M(\mathtt{X})$ consists of $\mathtt{X}_0$ and the elements of $M(\mathtt{X}_0)$.
  • If X is a union type, the set $M(\mathtt{X})$ is the union of all $M(\mathtt{U}_i)$ and the set containing all $\mathtt{U}_i$,
    where each $\mathtt{U}_i$ is the type of the $i^\text{th}$ non-static data member of X.
  • If X is an array type with element type $\mathtt{X}_e$, the set $M(\mathtt{X})$ consists of $\mathtt{X}_e$ and the elements of $M(\mathtt{X}_e)$.
  • If X is a non-class, non-array type, the set $M(\mathtt{X})$ is empty.

Issue description:

Consider the following code:

struct A {};
struct B : A { char ch; };

struct C : A {
    B b;
};

Class C stastfies all the conditions to be considered standard-layout, including [class.prop]/3.7. Evaluating [class.prop]/3.7:

  • $M(C)$: [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)$: [class.prop]/3.7.5, it's an empty set.

Therefore $M(C)$ is $\{B, char\}$, none of which is a base of class C.

The corresponding note suggests that the intention is to not consider such classes as standard-layout.

Practical issues as implemented in some ABIs:

On gcc and clang the following compiles with the example code above:

static_assert(std::is_standard_layout_v<C>);
static_assert(offsetof(C, b) == 1);

This contradicts pointer-interconvertibility rules for standard layout types.

On MSVC the following compiles:

static_assert(std::is_standard_layout_v<C>);
static_assert(sizeof(C) == 1);

Which means that the two distinct subobjects of type A must share the same address. This contradicts [intro.object], where it's specified that these must have distinct addresses. As far as I know the MS ABI has issues in general with this rule.

Suggested resolution:

In [class.prop]/3.7 include direct and indirect base classes of first members.

has no element of the set $M(\mathtt{S})$ of types as a base class, where for any type X, $M(\mathtt{X})$ is defined as follows.

  • If X is a non-union class type with no non-static data members, the set $M(\mathtt{X})$ is empty.
  • If X is a non-union class type with a non-static data member of type $\mathtt{X}_0$ that is either of zero size or is the first non-static data member of X (where said member may be an anonymous union), the set $M(\mathtt{X})$ consists of $\mathtt{X}_0$, direct and indirect base classes of $\mathtt{X}_0$ and the elements of $M(\mathtt{X}_0)$.
  • If X is a union type, the set $M(\mathtt{X})$ is the union of all $M(\mathtt{U}_i)$, the set containing all $\mathtt{U}_i$ and the set containing the direct and indirect base classes of all $\mathtt{U}_i$,
    where each $\mathtt{U}_i$ is the type of the $i^\text{th}$ non-static data member of X.
  • If X is an array type with element type $\mathtt{X}_e$, the set $M(\mathtt{X})$ consists of $\mathtt{X}_e$, direct and indirect base classes of $\mathtt{X}_e$ and the elements of $M(\mathtt{X}_e)$.
  • If X is a non-class, non-array type, the set $M(\mathtt{X})$ is empty.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions