| // RUN: %clang_cc1 -fno-rtti -fms-extensions -triple aarch64-windows-msvc -fdump-record-layouts -fsyntax-only %s 2>/dev/null \ | |
| // RUN: | FileCheck %s -check-prefix CHECK-ARM64 | |
| // RUN: %clang_cc1 -fno-rtti -fms-extensions -triple arm64ec-windows-msvc -fdump-record-layouts -fsyntax-only %s 2>/dev/null \ | |
| // RUN: | FileCheck %s -check-prefix CHECK-X64 | |
| // RUN: %clang_cc1 -fno-rtti -fms-extensions -triple x86_64-windows-msvc -fdump-record-layouts -fsyntax-only %s 2>/dev/null \ | |
| // RUN: | FileCheck %s -check-prefix CHECK-X64 | |
| // On Arm64 (but not Arm64EC or x64), MSVC reuses the tail padding of an | |
| // over-aligned base class for a subsequent base class. This holds whether the | |
| // over-alignment comes from the record itself or from one of its fields. | |
| struct alignas(16) Type { | |
| long long a, b, c; | |
| }; | |
| struct Mid : Type {}; | |
| struct Node { void *next; }; | |
| // The over-aligned base's tail padding is reused for the following base only on | |
| // Arm64. | |
| struct Derived : Mid, Node {}; | |
| int a = sizeof(Derived); | |
| // CHECK-ARM64-LABEL: 0 | struct Derived | |
| // CHECK-ARM64-NEXT: 0 | struct Mid (base) | |
| // CHECK-ARM64-NEXT: 0 | struct Type (base) | |
| // CHECK-ARM64: 24 | struct Node (base) | |
| // CHECK-ARM64-NEXT: 24 | void * next | |
| // CHECK-ARM64-NEXT: | [sizeof=32, align=16, | |
| // CHECK-ARM64-NEXT: | nvsize=32, nvalign=16] | |
| // CHECK-X64-LABEL: 0 | struct Derived | |
| // CHECK-X64-NEXT: 0 | struct Mid (base) | |
| // CHECK-X64-NEXT: 0 | struct Type (base) | |
| // CHECK-X64: 32 | struct Node (base) | |
| // CHECK-X64-NEXT: 32 | void * next | |
| // CHECK-X64-NEXT: | [sizeof=48, align=16, | |
| // CHECK-X64-NEXT: | nvsize=48, nvalign=16] | |
| // The over-alignment can also come from `alignas` on an individual field rather | |
| // than from the record itself; the tail padding is reused the same way. | |
| struct FieldOver { | |
| alignas(16) long long a; | |
| long long b, c; | |
| }; | |
| struct FieldMid : FieldOver {}; | |
| struct FieldDerived : FieldMid, Node {}; | |
| int b = sizeof(FieldDerived); | |
| // CHECK-ARM64-LABEL: 0 | struct FieldDerived | |
| // CHECK-ARM64-NEXT: 0 | struct FieldMid (base) | |
| // CHECK-ARM64-NEXT: 0 | struct FieldOver (base) | |
| // CHECK-ARM64: 24 | struct Node (base) | |
| // CHECK-ARM64-NEXT: 24 | void * next | |
| // CHECK-ARM64-NEXT: | [sizeof=32, align=16, | |
| // CHECK-ARM64-NEXT: | nvsize=32, nvalign=16] | |
| // CHECK-X64-LABEL: 0 | struct FieldDerived | |
| // CHECK-X64-NEXT: 0 | struct FieldMid (base) | |
| // CHECK-X64-NEXT: 0 | struct FieldOver (base) | |
| // CHECK-X64: 32 | struct Node (base) | |
| // CHECK-X64-NEXT: 32 | void * next | |
| // CHECK-X64-NEXT: | [sizeof=48, align=16, | |
| // CHECK-X64-NEXT: | nvsize=48, nvalign=16] | |
| // Reusing tail padding must not affect placement of an over-aligned base that | |
| // follows another base: padding is still inserted so it lands at its required | |
| // alignment. | |
| struct PadBefore : Node, Type {}; | |
| int c = sizeof(PadBefore); | |
| // CHECK-ARM64-LABEL: 0 | struct PadBefore | |
| // CHECK-ARM64-NEXT: 0 | struct Node (base) | |
| // CHECK-ARM64-NEXT: 0 | void * next | |
| // CHECK-ARM64-NEXT: 16 | struct Type (base) | |
| // CHECK-ARM64: | [sizeof=48, align=16, | |
| // CHECK-X64-LABEL: 0 | struct PadBefore | |
| // CHECK-X64-NEXT: 0 | struct Node (base) | |
| // CHECK-X64-NEXT: 0 | void * next | |
| // CHECK-X64-NEXT: 16 | struct Type (base) | |
| // CHECK-X64: | [sizeof=48, align=16, | |
| // Over-alignment applied directly to a bitfield via __declspec(align) raises | |
| // the record's alignment (rather than its required alignment) and is immune to | |
| // #pragma pack. The over-aligned base tail-padding reuse above does not apply | |
| // to bitfields, so this is left unchanged by that transformation and is handled | |
| // identically on every target. | |
| #pragma pack(2) | |
| struct BitfieldAlign { | |
| __declspec(align(16)) long long a : 8; | |
| }; | |
| #pragma pack() | |
| int d = sizeof(BitfieldAlign); | |
| // CHECK-ARM64-LABEL: 0 | struct BitfieldAlign | |
| // CHECK-ARM64-NEXT: 0:0-7 | long long a | |
| // CHECK-ARM64-NEXT: | [sizeof=8, align=16, | |
| // CHECK-ARM64-NEXT: | nvsize=8, nvalign=16] | |
| // CHECK-X64-LABEL: 0 | struct BitfieldAlign | |
| // CHECK-X64-NEXT: 0:0-7 | long long a | |
| // CHECK-X64-NEXT: | [sizeof=8, align=16, | |
| // CHECK-X64-NEXT: | nvsize=8, nvalign=16] |