382 lines
12 KiB
C++
382 lines
12 KiB
C++
|
// RUN: %clang_cc1 -std=c++2a -fsyntax-only -triple x86_64-windows-msvc -fms-compatibility -fdump-record-layouts %s | FileCheck %s
|
||
|
|
||
|
namespace Empty {
|
||
|
struct A {};
|
||
|
struct A2 {};
|
||
|
struct A3 { [[msvc::no_unique_address]] A a; };
|
||
|
struct alignas(8) A4 {};
|
||
|
|
||
|
struct B {
|
||
|
[[msvc::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, align=1,
|
||
|
// CHECK-NEXT: | nvsize=1, nvalign=1]
|
||
|
|
||
|
struct C {
|
||
|
[[msvc::no_unique_address]] A a;
|
||
|
[[msvc::no_unique_address]] A2 a2;
|
||
|
char c;
|
||
|
};
|
||
|
static_assert(sizeof(C) == 1);
|
||
|
|
||
|
// CHECK:*** Dumping AST Record Layout
|
||
|
// CHECK: 0 | struct Empty::C
|
||
|
// CHECK-NEXT: 0 | struct Empty::A a (empty)
|
||
|
// CHECK-NEXT: 0 | struct Empty::A2 a2 (empty)
|
||
|
// CHECK-NEXT: 0 | char c
|
||
|
// CHECK-NEXT: | [sizeof=1, align=1,
|
||
|
// CHECK-NEXT: | nvsize=1, nvalign=1]
|
||
|
|
||
|
struct D {
|
||
|
[[msvc::no_unique_address]] A3 a;
|
||
|
int i;
|
||
|
};
|
||
|
static_assert(sizeof(D) == 8);
|
||
|
|
||
|
// CHECK:*** Dumping AST Record Layout
|
||
|
// CHECK: 0 | struct Empty::D
|
||
|
// CHECK-NEXT: 0 | struct Empty::A3 a (empty)
|
||
|
// CHECK-NEXT: 0 | struct Empty::A a (empty)
|
||
|
// CHECK-NEXT: 4 | int i
|
||
|
// CHECK-NEXT: | [sizeof=8, align=4,
|
||
|
// CHECK-NEXT: | nvsize=8, nvalign=4]
|
||
|
|
||
|
struct E {
|
||
|
[[msvc::no_unique_address]] A a1;
|
||
|
[[msvc::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, align=1,
|
||
|
// CHECK-NEXT: | nvsize=2, nvalign=1]
|
||
|
|
||
|
struct F {
|
||
|
~F();
|
||
|
[[msvc::no_unique_address]] A a1;
|
||
|
[[msvc::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, align=1,
|
||
|
// CHECK-NEXT: | nvsize=2, nvalign=1]
|
||
|
|
||
|
struct G { [[msvc::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, align=1,
|
||
|
// CHECK-NEXT: | nvsize=1, nvalign=1]
|
||
|
|
||
|
struct H {
|
||
|
[[msvc::no_unique_address]] A a;
|
||
|
[[msvc::no_unique_address]] 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, align=1,
|
||
|
// CHECK-NEXT: | nvsize=2, nvalign=1]
|
||
|
|
||
|
struct I {
|
||
|
[[msvc::no_unique_address]] A4 a;
|
||
|
[[msvc::no_unique_address]] A4 b;
|
||
|
};
|
||
|
static_assert(sizeof(I) == 16);
|
||
|
|
||
|
// CHECK:*** Dumping AST Record Layout
|
||
|
// CHECK: 0 | struct Empty::I
|
||
|
// CHECK-NEXT: 0 | struct Empty::A4 a (empty)
|
||
|
// CHECK-NEXT: 8 | struct Empty::A4 b (empty)
|
||
|
// CHECK-NEXT: | [sizeof=16, align=8,
|
||
|
// CHECK-NEXT: | nvsize=16, nvalign=8]
|
||
|
|
||
|
struct J {
|
||
|
[[msvc::no_unique_address]] A4 a;
|
||
|
A4 b;
|
||
|
};
|
||
|
static_assert(sizeof(J) == 16);
|
||
|
|
||
|
// MSVC puts a and b at the same offset.
|
||
|
// CHECK:*** Dumping AST Record Layout
|
||
|
// CHECK: 0 | struct Empty::J
|
||
|
// CHECK-NEXT: 0 | struct Empty::A4 a (empty)
|
||
|
// CHECK-NEXT: 8 | struct Empty::A4 b (empty)
|
||
|
// CHECK-NEXT: | [sizeof=16, align=8,
|
||
|
// CHECK-NEXT: | nvsize=16, nvalign=8]
|
||
|
|
||
|
struct K {
|
||
|
[[msvc::no_unique_address]] A4 a;
|
||
|
[[msvc::no_unique_address]] char c;
|
||
|
[[msvc::no_unique_address]] A4 b;
|
||
|
};
|
||
|
static_assert(sizeof(K) == 16);
|
||
|
|
||
|
// CHECK:*** Dumping AST Record Layout
|
||
|
// CHECK: 0 | struct Empty::K
|
||
|
// CHECK-NEXT: 0 | struct Empty::A4 a (empty)
|
||
|
// CHECK-NEXT: 0 | char c
|
||
|
// CHECK-NEXT: 8 | struct Empty::A4 b (empty)
|
||
|
// CHECK-NEXT: | [sizeof=16, align=8,
|
||
|
// CHECK-NEXT: | nvsize=16, nvalign=8]
|
||
|
|
||
|
struct OversizedEmpty : A {
|
||
|
~OversizedEmpty();
|
||
|
[[msvc::no_unique_address]] A a;
|
||
|
};
|
||
|
static_assert(sizeof(OversizedEmpty) == 1);
|
||
|
|
||
|
// CHECK:*** Dumping AST Record Layout
|
||
|
// CHECK: 0 | struct Empty::OversizedEmpty
|
||
|
// CHECK-NEXT: 0 | struct Empty::A (base) (empty)
|
||
|
// CHECK-NEXT: 0 | struct Empty::A a (empty)
|
||
|
// CHECK-NEXT: | [sizeof=1, align=1,
|
||
|
// CHECK-NEXT: | nvsize=1, nvalign=1]
|
||
|
|
||
|
struct HasOversizedEmpty {
|
||
|
[[msvc::no_unique_address]] OversizedEmpty m;
|
||
|
};
|
||
|
static_assert(sizeof(HasOversizedEmpty) == 1);
|
||
|
|
||
|
// 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: 0 | struct Empty::A a (empty)
|
||
|
// CHECK-NEXT: | [sizeof=1, align=1,
|
||
|
// CHECK-NEXT: | nvsize=1, nvalign=1]
|
||
|
|
||
|
struct EmptyWithNonzeroDSize {
|
||
|
[[msvc::no_unique_address]] A a;
|
||
|
int x;
|
||
|
[[msvc::no_unique_address]] A b;
|
||
|
int y;
|
||
|
[[msvc::no_unique_address]] A c;
|
||
|
};
|
||
|
static_assert(sizeof(EmptyWithNonzeroDSize) == 8);
|
||
|
|
||
|
// 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: 1 | struct Empty::A b (empty)
|
||
|
// CHECK-NEXT: 4 | int y
|
||
|
// CHECK-NEXT: 2 | struct Empty::A c (empty)
|
||
|
// CHECK-NEXT: | [sizeof=8, align=4,
|
||
|
// CHECK-NEXT: | nvsize=8, nvalign=4]
|
||
|
|
||
|
struct EmptyWithNonzeroDSizeNonPOD {
|
||
|
~EmptyWithNonzeroDSizeNonPOD();
|
||
|
[[msvc::no_unique_address]] A a;
|
||
|
int x;
|
||
|
[[msvc::no_unique_address]] A b;
|
||
|
int y;
|
||
|
[[msvc::no_unique_address]] A c;
|
||
|
};
|
||
|
static_assert(sizeof(EmptyWithNonzeroDSizeNonPOD) == 8);
|
||
|
|
||
|
// 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: 1 | struct Empty::A b (empty)
|
||
|
// CHECK-NEXT: 4 | int y
|
||
|
// CHECK-NEXT: 2 | struct Empty::A c (empty)
|
||
|
// CHECK-NEXT: | [sizeof=8, align=4,
|
||
|
// CHECK-NEXT: | nvsize=8, nvalign=4]
|
||
|
}
|
||
|
|
||
|
namespace POD {
|
||
|
struct A { int n; char c[3]; };
|
||
|
struct B { [[msvc::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, align=4,
|
||
|
// CHECK-NEXT: | nvsize=12, nvalign=4]
|
||
|
}
|
||
|
|
||
|
namespace NonPOD {
|
||
|
struct A { int n; char c[3]; ~A(); };
|
||
|
struct B { [[msvc::no_unique_address]] A a; char d; };
|
||
|
static_assert(sizeof(B) == 12);
|
||
|
|
||
|
// 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: 8 | char d
|
||
|
// CHECK-NEXT: | [sizeof=12, align=4,
|
||
|
// CHECK-NEXT: | nvsize=12, nvalign=4]
|
||
|
}
|
||
|
|
||
|
namespace VBases {
|
||
|
// 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 Empty {};
|
||
|
struct alignas(8) 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 VBases::B
|
||
|
// CHECK-NEXT: 0 | struct VBases::A (base) (empty)
|
||
|
// CHECK-NEXT: 0 | char c
|
||
|
// CHECK-NEXT: | [sizeof=8, align=8,
|
||
|
// CHECK-NEXT: | nvsize=8, nvalign=8]
|
||
|
|
||
|
struct V { int n; };
|
||
|
|
||
|
struct C : B, virtual V {};
|
||
|
static_assert(sizeof(C) == 24);
|
||
|
|
||
|
// CHECK:*** Dumping AST Record Layout
|
||
|
// CHECK: 0 | struct VBases::C
|
||
|
// CHECK-NEXT: 0 | struct VBases::B (base)
|
||
|
// CHECK-NEXT: 0 | struct VBases::A (base) (empty)
|
||
|
// CHECK-NEXT: 0 | char c
|
||
|
// CHECK-NEXT: 8 | (C vbtable pointer)
|
||
|
// CHECK-NEXT: 16 | struct VBases::V (virtual base)
|
||
|
// CHECK-NEXT: 16 | int n
|
||
|
// CHECK-NEXT: | [sizeof=24, align=8,
|
||
|
// CHECK-NEXT: | nvsize=16, nvalign=8]
|
||
|
|
||
|
struct D : virtual Empty {
|
||
|
[[msvc::no_unique_address]] Empty a;
|
||
|
};
|
||
|
static_assert(sizeof(D) == 16);
|
||
|
|
||
|
// CHECK:*** Dumping AST Record Layout
|
||
|
// CHECK: 0 | struct VBases::D
|
||
|
// CHECK-NEXT: 0 | (D vbtable pointer)
|
||
|
// CHECK-NEXT: 8 | struct VBases::Empty a
|
||
|
// CHECK-NEXT: 16 | struct VBases::Empty (virtual base) (empty)
|
||
|
// CHECK-NEXT: | [sizeof=16, align=8,
|
||
|
// CHECK-NEXT: | nvsize=16, nvalign=8]
|
||
|
|
||
|
struct E : virtual V {
|
||
|
[[msvc::no_unique_address]] B b;
|
||
|
};
|
||
|
static_assert(sizeof(E) == 24);
|
||
|
|
||
|
// CHECK:*** Dumping AST Record Layout
|
||
|
// CHECK: 0 | struct VBases::E
|
||
|
// CHECK-NEXT: 0 | (E vbtable pointer)
|
||
|
// CHECK-NEXT: 8 | struct VBases::B b
|
||
|
// CHECK-NEXT: 8 | struct VBases::A (base) (empty)
|
||
|
// CHECK-NEXT: 8 | char c
|
||
|
// CHECK-NEXT: 16 | struct VBases::V (virtual base)
|
||
|
// CHECK-NEXT: 16 | int n
|
||
|
// CHECK-NEXT: | [sizeof=24, align=8,
|
||
|
// CHECK-NEXT: | nvsize=16, nvalign=8]
|
||
|
|
||
|
struct X : virtual A { [[msvc::no_unique_address]] A a; };
|
||
|
struct F : virtual A {
|
||
|
[[msvc::no_unique_address]] A a;
|
||
|
[[msvc::no_unique_address]] X x;
|
||
|
};
|
||
|
static_assert(sizeof(F) == 24);
|
||
|
|
||
|
// MSVC places x after a and the total size is 48.
|
||
|
// CHECK:*** Dumping AST Record Layout
|
||
|
// CHECK: 0 | struct VBases::F
|
||
|
// CHECK-NEXT: 0 | (F vbtable pointer)
|
||
|
// CHECK-NEXT: 8 | struct VBases::A a (empty)
|
||
|
// CHECK-NEXT: 8 | struct VBases::X x
|
||
|
// CHECK-NEXT: 8 | (X vbtable pointer)
|
||
|
// CHECK-NEXT: 16 | struct VBases::A a (empty)
|
||
|
// CHECK-NEXT: 24 | struct VBases::A (virtual base) (empty)
|
||
|
// CHECK-NEXT: 24 | struct VBases::A (virtual base) (empty)
|
||
|
// CHECK-NEXT: | [sizeof=24, align=8,
|
||
|
// CHECK-NEXT: | nvsize=24, nvalign=8]
|
||
|
|
||
|
struct G : virtual Empty {
|
||
|
int i;
|
||
|
[[msvc::no_unique_address]] A a;
|
||
|
};
|
||
|
static_assert(sizeof(G) == 16);
|
||
|
|
||
|
// MSVC places a at offset 12.
|
||
|
// CHECK:*** Dumping AST Record Layout
|
||
|
// CHECK: 0 | struct VBases::G
|
||
|
// CHECK-NEXT: 0 | (G vbtable pointer)
|
||
|
// CHECK-NEXT: 8 | int i
|
||
|
// CHECK-NEXT: 8 | struct VBases::A a (empty)
|
||
|
// CHECK-NEXT: 16 | struct VBases::Empty (virtual base) (empty)
|
||
|
// CHECK-NEXT: | [sizeof=16, align=8,
|
||
|
// CHECK-NEXT: | nvsize=16, nvalign=8]
|
||
|
}
|
||
|
|
||
|
namespace ZeroSize {
|
||
|
struct empty {};
|
||
|
|
||
|
union empty_union {};
|
||
|
|
||
|
struct empty_union_container {
|
||
|
[[msvc::no_unique_address]] empty_union x;
|
||
|
};
|
||
|
|
||
|
union union_of_empty {
|
||
|
[[msvc::no_unique_address]] empty x;
|
||
|
};
|
||
|
|
||
|
struct struct_of_empty {
|
||
|
[[msvc::no_unique_address]] empty x;
|
||
|
};
|
||
|
|
||
|
struct union_of_empty_container {
|
||
|
[[msvc::no_unique_address]] union_of_empty x;
|
||
|
};
|
||
|
static_assert(sizeof(union_of_empty_container) == 1);
|
||
|
// CHECK:*** Dumping AST Record Layout
|
||
|
// CHECK: 0 | struct ZeroSize::union_of_empty_container
|
||
|
// CHECK-NOT: (empty)
|
||
|
// CHECK: 0 | union ZeroSize::union_of_empty x (empty)
|
||
|
// CHECK: 0 | struct ZeroSize::empty x (empty)
|
||
|
// CHECK: | [sizeof=1, align=1,
|
||
|
// CHECK: | nvsize=1, nvalign=1]
|
||
|
|
||
|
struct struct_of_empty_container {
|
||
|
[[msvc::no_unique_address]] struct_of_empty x;
|
||
|
};
|
||
|
static_assert(sizeof(struct_of_empty_container) == 1);
|
||
|
// CHECK:*** Dumping AST Record Layout
|
||
|
// CHECK: 0 | struct ZeroSize::struct_of_empty_container
|
||
|
// CHECK-NOT: (empty)
|
||
|
// CHECK: 0 | struct ZeroSize::struct_of_empty x (empty)
|
||
|
// CHECK: 0 | struct ZeroSize::empty x (empty)
|
||
|
// CHECK: | [sizeof=1, align=1,
|
||
|
// CHECK: | nvsize=1, nvalign=1]
|
||
|
|
||
|
}
|