1 // RUN: %clang_cc1 -std=c++2a -fsyntax-only -triple x86_64-windows-msvc -fms-compatibility -fdump-record-layouts %s | FileCheck %s 2 3 namespace Empty { 4 struct A {}; 5 struct A2 {}; 6 struct A3 { [[msvc::no_unique_address]] A a; }; 7 struct alignas(8) A4 {}; 8 9 struct B { 10 [[msvc::no_unique_address]] A a; 11 char b; 12 }; 13 static_assert(sizeof(B) == 1); 14 15 // CHECK:*** Dumping AST Record Layout 16 // CHECK: 0 | struct Empty::B 17 // CHECK-NEXT: 0 | struct Empty::A a (empty) 18 // CHECK-NEXT: 0 | char b 19 // CHECK-NEXT: | [sizeof=1, align=1, 20 // CHECK-NEXT: | nvsize=1, nvalign=1] 21 22 struct C { 23 [[msvc::no_unique_address]] A a; 24 [[msvc::no_unique_address]] A2 a2; 25 char c; 26 }; 27 static_assert(sizeof(C) == 1); 28 29 // CHECK:*** Dumping AST Record Layout 30 // CHECK: 0 | struct Empty::C 31 // CHECK-NEXT: 0 | struct Empty::A a (empty) 32 // CHECK-NEXT: 0 | struct Empty::A2 a2 (empty) 33 // CHECK-NEXT: 0 | char c 34 // CHECK-NEXT: | [sizeof=1, align=1, 35 // CHECK-NEXT: | nvsize=1, nvalign=1] 36 37 struct D { 38 [[msvc::no_unique_address]] A3 a; 39 int i; 40 }; 41 static_assert(sizeof(D) == 8); 42 43 // CHECK:*** Dumping AST Record Layout 44 // CHECK: 0 | struct Empty::D 45 // CHECK-NEXT: 0 | struct Empty::A3 a (empty) 46 // CHECK-NEXT: 0 | struct Empty::A a (empty) 47 // CHECK-NEXT: 4 | int i 48 // CHECK-NEXT: | [sizeof=8, align=4, 49 // CHECK-NEXT: | nvsize=8, nvalign=4] 50 51 struct E { 52 [[msvc::no_unique_address]] A a1; 53 [[msvc::no_unique_address]] A a2; 54 char e; 55 }; 56 static_assert(sizeof(E) == 2); 57 58 // CHECK:*** Dumping AST Record Layout 59 // CHECK: 0 | struct Empty::E 60 // CHECK-NEXT: 0 | struct Empty::A a1 (empty) 61 // CHECK-NEXT: 1 | struct Empty::A a2 (empty) 62 // CHECK-NEXT: 0 | char e 63 // CHECK-NEXT: | [sizeof=2, align=1, 64 // CHECK-NEXT: | nvsize=2, nvalign=1] 65 66 struct F { 67 ~F(); 68 [[msvc::no_unique_address]] A a1; 69 [[msvc::no_unique_address]] A a2; 70 char f; 71 }; 72 static_assert(sizeof(F) == 2); 73 74 // CHECK:*** Dumping AST Record Layout 75 // CHECK: 0 | struct Empty::F 76 // CHECK-NEXT: 0 | struct Empty::A a1 (empty) 77 // CHECK-NEXT: 1 | struct Empty::A a2 (empty) 78 // CHECK-NEXT: 0 | char f 79 // CHECK-NEXT: | [sizeof=2, align=1, 80 // CHECK-NEXT: | nvsize=2, nvalign=1] 81 82 struct G { [[msvc::no_unique_address]] A a; ~G(); }; 83 static_assert(sizeof(G) == 1); 84 85 // CHECK:*** Dumping AST Record Layout 86 // CHECK: 0 | struct Empty::G 87 // CHECK-NEXT: 0 | struct Empty::A a (empty) 88 // CHECK-NEXT: | [sizeof=1, align=1, 89 // CHECK-NEXT: | nvsize=1, nvalign=1] 90 91 struct H { 92 [[msvc::no_unique_address]] A a; 93 [[msvc::no_unique_address]] A b; 94 ~H(); 95 }; 96 static_assert(sizeof(H) == 2); 97 98 // CHECK:*** Dumping AST Record Layout 99 // CHECK: 0 | struct Empty::H 100 // CHECK-NEXT: 0 | struct Empty::A a (empty) 101 // CHECK-NEXT: 1 | struct Empty::A b (empty) 102 // CHECK-NEXT: | [sizeof=2, align=1, 103 // CHECK-NEXT: | nvsize=2, nvalign=1] 104 105 struct I { 106 [[msvc::no_unique_address]] A4 a; 107 [[msvc::no_unique_address]] A4 b; 108 }; 109 static_assert(sizeof(I) == 16); 110 111 // CHECK:*** Dumping AST Record Layout 112 // CHECK: 0 | struct Empty::I 113 // CHECK-NEXT: 0 | struct Empty::A4 a (empty) 114 // CHECK-NEXT: 8 | struct Empty::A4 b (empty) 115 // CHECK-NEXT: | [sizeof=16, align=8, 116 // CHECK-NEXT: | nvsize=16, nvalign=8] 117 118 struct J { 119 [[msvc::no_unique_address]] A4 a; 120 A4 b; 121 }; 122 static_assert(sizeof(J) == 16); 123 124 // MSVC puts a and b at the same offset. 125 // CHECK:*** Dumping AST Record Layout 126 // CHECK: 0 | struct Empty::J 127 // CHECK-NEXT: 0 | struct Empty::A4 a (empty) 128 // CHECK-NEXT: 8 | struct Empty::A4 b (empty) 129 // CHECK-NEXT: | [sizeof=16, align=8, 130 // CHECK-NEXT: | nvsize=16, nvalign=8] 131 132 struct K { 133 [[msvc::no_unique_address]] A4 a; 134 [[msvc::no_unique_address]] char c; 135 [[msvc::no_unique_address]] A4 b; 136 }; 137 static_assert(sizeof(K) == 16); 138 139 // CHECK:*** Dumping AST Record Layout 140 // CHECK: 0 | struct Empty::K 141 // CHECK-NEXT: 0 | struct Empty::A4 a (empty) 142 // CHECK-NEXT: 0 | char c 143 // CHECK-NEXT: 8 | struct Empty::A4 b (empty) 144 // CHECK-NEXT: | [sizeof=16, align=8, 145 // CHECK-NEXT: | nvsize=16, nvalign=8] 146 147 struct OversizedEmpty : A { 148 ~OversizedEmpty(); 149 [[msvc::no_unique_address]] A a; 150 }; 151 static_assert(sizeof(OversizedEmpty) == 1); 152 153 // CHECK:*** Dumping AST Record Layout 154 // CHECK: 0 | struct Empty::OversizedEmpty 155 // CHECK-NEXT: 0 | struct Empty::A (base) (empty) 156 // CHECK-NEXT: 0 | struct Empty::A a (empty) 157 // CHECK-NEXT: | [sizeof=1, align=1, 158 // CHECK-NEXT: | nvsize=1, nvalign=1] 159 160 struct HasOversizedEmpty { 161 [[msvc::no_unique_address]] OversizedEmpty m; 162 }; 163 static_assert(sizeof(HasOversizedEmpty) == 1); 164 165 // CHECK:*** Dumping AST Record Layout 166 // CHECK: 0 | struct Empty::HasOversizedEmpty 167 // CHECK-NEXT: 0 | struct Empty::OversizedEmpty m (empty) 168 // CHECK-NEXT: 0 | struct Empty::A (base) (empty) 169 // CHECK-NEXT: 0 | struct Empty::A a (empty) 170 // CHECK-NEXT: | [sizeof=1, align=1, 171 // CHECK-NEXT: | nvsize=1, nvalign=1] 172 173 struct EmptyWithNonzeroDSize { 174 [[msvc::no_unique_address]] A a; 175 int x; 176 [[msvc::no_unique_address]] A b; 177 int y; 178 [[msvc::no_unique_address]] A c; 179 }; 180 static_assert(sizeof(EmptyWithNonzeroDSize) == 8); 181 182 // CHECK:*** Dumping AST Record Layout 183 // CHECK: 0 | struct Empty::EmptyWithNonzeroDSize 184 // CHECK-NEXT: 0 | struct Empty::A a (empty) 185 // CHECK-NEXT: 0 | int x 186 // CHECK-NEXT: 1 | struct Empty::A b (empty) 187 // CHECK-NEXT: 4 | int y 188 // CHECK-NEXT: 2 | struct Empty::A c (empty) 189 // CHECK-NEXT: | [sizeof=8, align=4, 190 // CHECK-NEXT: | nvsize=8, nvalign=4] 191 192 struct EmptyWithNonzeroDSizeNonPOD { 193 ~EmptyWithNonzeroDSizeNonPOD(); 194 [[msvc::no_unique_address]] A a; 195 int x; 196 [[msvc::no_unique_address]] A b; 197 int y; 198 [[msvc::no_unique_address]] A c; 199 }; 200 static_assert(sizeof(EmptyWithNonzeroDSizeNonPOD) == 8); 201 202 // CHECK:*** Dumping AST Record Layout 203 // CHECK: 0 | struct Empty::EmptyWithNonzeroDSizeNonPOD 204 // CHECK-NEXT: 0 | struct Empty::A a (empty) 205 // CHECK-NEXT: 0 | int x 206 // CHECK-NEXT: 1 | struct Empty::A b (empty) 207 // CHECK-NEXT: 4 | int y 208 // CHECK-NEXT: 2 | struct Empty::A c (empty) 209 // CHECK-NEXT: | [sizeof=8, align=4, 210 // CHECK-NEXT: | nvsize=8, nvalign=4] 211 } 212 213 namespace POD { 214 struct A { int n; char c[3]; }; 215 struct B { [[msvc::no_unique_address]] A a; char d; }; 216 static_assert(sizeof(B) == 12); 217 218 // CHECK:*** Dumping AST Record Layout 219 // CHECK: 0 | struct POD::B 220 // CHECK-NEXT: 0 | struct POD::A a 221 // CHECK-NEXT: 0 | int n 222 // CHECK-NEXT: 4 | char[3] c 223 // CHECK-NEXT: 8 | char d 224 // CHECK-NEXT: | [sizeof=12, align=4, 225 // CHECK-NEXT: | nvsize=12, nvalign=4] 226 } 227 228 namespace NonPOD { 229 struct A { int n; char c[3]; ~A(); }; 230 struct B { [[msvc::no_unique_address]] A a; char d; }; 231 static_assert(sizeof(B) == 12); 232 233 // CHECK:*** Dumping AST Record Layout 234 // CHECK: 0 | struct NonPOD::B 235 // CHECK-NEXT: 0 | struct NonPOD::A a 236 // CHECK-NEXT: 0 | int n 237 // CHECK-NEXT: 4 | char[3] c 238 // CHECK-NEXT: 8 | char d 239 // CHECK-NEXT: | [sizeof=12, align=4, 240 // CHECK-NEXT: | nvsize=12, nvalign=4] 241 } 242 243 namespace VBases { 244 // The nvsize of an object includes the complete size of its empty subobjects 245 // (although it's unclear why). Ensure this corner case is handled properly. 246 struct Empty {}; 247 struct alignas(8) A {}; // dsize 0, nvsize 0, size 8 248 struct B : A { char c; }; // dsize 1, nvsize 8, size 8 249 static_assert(sizeof(B) == 8); 250 251 // CHECK:*** Dumping AST Record Layout 252 // CHECK: 0 | struct VBases::B 253 // CHECK-NEXT: 0 | struct VBases::A (base) (empty) 254 // CHECK-NEXT: 0 | char c 255 // CHECK-NEXT: | [sizeof=8, align=8, 256 // CHECK-NEXT: | nvsize=8, nvalign=8] 257 258 struct V { int n; }; 259 260 struct C : B, virtual V {}; 261 static_assert(sizeof(C) == 24); 262 263 // CHECK:*** Dumping AST Record Layout 264 // CHECK: 0 | struct VBases::C 265 // CHECK-NEXT: 0 | struct VBases::B (base) 266 // CHECK-NEXT: 0 | struct VBases::A (base) (empty) 267 // CHECK-NEXT: 0 | char c 268 // CHECK-NEXT: 8 | (C vbtable pointer) 269 // CHECK-NEXT: 16 | struct VBases::V (virtual base) 270 // CHECK-NEXT: 16 | int n 271 // CHECK-NEXT: | [sizeof=24, align=8, 272 // CHECK-NEXT: | nvsize=16, nvalign=8] 273 274 struct D : virtual Empty { 275 [[msvc::no_unique_address]] Empty a; 276 }; 277 static_assert(sizeof(D) == 16); 278 279 // CHECK:*** Dumping AST Record Layout 280 // CHECK: 0 | struct VBases::D 281 // CHECK-NEXT: 0 | (D vbtable pointer) 282 // CHECK-NEXT: 8 | struct VBases::Empty a 283 // CHECK-NEXT: 16 | struct VBases::Empty (virtual base) (empty) 284 // CHECK-NEXT: | [sizeof=16, align=8, 285 // CHECK-NEXT: | nvsize=16, nvalign=8] 286 287 struct E : virtual V { 288 [[msvc::no_unique_address]] B b; 289 }; 290 static_assert(sizeof(E) == 24); 291 292 // CHECK:*** Dumping AST Record Layout 293 // CHECK: 0 | struct VBases::E 294 // CHECK-NEXT: 0 | (E vbtable pointer) 295 // CHECK-NEXT: 8 | struct VBases::B b 296 // CHECK-NEXT: 8 | struct VBases::A (base) (empty) 297 // CHECK-NEXT: 8 | char c 298 // CHECK-NEXT: 16 | struct VBases::V (virtual base) 299 // CHECK-NEXT: 16 | int n 300 // CHECK-NEXT: | [sizeof=24, align=8, 301 // CHECK-NEXT: | nvsize=16, nvalign=8] 302 303 struct X : virtual A { [[msvc::no_unique_address]] A a; }; 304 struct F : virtual A { 305 [[msvc::no_unique_address]] A a; 306 [[msvc::no_unique_address]] X x; 307 }; 308 static_assert(sizeof(F) == 24); 309 310 // MSVC places x after a and the total size is 48. 311 // CHECK:*** Dumping AST Record Layout 312 // CHECK: 0 | struct VBases::F 313 // CHECK-NEXT: 0 | (F vbtable pointer) 314 // CHECK-NEXT: 8 | struct VBases::A a (empty) 315 // CHECK-NEXT: 8 | struct VBases::X x 316 // CHECK-NEXT: 8 | (X vbtable pointer) 317 // CHECK-NEXT: 16 | struct VBases::A a (empty) 318 // CHECK-NEXT: 24 | struct VBases::A (virtual base) (empty) 319 // CHECK-NEXT: 24 | struct VBases::A (virtual base) (empty) 320 // CHECK-NEXT: | [sizeof=24, align=8, 321 // CHECK-NEXT: | nvsize=24, nvalign=8] 322 323 struct G : virtual Empty { 324 int i; 325 [[msvc::no_unique_address]] A a; 326 }; 327 static_assert(sizeof(G) == 16); 328 329 // MSVC places a at offset 12. 330 // CHECK:*** Dumping AST Record Layout 331 // CHECK: 0 | struct VBases::G 332 // CHECK-NEXT: 0 | (G vbtable pointer) 333 // CHECK-NEXT: 8 | int i 334 // CHECK-NEXT: 8 | struct VBases::A a (empty) 335 // CHECK-NEXT: 16 | struct VBases::Empty (virtual base) (empty) 336 // CHECK-NEXT: | [sizeof=16, align=8, 337 // CHECK-NEXT: | nvsize=16, nvalign=8] 338 } 339 340 namespace ZeroSize { 341 struct empty {}; 342 343 union empty_union {}; 344 345 struct empty_union_container { 346 [[msvc::no_unique_address]] empty_union x; 347 }; 348 349 union union_of_empty { 350 [[msvc::no_unique_address]] empty x; 351 }; 352 353 struct struct_of_empty { 354 [[msvc::no_unique_address]] empty x; 355 }; 356 357 struct union_of_empty_container { 358 [[msvc::no_unique_address]] union_of_empty x; 359 }; 360 static_assert(sizeof(union_of_empty_container) == 1); 361 // CHECK:*** Dumping AST Record Layout 362 // CHECK: 0 | struct ZeroSize::union_of_empty_container 363 // CHECK-NOT: (empty) 364 // CHECK: 0 | union ZeroSize::union_of_empty x (empty) 365 // CHECK: 0 | struct ZeroSize::empty x (empty) 366 // CHECK: | [sizeof=1, align=1, 367 // CHECK: | nvsize=1, nvalign=1] 368 369 struct struct_of_empty_container { 370 [[msvc::no_unique_address]] struct_of_empty x; 371 }; 372 static_assert(sizeof(struct_of_empty_container) == 1); 373 // CHECK:*** Dumping AST Record Layout 374 // CHECK: 0 | struct ZeroSize::struct_of_empty_container 375 // CHECK-NOT: (empty) 376 // CHECK: 0 | struct ZeroSize::struct_of_empty x (empty) 377 // CHECK: 0 | struct ZeroSize::empty x (empty) 378 // CHECK: | [sizeof=1, align=1, 379 // CHECK: | nvsize=1, nvalign=1] 380 381 } 382