blob: 0aaf79c27cafd0badcfdc569a609b4beb691e6f3 [file] [edit]
// 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]