1 // RUN: %clang_cc1 -std=c++2a -fsyntax-only -triple x86_64-linux-gnu -fdump-record-layouts %s | FileCheck %s 2 3 namespace Empty { 4 struct A {}; 5 struct B { [[no_unique_address]] A a; char b; }; 6 static_assert(sizeof(B) == 1); 7 8 // CHECK:*** Dumping AST Record Layout 9 // CHECK: 0 | struct Empty::B 10 // CHECK-NEXT: 0 | struct Empty::A a (empty) 11 // CHECK-NEXT: 0 | char b 12 // CHECK-NEXT: | [sizeof=1, dsize=1, align=1, 13 // CHECK-NEXT: | nvsize=1, nvalign=1] 14 15 struct C {}; 16 struct D { 17 [[no_unique_address]] A a; 18 [[no_unique_address]] C c; 19 char d; 20 }; 21 static_assert(sizeof(D) == 1); 22 23 // CHECK:*** Dumping AST Record Layout 24 // CHECK: 0 | struct Empty::D 25 // CHECK-NEXT: 0 | struct Empty::A a (empty) 26 // CHECK-NEXT: 0 | struct Empty::C c (empty) 27 // CHECK-NEXT: 0 | char d 28 // CHECK-NEXT: | [sizeof=1, dsize=1, align=1, 29 // CHECK-NEXT: | nvsize=1, nvalign=1] 30 31 struct E { 32 [[no_unique_address]] A a1; 33 [[no_unique_address]] A a2; 34 char e; 35 }; 36 static_assert(sizeof(E) == 2); 37 38 // CHECK:*** Dumping AST Record Layout 39 // CHECK: 0 | struct Empty::E 40 // CHECK-NEXT: 0 | struct Empty::A a1 (empty) 41 // CHECK-NEXT: 1 | struct Empty::A a2 (empty) 42 // CHECK-NEXT: 0 | char e 43 // CHECK-NEXT: | [sizeof=2, dsize=2, align=1, 44 // CHECK-NEXT: | nvsize=2, nvalign=1] 45 46 struct F { 47 ~F(); 48 [[no_unique_address]] A a1; 49 [[no_unique_address]] A a2; 50 char f; 51 }; 52 static_assert(sizeof(F) == 2); 53 54 // CHECK:*** Dumping AST Record Layout 55 // CHECK: 0 | struct Empty::F 56 // CHECK-NEXT: 0 | struct Empty::A a1 (empty) 57 // CHECK-NEXT: 1 | struct Empty::A a2 (empty) 58 // CHECK-NEXT: 0 | char f 59 // CHECK-NEXT: | [sizeof=2, dsize=1, align=1, 60 // CHECK-NEXT: | nvsize=2, nvalign=1] 61 62 struct G { [[no_unique_address]] A a; ~G(); }; 63 static_assert(sizeof(G) == 1); 64 65 // CHECK:*** Dumping AST Record Layout 66 // CHECK: 0 | struct Empty::G 67 // CHECK-NEXT: 0 | struct Empty::A a (empty) 68 // CHECK-NEXT: | [sizeof=1, dsize=0, align=1, 69 // CHECK-NEXT: | nvsize=1, nvalign=1] 70 71 struct H { [[no_unique_address]] A a, b; ~H(); }; 72 static_assert(sizeof(H) == 2); 73 74 // CHECK:*** Dumping AST Record Layout 75 // CHECK: 0 | struct Empty::H 76 // CHECK-NEXT: 0 | struct Empty::A a (empty) 77 // CHECK-NEXT: 1 | struct Empty::A b (empty) 78 // CHECK-NEXT: | [sizeof=2, dsize=0, align=1, 79 // CHECK-NEXT: | nvsize=2, nvalign=1] 80 81 struct OversizedEmpty : A { 82 ~OversizedEmpty(); 83 [[no_unique_address]] A a; 84 }; 85 static_assert(sizeof(OversizedEmpty) == 2); 86 87 // CHECK:*** Dumping AST Record Layout 88 // CHECK: 0 | struct Empty::OversizedEmpty 89 // CHECK-NEXT: 0 | struct Empty::A (base) (empty) 90 // CHECK-NEXT: 1 | struct Empty::A a (empty) 91 // CHECK-NEXT: | [sizeof=2, dsize=0, align=1, 92 // CHECK-NEXT: | nvsize=2, nvalign=1] 93 94 struct HasOversizedEmpty { 95 [[no_unique_address]] OversizedEmpty m; 96 }; 97 static_assert(sizeof(HasOversizedEmpty) == 2); 98 99 // CHECK:*** Dumping AST Record Layout 100 // CHECK: 0 | struct Empty::HasOversizedEmpty 101 // CHECK-NEXT: 0 | struct Empty::OversizedEmpty m (empty) 102 // CHECK-NEXT: 0 | struct Empty::A (base) (empty) 103 // CHECK-NEXT: 1 | struct Empty::A a (empty) 104 // CHECK-NEXT: | [sizeof=2, dsize=0, align=1, 105 // CHECK-NEXT: | nvsize=2, nvalign=1] 106 107 struct EmptyWithNonzeroDSize { 108 [[no_unique_address]] A a; 109 int x; 110 [[no_unique_address]] A b; 111 int y; 112 [[no_unique_address]] A c; 113 }; 114 static_assert(sizeof(EmptyWithNonzeroDSize) == 12); 115 116 // CHECK:*** Dumping AST Record Layout 117 // CHECK: 0 | struct Empty::EmptyWithNonzeroDSize 118 // CHECK-NEXT: 0 | struct Empty::A a (empty) 119 // CHECK-NEXT: 0 | int x 120 // CHECK-NEXT: 4 | struct Empty::A b (empty) 121 // CHECK-NEXT: 4 | int y 122 // CHECK-NEXT: 8 | struct Empty::A c (empty) 123 // CHECK-NEXT: | [sizeof=12, dsize=12, align=4, 124 // CHECK-NEXT: | nvsize=12, nvalign=4] 125 126 struct EmptyWithNonzeroDSizeNonPOD { 127 ~EmptyWithNonzeroDSizeNonPOD(); 128 [[no_unique_address]] A a; 129 int x; 130 [[no_unique_address]] A b; 131 int y; 132 [[no_unique_address]] A c; 133 }; 134 static_assert(sizeof(EmptyWithNonzeroDSizeNonPOD) == 12); 135 136 // CHECK:*** Dumping AST Record Layout 137 // CHECK: 0 | struct Empty::EmptyWithNonzeroDSizeNonPOD 138 // CHECK-NEXT: 0 | struct Empty::A a (empty) 139 // CHECK-NEXT: 0 | int x 140 // CHECK-NEXT: 4 | struct Empty::A b (empty) 141 // CHECK-NEXT: 4 | int y 142 // CHECK-NEXT: 8 | struct Empty::A c (empty) 143 // CHECK-NEXT: | [sizeof=12, dsize=8, align=4, 144 // CHECK-NEXT: | nvsize=9, nvalign=4] 145 } 146 147 namespace POD { 148 // Cannot reuse tail padding of a PDO type. 149 struct A { int n; char c[3]; }; 150 struct B { [[no_unique_address]] A a; char d; }; 151 static_assert(sizeof(B) == 12); 152 153 // CHECK:*** Dumping AST Record Layout 154 // CHECK: 0 | struct POD::B 155 // CHECK-NEXT: 0 | struct POD::A a 156 // CHECK-NEXT: 0 | int n 157 // CHECK-NEXT: 4 | char[3] c 158 // CHECK-NEXT: 8 | char d 159 // CHECK-NEXT: | [sizeof=12, dsize=12, align=4, 160 // CHECK-NEXT: | nvsize=12, nvalign=4] 161 } 162 163 namespace NonPOD { 164 struct A { int n; char c[3]; ~A(); }; 165 struct B { [[no_unique_address]] A a; char d; }; 166 static_assert(sizeof(B) == 8); 167 168 // CHECK:*** Dumping AST Record Layout 169 // CHECK: 0 | struct NonPOD::B 170 // CHECK-NEXT: 0 | struct NonPOD::A a 171 // CHECK-NEXT: 0 | int n 172 // CHECK-NEXT: 4 | char[3] c 173 // CHECK-NEXT: 7 | char d 174 // CHECK-NEXT: | [sizeof=8, dsize=8, align=4, 175 // CHECK-NEXT: | nvsize=8, nvalign=4] 176 } 177 178 namespace NVSizeGreaterThanDSize { 179 // The nvsize of an object includes the complete size of its empty subobjects 180 // (although it's unclear why). Ensure this corner case is handled properly. 181 struct alignas(8) A { ~A(); }; // dsize 0, nvsize 0, size 8 182 struct B : A { char c; }; // dsize 1, nvsize 8, size 8 183 static_assert(sizeof(B) == 8); 184 185 // CHECK:*** Dumping AST Record Layout 186 // CHECK: 0 | struct NVSizeGreaterThanDSize::B 187 // CHECK-NEXT: 0 | struct NVSizeGreaterThanDSize::A (base) (empty) 188 // CHECK-NEXT: 0 | char c 189 // CHECK-NEXT: | [sizeof=8, dsize=1, align=8, 190 // CHECK-NEXT: | nvsize=8, nvalign=8] 191 192 struct V { int n; }; 193 194 // V is at offset 16, not offset 12, because B's tail padding is strangely not 195 // usable for virtual bases. 196 struct C : B, virtual V {}; 197 static_assert(sizeof(C) == 24); 198 199 // CHECK:*** Dumping AST Record Layout 200 // CHECK: 0 | struct NVSizeGreaterThanDSize::C 201 // CHECK-NEXT: 0 | (C vtable pointer) 202 // CHECK-NEXT: 8 | struct NVSizeGreaterThanDSize::B (base) 203 // CHECK-NEXT: 8 | struct NVSizeGreaterThanDSize::A (base) (empty) 204 // CHECK-NEXT: 8 | char c 205 // CHECK-NEXT: 16 | struct NVSizeGreaterThanDSize::V (virtual base) 206 // CHECK-NEXT: 16 | int n 207 // CHECK-NEXT: | [sizeof=24, dsize=20, align=8, 208 // CHECK-NEXT: | nvsize=16, nvalign=8] 209 210 struct D : virtual V { 211 [[no_unique_address]] B b; 212 }; 213 static_assert(sizeof(D) == 24); 214 215 // CHECK:*** Dumping AST Record Layout 216 // CHECK: 0 | struct NVSizeGreaterThanDSize::D 217 // CHECK-NEXT: 0 | (D vtable pointer) 218 // CHECK-NEXT: 8 | struct NVSizeGreaterThanDSize::B b 219 // CHECK-NEXT: 8 | struct NVSizeGreaterThanDSize::A (base) (empty) 220 // CHECK-NEXT: 8 | char c 221 // CHECK-NEXT: 16 | struct NVSizeGreaterThanDSize::V (virtual base) 222 // CHECK-NEXT: 16 | int n 223 // CHECK-NEXT: | [sizeof=24, dsize=20, align=8, 224 // CHECK-NEXT: | nvsize=16, nvalign=8] 225 226 struct X : virtual A { [[no_unique_address]] A a; }; 227 struct E : virtual A { 228 [[no_unique_address]] A a; 229 // Here, we arrange for X to hang over the end of the nvsize of E. This 230 // should force the A vbase to be laid out at offset 24, not 16. 231 [[no_unique_address]] X x; 232 }; 233 static_assert(sizeof(E) == 32); 234 235 // CHECK:*** Dumping AST Record Layout 236 // CHECK: 0 | struct NVSizeGreaterThanDSize::E 237 // CHECK-NEXT: 0 | (E vtable pointer) 238 // CHECK-NEXT: 0 | struct NVSizeGreaterThanDSize::A a (empty) 239 // CHECK-NEXT: 8 | struct NVSizeGreaterThanDSize::X x 240 // CHECK-NEXT: 8 | (X vtable pointer) 241 // CHECK-NEXT: 8 | struct NVSizeGreaterThanDSize::A a (empty) 242 // CHECK-NEXT: 16 | struct NVSizeGreaterThanDSize::A (virtual base) (empty) 243 // CHECK-NEXT: 24 | struct NVSizeGreaterThanDSize::A (virtual base) (empty) 244 // CHECK-NEXT: | [sizeof=32, dsize=16, align=8, 245 // CHECK-NEXT: | nvsize=16, nvalign=8] 246 } 247 248 namespace RepeatedVBase { 249 struct alignas(16) A { ~A(); }; 250 struct B : A {}; 251 struct X : virtual A, virtual B {}; 252 struct Y { [[no_unique_address]] X x; char c; }; 253 static_assert(sizeof(Y) == 32); 254 255 // CHECK:*** Dumping AST Record Layout 256 // CHECK: 0 | struct RepeatedVBase::Y 257 // CHECK-NEXT: 0 | struct RepeatedVBase::X x 258 // CHECK-NEXT: 0 | (X vtable pointer) 259 // CHECK-NEXT: 0 | struct RepeatedVBase::A (virtual base) (empty) 260 // CHECK-NEXT: 16 | struct RepeatedVBase::B (virtual base) (empty) 261 // CHECK-NEXT: 16 | struct RepeatedVBase::A (base) (empty) 262 // CHECK-NEXT: 8 | char c 263 // CHECK-NEXT: | [sizeof=32, dsize=9, align=16, 264 // CHECK-NEXT: | nvsize=9, nvalign=16] 265 } 266