// RUN: %clang_cc1 -std=c++2a -fsyntax-only -triple x86_64-linux-gnu -fdump-record-layouts %s | FileCheck %s namespace Empty { struct A {}; struct B { [[no_unique_address]] A a; char b; }; static_assert(sizeof(B) == 1); // CHECK:*** Dumping AST Record Layout // CHECK: 0 | struct Empty::B // CHECK-NEXT: 0 | struct Empty::A a (empty) // CHECK-NEXT: 0 | char b // CHECK-NEXT: | [sizeof=1, dsize=1, align=1, // CHECK-NEXT: | nvsize=1, nvalign=1] struct C {}; struct D { [[no_unique_address]] A a; [[no_unique_address]] C c; char d; }; static_assert(sizeof(D) == 1); // CHECK:*** Dumping AST Record Layout // CHECK: 0 | struct Empty::D // CHECK-NEXT: 0 | struct Empty::A a (empty) // CHECK-NEXT: 0 | struct Empty::C c (empty) // CHECK-NEXT: 0 | char d // CHECK-NEXT: | [sizeof=1, dsize=1, align=1, // CHECK-NEXT: | nvsize=1, nvalign=1] struct E { [[no_unique_address]] A a1; [[no_unique_address]] A a2; char e; }; static_assert(sizeof(E) == 2); // CHECK:*** Dumping AST Record Layout // CHECK: 0 | struct Empty::E // CHECK-NEXT: 0 | struct Empty::A a1 (empty) // CHECK-NEXT: 1 | struct Empty::A a2 (empty) // CHECK-NEXT: 0 | char e // CHECK-NEXT: | [sizeof=2, dsize=2, align=1, // CHECK-NEXT: | nvsize=2, nvalign=1] struct F { ~F(); [[no_unique_address]] A a1; [[no_unique_address]] A a2; char f; }; static_assert(sizeof(F) == 2); // CHECK:*** Dumping AST Record Layout // CHECK: 0 | struct Empty::F // CHECK-NEXT: 0 | struct Empty::A a1 (empty) // CHECK-NEXT: 1 | struct Empty::A a2 (empty) // CHECK-NEXT: 0 | char f // CHECK-NEXT: | [sizeof=2, dsize=1, align=1, // CHECK-NEXT: | nvsize=2, nvalign=1] struct G { [[no_unique_address]] A a; ~G(); }; static_assert(sizeof(G) == 1); // CHECK:*** Dumping AST Record Layout // CHECK: 0 | struct Empty::G // CHECK-NEXT: 0 | struct Empty::A a (empty) // CHECK-NEXT: | [sizeof=1, dsize=0, align=1, // CHECK-NEXT: | nvsize=1, nvalign=1] struct H { [[no_unique_address]] A a, b; ~H(); }; static_assert(sizeof(H) == 2); // CHECK:*** Dumping AST Record Layout // CHECK: 0 | struct Empty::H // CHECK-NEXT: 0 | struct Empty::A a (empty) // CHECK-NEXT: 1 | struct Empty::A b (empty) // CHECK-NEXT: | [sizeof=2, dsize=0, align=1, // CHECK-NEXT: | nvsize=2, nvalign=1] struct OversizedEmpty : A { ~OversizedEmpty(); [[no_unique_address]] A a; }; static_assert(sizeof(OversizedEmpty) == 2); // CHECK:*** Dumping AST Record Layout // CHECK: 0 | struct Empty::OversizedEmpty // CHECK-NEXT: 0 | struct Empty::A (base) (empty) // CHECK-NEXT: 1 | struct Empty::A a (empty) // CHECK-NEXT: | [sizeof=2, dsize=0, align=1, // CHECK-NEXT: | nvsize=2, nvalign=1] struct HasOversizedEmpty { [[no_unique_address]] OversizedEmpty m; }; static_assert(sizeof(HasOversizedEmpty) == 2); // CHECK:*** Dumping AST Record Layout // CHECK: 0 | struct Empty::HasOversizedEmpty // CHECK-NEXT: 0 | struct Empty::OversizedEmpty m (empty) // CHECK-NEXT: 0 | struct Empty::A (base) (empty) // CHECK-NEXT: 1 | struct Empty::A a (empty) // CHECK-NEXT: | [sizeof=2, dsize=0, align=1, // CHECK-NEXT: | nvsize=2, nvalign=1] struct EmptyWithNonzeroDSize { [[no_unique_address]] A a; int x; [[no_unique_address]] A b; int y; [[no_unique_address]] A c; }; static_assert(sizeof(EmptyWithNonzeroDSize) == 12); // CHECK:*** Dumping AST Record Layout // CHECK: 0 | struct Empty::EmptyWithNonzeroDSize // CHECK-NEXT: 0 | struct Empty::A a (empty) // CHECK-NEXT: 0 | int x // CHECK-NEXT: 4 | struct Empty::A b (empty) // CHECK-NEXT: 4 | int y // CHECK-NEXT: 8 | struct Empty::A c (empty) // CHECK-NEXT: | [sizeof=12, dsize=12, align=4, // CHECK-NEXT: | nvsize=12, nvalign=4] struct EmptyWithNonzeroDSizeNonPOD { ~EmptyWithNonzeroDSizeNonPOD(); [[no_unique_address]] A a; int x; [[no_unique_address]] A b; int y; [[no_unique_address]] A c; }; static_assert(sizeof(EmptyWithNonzeroDSizeNonPOD) == 12); // CHECK:*** Dumping AST Record Layout // CHECK: 0 | struct Empty::EmptyWithNonzeroDSizeNonPOD // CHECK-NEXT: 0 | struct Empty::A a (empty) // CHECK-NEXT: 0 | int x // CHECK-NEXT: 4 | struct Empty::A b (empty) // CHECK-NEXT: 4 | int y // CHECK-NEXT: 8 | struct Empty::A c (empty) // CHECK-NEXT: | [sizeof=12, dsize=8, align=4, // CHECK-NEXT: | nvsize=9, nvalign=4] } namespace POD { // Cannot reuse tail padding of a PDO type. struct A { int n; char c[3]; }; struct B { [[no_unique_address]] A a; char d; }; static_assert(sizeof(B) == 12); // CHECK:*** Dumping AST Record Layout // CHECK: 0 | struct POD::B // CHECK-NEXT: 0 | struct POD::A a // CHECK-NEXT: 0 | int n // CHECK-NEXT: 4 | char [3] c // CHECK-NEXT: 8 | char d // CHECK-NEXT: | [sizeof=12, dsize=12, align=4, // CHECK-NEXT: | nvsize=12, nvalign=4] } namespace NonPOD { struct A { int n; char c[3]; ~A(); }; struct B { [[no_unique_address]] A a; char d; }; static_assert(sizeof(B) == 8); // CHECK:*** Dumping AST Record Layout // CHECK: 0 | struct NonPOD::B // CHECK-NEXT: 0 | struct NonPOD::A a // CHECK-NEXT: 0 | int n // CHECK-NEXT: 4 | char [3] c // CHECK-NEXT: 7 | char d // CHECK-NEXT: | [sizeof=8, dsize=8, align=4, // CHECK-NEXT: | nvsize=8, nvalign=4] } namespace NVSizeGreaterThanDSize { // The nvsize of an object includes the complete size of its empty subobjects // (although it's unclear why). Ensure this corner case is handled properly. struct alignas(8) A { ~A(); }; // dsize 0, nvsize 0, size 8 struct B : A { char c; }; // dsize 1, nvsize 8, size 8 static_assert(sizeof(B) == 8); // CHECK:*** Dumping AST Record Layout // CHECK: 0 | struct NVSizeGreaterThanDSize::B // CHECK-NEXT: 0 | struct NVSizeGreaterThanDSize::A (base) (empty) // CHECK-NEXT: 0 | char c // CHECK-NEXT: | [sizeof=8, dsize=1, align=8, // CHECK-NEXT: | nvsize=8, nvalign=8] struct V { int n; }; // V is at offset 16, not offset 12, because B's tail padding is strangely not // usable for virtual bases. struct C : B, virtual V {}; static_assert(sizeof(C) == 24); // CHECK:*** Dumping AST Record Layout // CHECK: 0 | struct NVSizeGreaterThanDSize::C // CHECK-NEXT: 0 | (C vtable pointer) // CHECK-NEXT: 8 | struct NVSizeGreaterThanDSize::B (base) // CHECK-NEXT: 8 | struct NVSizeGreaterThanDSize::A (base) (empty) // CHECK-NEXT: 8 | char c // CHECK-NEXT: 16 | struct NVSizeGreaterThanDSize::V (virtual base) // CHECK-NEXT: 16 | int n // CHECK-NEXT: | [sizeof=24, dsize=20, align=8, // CHECK-NEXT: | nvsize=16, nvalign=8] struct D : virtual V { [[no_unique_address]] B b; }; static_assert(sizeof(D) == 24); // CHECK:*** Dumping AST Record Layout // CHECK: 0 | struct NVSizeGreaterThanDSize::D // CHECK-NEXT: 0 | (D vtable pointer) // CHECK-NEXT: 8 | struct NVSizeGreaterThanDSize::B b // CHECK-NEXT: 8 | struct NVSizeGreaterThanDSize::A (base) (empty) // CHECK-NEXT: 8 | char c // CHECK-NEXT: 16 | struct NVSizeGreaterThanDSize::V (virtual base) // CHECK-NEXT: 16 | int n // CHECK-NEXT: | [sizeof=24, dsize=20, align=8, // CHECK-NEXT: | nvsize=16, nvalign=8] struct X : virtual A { [[no_unique_address]] A a; }; struct E : virtual A { [[no_unique_address]] A a; // Here, we arrange for X to hang over the end of the nvsize of E. This // should force the A vbase to be laid out at offset 24, not 16. [[no_unique_address]] X x; }; static_assert(sizeof(E) == 32); // CHECK:*** Dumping AST Record Layout // CHECK: 0 | struct NVSizeGreaterThanDSize::E // CHECK-NEXT: 0 | (E vtable pointer) // CHECK-NEXT: 0 | struct NVSizeGreaterThanDSize::A a (empty) // CHECK-NEXT: 8 | struct NVSizeGreaterThanDSize::X x // CHECK-NEXT: 8 | (X vtable pointer) // CHECK-NEXT: 8 | struct NVSizeGreaterThanDSize::A a (empty) // CHECK-NEXT: 16 | struct NVSizeGreaterThanDSize::A (virtual base) (empty) // CHECK-NEXT: 24 | struct NVSizeGreaterThanDSize::A (virtual base) (empty) // CHECK-NEXT: | [sizeof=32, dsize=16, align=8, // CHECK-NEXT: | nvsize=16, nvalign=8] } namespace RepeatedVBase { struct alignas(16) A { ~A(); }; struct B : A {}; struct X : virtual A, virtual B {}; struct Y { [[no_unique_address]] X x; char c; }; static_assert(sizeof(Y) == 32); // CHECK:*** Dumping AST Record Layout // CHECK: 0 | struct RepeatedVBase::Y // CHECK-NEXT: 0 | struct RepeatedVBase::X x // CHECK-NEXT: 0 | (X vtable pointer) // CHECK-NEXT: 0 | struct RepeatedVBase::A (virtual base) (empty) // CHECK-NEXT: 16 | struct RepeatedVBase::B (virtual base) (empty) // CHECK-NEXT: 16 | struct RepeatedVBase::A (base) (empty) // CHECK-NEXT: 8 | char c // CHECK-NEXT: | [sizeof=32, dsize=9, align=16, // CHECK-NEXT: | nvsize=9, nvalign=16] }