383 lines · cpp
1// RUN: %clang_cc1 -std=c++2a -fsyntax-only -triple x86_64-windows-msvc -fms-compatibility -fdump-record-layouts %s | FileCheck %s2// RUN: %clang_cc1 -std=c++2a -fsyntax-only -triple x86_64-uefi -fms-compatibility -fdump-record-layouts %s | FileCheck %s3 4namespace Empty {5 struct A {};6 struct A2 {};7 struct A3 { [[msvc::no_unique_address]] A a; };8 struct alignas(8) A4 {};9 10 struct B {11 [[msvc::no_unique_address]] A a;12 char b;13 };14 static_assert(sizeof(B) == 1);15 16 // CHECK:*** Dumping AST Record Layout17 // CHECK: 0 | struct Empty::B18 // CHECK-NEXT: 0 | struct Empty::A a (empty)19 // CHECK-NEXT: 0 | char b20 // CHECK-NEXT: | [sizeof=1, align=1,21 // CHECK-NEXT: | nvsize=1, nvalign=1]22 23 struct C {24 [[msvc::no_unique_address]] A a;25 [[msvc::no_unique_address]] A2 a2;26 char c;27 };28 static_assert(sizeof(C) == 1);29 30 // CHECK:*** Dumping AST Record Layout31 // CHECK: 0 | struct Empty::C32 // CHECK-NEXT: 0 | struct Empty::A a (empty)33 // CHECK-NEXT: 0 | struct Empty::A2 a2 (empty)34 // CHECK-NEXT: 0 | char c35 // CHECK-NEXT: | [sizeof=1, align=1,36 // CHECK-NEXT: | nvsize=1, nvalign=1]37 38 struct D {39 [[msvc::no_unique_address]] A3 a;40 int i;41 };42 static_assert(sizeof(D) == 8);43 44 // CHECK:*** Dumping AST Record Layout45 // CHECK: 0 | struct Empty::D46 // CHECK-NEXT: 0 | struct Empty::A3 a (empty)47 // CHECK-NEXT: 0 | struct Empty::A a (empty)48 // CHECK-NEXT: 4 | int i49 // CHECK-NEXT: | [sizeof=8, align=4,50 // CHECK-NEXT: | nvsize=8, nvalign=4]51 52 struct E {53 [[msvc::no_unique_address]] A a1;54 [[msvc::no_unique_address]] A a2;55 char e;56 };57 static_assert(sizeof(E) == 2);58 59 // CHECK:*** Dumping AST Record Layout60 // CHECK: 0 | struct Empty::E61 // CHECK-NEXT: 0 | struct Empty::A a1 (empty)62 // CHECK-NEXT: 1 | struct Empty::A a2 (empty)63 // CHECK-NEXT: 0 | char e64 // CHECK-NEXT: | [sizeof=2, align=1,65 // CHECK-NEXT: | nvsize=2, nvalign=1]66 67 struct F {68 ~F();69 [[msvc::no_unique_address]] A a1;70 [[msvc::no_unique_address]] A a2;71 char f;72 };73 static_assert(sizeof(F) == 2);74 75 // CHECK:*** Dumping AST Record Layout76 // CHECK: 0 | struct Empty::F77 // CHECK-NEXT: 0 | struct Empty::A a1 (empty)78 // CHECK-NEXT: 1 | struct Empty::A a2 (empty)79 // CHECK-NEXT: 0 | char f80 // CHECK-NEXT: | [sizeof=2, align=1,81 // CHECK-NEXT: | nvsize=2, nvalign=1]82 83 struct G { [[msvc::no_unique_address]] A a; ~G(); };84 static_assert(sizeof(G) == 1);85 86 // CHECK:*** Dumping AST Record Layout87 // CHECK: 0 | struct Empty::G88 // CHECK-NEXT: 0 | struct Empty::A a (empty)89 // CHECK-NEXT: | [sizeof=1, align=1,90 // CHECK-NEXT: | nvsize=1, nvalign=1]91 92 struct H {93 [[msvc::no_unique_address]] A a;94 [[msvc::no_unique_address]] A b;95 ~H();96 };97 static_assert(sizeof(H) == 2);98 99 // CHECK:*** Dumping AST Record Layout100 // CHECK: 0 | struct Empty::H101 // CHECK-NEXT: 0 | struct Empty::A a (empty)102 // CHECK-NEXT: 1 | struct Empty::A b (empty)103 // CHECK-NEXT: | [sizeof=2, align=1,104 // CHECK-NEXT: | nvsize=2, nvalign=1]105 106 struct I {107 [[msvc::no_unique_address]] A4 a;108 [[msvc::no_unique_address]] A4 b;109 };110 static_assert(sizeof(I) == 16);111 112 // CHECK:*** Dumping AST Record Layout113 // CHECK: 0 | struct Empty::I114 // CHECK-NEXT: 0 | struct Empty::A4 a (empty)115 // CHECK-NEXT: 8 | struct Empty::A4 b (empty)116 // CHECK-NEXT: | [sizeof=16, align=8,117 // CHECK-NEXT: | nvsize=16, nvalign=8]118 119 struct J {120 [[msvc::no_unique_address]] A4 a;121 A4 b;122 };123 static_assert(sizeof(J) == 16);124 125 // MSVC puts a and b at the same offset.126 // CHECK:*** Dumping AST Record Layout127 // CHECK: 0 | struct Empty::J128 // CHECK-NEXT: 0 | struct Empty::A4 a (empty)129 // CHECK-NEXT: 8 | struct Empty::A4 b (empty)130 // CHECK-NEXT: | [sizeof=16, align=8,131 // CHECK-NEXT: | nvsize=16, nvalign=8]132 133 struct K {134 [[msvc::no_unique_address]] A4 a;135 [[msvc::no_unique_address]] char c;136 [[msvc::no_unique_address]] A4 b;137 };138 static_assert(sizeof(K) == 16);139 140 // CHECK:*** Dumping AST Record Layout141 // CHECK: 0 | struct Empty::K142 // CHECK-NEXT: 0 | struct Empty::A4 a (empty)143 // CHECK-NEXT: 0 | char c144 // CHECK-NEXT: 8 | struct Empty::A4 b (empty)145 // CHECK-NEXT: | [sizeof=16, align=8,146 // CHECK-NEXT: | nvsize=16, nvalign=8]147 148 struct OversizedEmpty : A {149 ~OversizedEmpty();150 [[msvc::no_unique_address]] A a;151 };152 static_assert(sizeof(OversizedEmpty) == 1);153 154 // CHECK:*** Dumping AST Record Layout155 // CHECK: 0 | struct Empty::OversizedEmpty156 // CHECK-NEXT: 0 | struct Empty::A (base) (empty)157 // CHECK-NEXT: 0 | struct Empty::A a (empty)158 // CHECK-NEXT: | [sizeof=1, align=1,159 // CHECK-NEXT: | nvsize=1, nvalign=1]160 161 struct HasOversizedEmpty {162 [[msvc::no_unique_address]] OversizedEmpty m;163 };164 static_assert(sizeof(HasOversizedEmpty) == 1);165 166 // CHECK:*** Dumping AST Record Layout167 // CHECK: 0 | struct Empty::HasOversizedEmpty168 // CHECK-NEXT: 0 | struct Empty::OversizedEmpty m (empty)169 // CHECK-NEXT: 0 | struct Empty::A (base) (empty)170 // CHECK-NEXT: 0 | struct Empty::A a (empty)171 // CHECK-NEXT: | [sizeof=1, align=1,172 // CHECK-NEXT: | nvsize=1, nvalign=1]173 174 struct EmptyWithNonzeroDSize {175 [[msvc::no_unique_address]] A a;176 int x;177 [[msvc::no_unique_address]] A b;178 int y;179 [[msvc::no_unique_address]] A c;180 };181 static_assert(sizeof(EmptyWithNonzeroDSize) == 8);182 183 // CHECK:*** Dumping AST Record Layout184 // CHECK: 0 | struct Empty::EmptyWithNonzeroDSize185 // CHECK-NEXT: 0 | struct Empty::A a (empty)186 // CHECK-NEXT: 0 | int x187 // CHECK-NEXT: 1 | struct Empty::A b (empty)188 // CHECK-NEXT: 4 | int y189 // CHECK-NEXT: 2 | struct Empty::A c (empty)190 // CHECK-NEXT: | [sizeof=8, align=4,191 // CHECK-NEXT: | nvsize=8, nvalign=4]192 193 struct EmptyWithNonzeroDSizeNonPOD {194 ~EmptyWithNonzeroDSizeNonPOD();195 [[msvc::no_unique_address]] A a;196 int x;197 [[msvc::no_unique_address]] A b;198 int y;199 [[msvc::no_unique_address]] A c;200 };201 static_assert(sizeof(EmptyWithNonzeroDSizeNonPOD) == 8);202 203 // CHECK:*** Dumping AST Record Layout204 // CHECK: 0 | struct Empty::EmptyWithNonzeroDSizeNonPOD205 // CHECK-NEXT: 0 | struct Empty::A a (empty)206 // CHECK-NEXT: 0 | int x207 // CHECK-NEXT: 1 | struct Empty::A b (empty)208 // CHECK-NEXT: 4 | int y209 // CHECK-NEXT: 2 | struct Empty::A c (empty)210 // CHECK-NEXT: | [sizeof=8, align=4,211 // CHECK-NEXT: | nvsize=8, nvalign=4]212}213 214namespace POD {215 struct A { int n; char c[3]; };216 struct B { [[msvc::no_unique_address]] A a; char d; };217 static_assert(sizeof(B) == 12);218 219 // CHECK:*** Dumping AST Record Layout220 // CHECK: 0 | struct POD::B221 // CHECK-NEXT: 0 | struct POD::A a222 // CHECK-NEXT: 0 | int n223 // CHECK-NEXT: 4 | char[3] c224 // CHECK-NEXT: 8 | char d225 // CHECK-NEXT: | [sizeof=12, align=4,226 // CHECK-NEXT: | nvsize=12, nvalign=4]227}228 229namespace NonPOD {230 struct A { int n; char c[3]; ~A(); };231 struct B { [[msvc::no_unique_address]] A a; char d; };232 static_assert(sizeof(B) == 12);233 234 // CHECK:*** Dumping AST Record Layout235 // CHECK: 0 | struct NonPOD::B236 // CHECK-NEXT: 0 | struct NonPOD::A a237 // CHECK-NEXT: 0 | int n238 // CHECK-NEXT: 4 | char[3] c239 // CHECK-NEXT: 8 | char d240 // CHECK-NEXT: | [sizeof=12, align=4,241 // CHECK-NEXT: | nvsize=12, nvalign=4]242}243 244namespace VBases {245 // The nvsize of an object includes the complete size of its empty subobjects246 // (although it's unclear why). Ensure this corner case is handled properly.247 struct Empty {};248 struct alignas(8) A {}; // dsize 0, nvsize 0, size 8249 struct B : A { char c; }; // dsize 1, nvsize 8, size 8250 static_assert(sizeof(B) == 8);251 252 // CHECK:*** Dumping AST Record Layout253 // CHECK: 0 | struct VBases::B254 // CHECK-NEXT: 0 | struct VBases::A (base) (empty)255 // CHECK-NEXT: 0 | char c256 // CHECK-NEXT: | [sizeof=8, align=8,257 // CHECK-NEXT: | nvsize=8, nvalign=8]258 259 struct V { int n; };260 261 struct C : B, virtual V {};262 static_assert(sizeof(C) == 24);263 264 // CHECK:*** Dumping AST Record Layout265 // CHECK: 0 | struct VBases::C266 // CHECK-NEXT: 0 | struct VBases::B (base)267 // CHECK-NEXT: 0 | struct VBases::A (base) (empty)268 // CHECK-NEXT: 0 | char c269 // CHECK-NEXT: 8 | (C vbtable pointer)270 // CHECK-NEXT: 16 | struct VBases::V (virtual base)271 // CHECK-NEXT: 16 | int n272 // CHECK-NEXT: | [sizeof=24, align=8,273 // CHECK-NEXT: | nvsize=16, nvalign=8]274 275 struct D : virtual Empty {276 [[msvc::no_unique_address]] Empty a;277 };278 static_assert(sizeof(D) == 16);279 280 // CHECK:*** Dumping AST Record Layout281 // CHECK: 0 | struct VBases::D282 // CHECK-NEXT: 0 | (D vbtable pointer)283 // CHECK-NEXT: 8 | struct VBases::Empty a284 // CHECK-NEXT: 16 | struct VBases::Empty (virtual base) (empty)285 // CHECK-NEXT: | [sizeof=16, align=8,286 // CHECK-NEXT: | nvsize=16, nvalign=8]287 288 struct E : virtual V {289 [[msvc::no_unique_address]] B b;290 };291 static_assert(sizeof(E) == 24);292 293 // CHECK:*** Dumping AST Record Layout294 // CHECK: 0 | struct VBases::E295 // CHECK-NEXT: 0 | (E vbtable pointer)296 // CHECK-NEXT: 8 | struct VBases::B b297 // CHECK-NEXT: 8 | struct VBases::A (base) (empty)298 // CHECK-NEXT: 8 | char c299 // CHECK-NEXT: 16 | struct VBases::V (virtual base)300 // CHECK-NEXT: 16 | int n301 // CHECK-NEXT: | [sizeof=24, align=8,302 // CHECK-NEXT: | nvsize=16, nvalign=8]303 304 struct X : virtual A { [[msvc::no_unique_address]] A a; };305 struct F : virtual A {306 [[msvc::no_unique_address]] A a;307 [[msvc::no_unique_address]] X x;308 };309 static_assert(sizeof(F) == 24);310 311 // MSVC places x after a and the total size is 48.312 // CHECK:*** Dumping AST Record Layout313 // CHECK: 0 | struct VBases::F314 // CHECK-NEXT: 0 | (F vbtable pointer)315 // CHECK-NEXT: 8 | struct VBases::A a (empty)316 // CHECK-NEXT: 8 | struct VBases::X x317 // CHECK-NEXT: 8 | (X vbtable pointer)318 // CHECK-NEXT: 16 | struct VBases::A a (empty)319 // CHECK-NEXT: 24 | struct VBases::A (virtual base) (empty)320 // CHECK-NEXT: 24 | struct VBases::A (virtual base) (empty)321 // CHECK-NEXT: | [sizeof=24, align=8,322 // CHECK-NEXT: | nvsize=24, nvalign=8]323 324 struct G : virtual Empty {325 int i;326 [[msvc::no_unique_address]] A a;327 };328 static_assert(sizeof(G) == 16);329 330 // MSVC places a at offset 12.331 // CHECK:*** Dumping AST Record Layout332 // CHECK: 0 | struct VBases::G333 // CHECK-NEXT: 0 | (G vbtable pointer)334 // CHECK-NEXT: 8 | int i335 // CHECK-NEXT: 8 | struct VBases::A a (empty)336 // CHECK-NEXT: 16 | struct VBases::Empty (virtual base) (empty)337 // CHECK-NEXT: | [sizeof=16, align=8,338 // CHECK-NEXT: | nvsize=16, nvalign=8]339}340 341namespace ZeroSize {342 struct empty {};343 344 union empty_union {};345 346 struct empty_union_container {347 [[msvc::no_unique_address]] empty_union x;348 };349 350 union union_of_empty {351 [[msvc::no_unique_address]] empty x;352 };353 354 struct struct_of_empty {355 [[msvc::no_unique_address]] empty x;356 };357 358 struct union_of_empty_container {359 [[msvc::no_unique_address]] union_of_empty x;360 };361 static_assert(sizeof(union_of_empty_container) == 1);362 // CHECK:*** Dumping AST Record Layout363 // CHECK: 0 | struct ZeroSize::union_of_empty_container364 // CHECK-NOT: (empty)365 // CHECK: 0 | union ZeroSize::union_of_empty x (empty)366 // CHECK: 0 | struct ZeroSize::empty x (empty)367 // CHECK: | [sizeof=1, align=1,368 // CHECK: | nvsize=1, nvalign=1] 369 370 struct struct_of_empty_container {371 [[msvc::no_unique_address]] struct_of_empty x;372 }; 373 static_assert(sizeof(struct_of_empty_container) == 1);374 // CHECK:*** Dumping AST Record Layout375 // CHECK: 0 | struct ZeroSize::struct_of_empty_container376 // CHECK-NOT: (empty)377 // CHECK: 0 | struct ZeroSize::struct_of_empty x (empty)378 // CHECK: 0 | struct ZeroSize::empty x (empty)379 // CHECK: | [sizeof=1, align=1,380 // CHECK: | nvsize=1, nvalign=1] 381 382}383