[clang] [Clang][Windows] Preserve natural alignment for vector and x86_fp80 arrays under #pragma pack. (PR #208256)
Zahira Ammarguellat via cfe-commits
cfe-commits at lists.llvm.org
Wed Sep 23 07:06:24 PDT 2026
https://github.com/zahiraam updated https://github.com/llvm/llvm-project/pull/208256
>From 4edfb5154f7e43d45a2d16df890b16f4d4fcbb1a Mon Sep 17 00:00:00 2001
From: Zahira Ammarguellat <zahira.ammarguellat at intel.com>
Date: Fri, 28 Aug 2026 08:19:10 -0700
Subject: [PATCH 1/8] Addressed review comments
---
clang/lib/AST/RecordLayoutBuilder.cpp | 196 +++++++++++++++++-
.../pragma-pack-array-alignment-itanium.cpp | 40 ++++
.../pragma-pack-array-alignment-msvc.cpp | 40 ++++
3 files changed, 266 insertions(+), 10 deletions(-)
create mode 100644 clang/test/CodeGen/pragma-pack-array-alignment-itanium.cpp
create mode 100644 clang/test/CodeGen/pragma-pack-array-alignment-msvc.cpp
diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp
index e6da6c78238c13..03a9318547fdea 100644
--- a/clang/lib/AST/RecordLayoutBuilder.cpp
+++ b/clang/lib/AST/RecordLayoutBuilder.cpp
@@ -781,6 +781,13 @@ class ItaniumRecordLayoutBuilder {
UpdateAlignment(NewAlignment, NewAlignment, NewAlignment);
}
+ /// Check if a type contains vector types.
+ bool TypeContainsVectors(QualType Ty);
+
+ /// Get the natural alignment of vectors contained in a type, bypassing
+ /// any pragma pack that may have been applied to enclosing structs.
+ CharUnits GetNaturalVectorAlignment(QualType Ty);
+
/// Retrieve the externally-supplied field offset for the given
/// field.
///
@@ -1688,13 +1695,24 @@ void ItaniumRecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
// But, if there's a #pragma pack in play, that takes precedent over
// even the 'aligned' attribute, for non-zero-width bitfields.
+ // However, pragma pack should not reduce the natural alignment of vector
+ // array elements.
unsigned MaxFieldAlignmentInBits = Context.toBits(MaxFieldAlignment);
if (!MaxFieldAlignment.isZero() && FieldSize) {
- UnpackedFieldAlign = std::min(UnpackedFieldAlign, MaxFieldAlignmentInBits);
- if (FieldPacked)
- FieldAlign = UnpackedFieldAlign;
- else
- FieldAlign = std::min(FieldAlign, MaxFieldAlignmentInBits);
+ QualType FieldType = D->getType();
+ // Only exempt arrays of vectors from pragma pack, not direct vector
+ // fields.
+ bool IsVectorArray =
+ !FieldType->isVectorType() &&
+ FieldType->getBaseElementTypeUnsafe()->isVectorType();
+ if (!IsVectorArray) {
+ UnpackedFieldAlign =
+ std::min(UnpackedFieldAlign, MaxFieldAlignmentInBits);
+ if (FieldPacked)
+ FieldAlign = UnpackedFieldAlign;
+ else
+ FieldAlign = std::min(FieldAlign, MaxFieldAlignmentInBits);
+ }
}
// But, ms_struct just ignores all of that in unions, even explicit
@@ -1910,6 +1928,17 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D,
} else {
setDeclInfo(false /* IsIncompleteArrayType */);
+ // If this is an array containing vectors (directly or in nested
+ // structs), we need to use the natural alignment of the vectors, not the
+ // potentially pragma-pack-clamped alignment from the struct layout.
+ QualType FieldType = D->getType();
+ if (!FieldType->isVectorType() && TypeContainsVectors(FieldType)) {
+ // Get the natural vector alignment, bypassing any pragma pack on
+ // structs.
+ CharUnits VecAlign = GetNaturalVectorAlignment(FieldType);
+ FieldAlign = std::max(FieldAlign, VecAlign);
+ }
+
// A potentially-overlapping field occupies its dsize or nvsize, whichever
// is larger.
if (D->isPotentiallyOverlapping()) {
@@ -2012,6 +2041,16 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D,
const RecordDecl *RD = RT->getDecl();
const ASTRecordLayout &FieldRecord = Context.getASTRecordLayout(RD);
PreferredAlign = FieldRecord.getPreferredAlignment();
+ // If this is an array of records containing vectors, use the
+ // unadjusted alignment to avoid inheriting pragma pack from the nested
+ // struct.
+ QualType BaseQualTy = QualType(BaseTy, 0);
+ if (D->getType() != BaseQualTy && TypeContainsVectors(D->getType())) {
+ FieldAlign =
+ std::max(FieldAlign, FieldRecord.getUnadjustedAlignment());
+ PreferredAlign =
+ std::max(PreferredAlign, FieldRecord.getUnadjustedAlignment());
+ }
}
}
@@ -2029,10 +2068,20 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D,
UnpackedFieldAlign = std::max(UnpackedFieldAlign, MaxAlignmentInChars);
// The maximum field alignment overrides the aligned attribute.
+ // However, pragma pack should not reduce the natural alignment of array
+ // elements that contain vectors (either arrays of vectors, or arrays of
+ // structs containing vectors). Direct vector fields ARE affected by pragma
+ // pack.
if (!MaxFieldAlignment.isZero()) {
- PackedFieldAlign = std::min(PackedFieldAlign, MaxFieldAlignment);
- PreferredAlign = std::min(PreferredAlign, MaxFieldAlignment);
- UnpackedFieldAlign = std::min(UnpackedFieldAlign, MaxFieldAlignment);
+ QualType FieldType = D->getType();
+ // Only exempt arrays containing vectors, not direct vector fields.
+ bool IsArrayContainingVectors =
+ !FieldType->isVectorType() && TypeContainsVectors(FieldType);
+ if (!IsArrayContainingVectors) {
+ PackedFieldAlign = std::min(PackedFieldAlign, MaxFieldAlignment);
+ PreferredAlign = std::min(PreferredAlign, MaxFieldAlignment);
+ UnpackedFieldAlign = std::min(UnpackedFieldAlign, MaxFieldAlignment);
+ }
}
@@ -2210,6 +2259,52 @@ void ItaniumRecordLayoutBuilder::FinishLayout(const NamedDecl *D) {
}
}
+bool ItaniumRecordLayoutBuilder::TypeContainsVectors(QualType Ty) {
+ // Strip through arrays.
+ while (const ArrayType *AT = Context.getAsArrayType(Ty))
+ Ty = AT->getElementType();
+
+ // Direct vector type.
+ if (Ty->isVectorType())
+ return true;
+
+ // Check if it's a record type with vector fields.
+ if (const RecordType *RT = Ty->getAs<RecordType>()) {
+ const RecordDecl *RD = RT->getDecl();
+ for (const FieldDecl *Field : RD->fields()) {
+ if (TypeContainsVectors(Field->getType()))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+CharUnits ItaniumRecordLayoutBuilder::GetNaturalVectorAlignment(QualType Ty) {
+ // Strip through arrays.
+ while (const ArrayType *AT = Context.getAsArrayType(Ty))
+ Ty = AT->getElementType();
+
+ // Direct vector type - get its natural alignment.
+ if (Ty->isVectorType())
+ return Context.getTypeAlignInChars(Ty);
+
+ // Record type - find the maximum vector alignment inside.
+ if (const RecordType *RT = Ty->getAs<RecordType>()) {
+ const RecordDecl *RD = RT->getDecl();
+ CharUnits MaxAlign = CharUnits::One();
+ for (const FieldDecl *Field : RD->fields()) {
+ if (TypeContainsVectors(Field->getType())) {
+ CharUnits FieldVecAlign = GetNaturalVectorAlignment(Field->getType());
+ MaxAlign = std::max(MaxAlign, FieldVecAlign);
+ }
+ }
+ return MaxAlign;
+ }
+
+ return CharUnits::One();
+}
+
void ItaniumRecordLayoutBuilder::UpdateAlignment(
CharUnits NewAlignment, CharUnits UnpackedNewAlignment,
CharUnits PreferredNewAlignment) {
@@ -2614,6 +2709,11 @@ struct MicrosoftRecordLayoutBuilder {
void computeVtorDispSet(
llvm::SmallPtrSetImpl<const CXXRecordDecl *> &HasVtorDispSet,
const CXXRecordDecl *RD) const;
+ /// Check if a type (recursively) contains vector types.
+ bool TypeContainsVectors(QualType Ty);
+ /// Get the natural alignment of vectors contained in a type, bypassing
+ /// any pragma pack that may have been applied to enclosing structs.
+ CharUnits GetNaturalVectorAlignment(QualType Ty);
const ASTContext &Context;
EmptySubobjectMap *EmptySubobjects;
@@ -2680,6 +2780,52 @@ struct MicrosoftRecordLayoutBuilder {
};
} // namespace
+bool MicrosoftRecordLayoutBuilder::TypeContainsVectors(QualType Ty) {
+ // Strip through arrays.
+ while (const ArrayType *AT = Context.getAsArrayType(Ty))
+ Ty = AT->getElementType();
+
+ // Direct vector type.
+ if (Ty->isVectorType())
+ return true;
+
+ // Check if it's a record type with vector fields.
+ if (const RecordType *RT = Ty->getAs<RecordType>()) {
+ const RecordDecl *RD = RT->getDecl();
+ for (const FieldDecl *Field : RD->fields()) {
+ if (TypeContainsVectors(Field->getType()))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+CharUnits MicrosoftRecordLayoutBuilder::GetNaturalVectorAlignment(QualType Ty) {
+ // Strip through arrays.
+ while (const ArrayType *AT = Context.getAsArrayType(Ty))
+ Ty = AT->getElementType();
+
+ // Direct vector type - get its natural alignment.
+ if (Ty->isVectorType())
+ return Context.getTypeAlignInChars(Ty);
+
+ // Record type - find the maximum vector alignment inside.
+ if (const RecordType *RT = Ty->getAs<RecordType>()) {
+ const RecordDecl *RD = RT->getDecl();
+ CharUnits MaxAlign = CharUnits::One();
+ for (const FieldDecl *Field : RD->fields()) {
+ if (TypeContainsVectors(Field->getType())) {
+ CharUnits FieldVecAlign = GetNaturalVectorAlignment(Field->getType());
+ MaxAlign = std::max(MaxAlign, FieldVecAlign);
+ }
+ }
+ return MaxAlign;
+ }
+
+ return CharUnits::One();
+}
+
MicrosoftRecordLayoutBuilder::ElementInfo
MicrosoftRecordLayoutBuilder::getAdjustedElementInfo(
const ASTRecordLayout &Layout) {
@@ -2718,6 +2864,18 @@ MicrosoftRecordLayoutBuilder::getAdjustedElementInfo(
auto TInfo =
Context.getTypeInfoInChars(FD->getType()->getUnqualifiedDesugaredType());
ElementInfo Info{TInfo.Width, TInfo.Align, CharUnits::Zero()};
+
+ // If this is an array containing vectors (directly or in nested
+ // structs), we need to use the natural alignment of the vectors, not the
+ // potentially pragma-pack-clamped alignment from the struct layout.
+ QualType FieldType = FD->getType();
+ if (!FieldType->isVectorType() && TypeContainsVectors(FieldType)) {
+ // Get the natural vector alignment, bypassing any pragma pack on
+ // structs.
+ CharUnits VecAlign = GetNaturalVectorAlignment(FieldType);
+ Info.Alignment = std::max(Info.Alignment, VecAlign);
+ }
+
// Respect align attributes on the field.
CharUnits DirectFieldAlignment =
Context.toCharUnitsFromBits(FD->getMaxAlignment());
@@ -2742,6 +2900,14 @@ MicrosoftRecordLayoutBuilder::getAdjustedElementInfo(
EndsWithZeroSizedObject = Layout.endsWithZeroSizedObject();
FieldTypeRequiredAlignment =
std::max(FieldTypeRequiredAlignment, Layout.getRequiredAlignment());
+ // If this is an array of records containing vectors, use the
+ // unadjusted alignment to avoid inheriting pragma pack from the nested
+ // struct.
+ QualType BaseTy = QualType(FD->getType()->getBaseElementTypeUnsafe(), 0);
+ if (FD->getType() != BaseTy && TypeContainsVectors(FD->getType())) {
+ Info.Alignment =
+ std::max(Info.Alignment, Layout.getUnadjustedAlignment());
+ }
}
// Capture required alignment as a side-effect.
RequiredAlignment =
@@ -2749,8 +2915,18 @@ MicrosoftRecordLayoutBuilder::getAdjustedElementInfo(
std::max(DirectFieldAlignment, FieldTypeRequiredAlignment));
}
// Respect pragma pack, attribute pack and declspec align
- if (!MaxFieldAlignment.isZero())
- Info.Alignment = std::min(Info.Alignment, MaxFieldAlignment);
+ // However, pragma pack should not reduce the natural alignment of array
+ // elements that contain vectors (either arrays of vectors, or arrays of
+ // structs containing vectors). Direct vector fields ARE affected by pragma
+ // pack.
+ if (!MaxFieldAlignment.isZero()) {
+ QualType FieldType = FD->getType();
+ // Only exempt arrays containing vectors, not direct vector fields.
+ bool IsArrayContainingVectors =
+ !FieldType->isVectorType() && TypeContainsVectors(FieldType);
+ if (!IsArrayContainingVectors)
+ Info.Alignment = std::min(Info.Alignment, MaxFieldAlignment);
+ }
if (FD->hasAttr<PackedAttr>())
Info.Alignment = CharUnits::One();
// The alignment used to update the record's alignment excludes over-alignment
diff --git a/clang/test/CodeGen/pragma-pack-array-alignment-itanium.cpp b/clang/test/CodeGen/pragma-pack-array-alignment-itanium.cpp
new file mode 100644
index 00000000000000..bdac5298211659
--- /dev/null
+++ b/clang/test/CodeGen/pragma-pack-array-alignment-itanium.cpp
@@ -0,0 +1,40 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm -o - %s \
+// RUN: | FileCheck %s
+
+// Test that #pragma pack does not reduce natural type alignment for vector types
+// when used as array elements (Itanium ABI).
+
+typedef float __m128 __attribute__((__vector_size__(16)));
+
+// Simple array-like struct with vector type under pragma pack.
+#pragma pack(push, 8)
+template<typename T, unsigned N>
+struct array {
+ T _Elems[N];
+};
+#pragma pack(pop)
+
+// CHECK-LABEL: define {{.*}} @_Z17test_vector_arrayv
+void test_vector_array() {
+ // CHECK: %matrix = alloca %struct.array, align 16
+ array<__m128, 16> matrix;
+ matrix._Elems[0] = (__m128){};
+}
+
+// Struct containing vector under pragma pack.
+#pragma pack(push, 8)
+struct VectorStruct {
+ __m128 vec;
+};
+
+struct ArrayOfVectorStruct {
+ VectorStruct elems[4];
+};
+#pragma pack(pop)
+
+// CHECK-LABEL: define {{.*}} @_Z18test_vector_structv
+void test_vector_struct() {
+ // CHECK: %s = alloca %struct.ArrayOfVectorStruct, align 16
+ ArrayOfVectorStruct s;
+ s.elems[0].vec = (__m128){};
+}
diff --git a/clang/test/CodeGen/pragma-pack-array-alignment-msvc.cpp b/clang/test/CodeGen/pragma-pack-array-alignment-msvc.cpp
new file mode 100644
index 00000000000000..bdea75d3862356
--- /dev/null
+++ b/clang/test/CodeGen/pragma-pack-array-alignment-msvc.cpp
@@ -0,0 +1,40 @@
+// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -fms-extensions \
+// RUN: -emit-llvm -o - %s | FileCheck %s
+
+// Test that #pragma pack does not reduce natural type alignment for vector types
+// when used as array elements (matching MSVC behavior).
+
+typedef float __m128 __attribute__((__vector_size__(16)));
+
+// Simple array-like struct with vector type under pragma pack.
+#pragma pack(push, 8)
+template<typename T, unsigned N>
+struct array {
+ T _Elems[N];
+};
+#pragma pack(pop)
+
+// CHECK-LABEL: define {{.*}} @"?test_vector_array
+void test_vector_array() {
+ // CHECK: %matrix = alloca %struct.array, align 16
+ array<__m128, 16> matrix;
+ matrix._Elems[0] = (__m128){};
+}
+
+// Struct containing vector under pragma pack.
+#pragma pack(push, 8)
+struct VectorStruct {
+ __m128 vec;
+};
+
+struct ArrayOfVectorStruct {
+ VectorStruct elems[4];
+};
+#pragma pack(pop)
+
+// CHECK-LABEL: define {{.*}} @"?test_vector_struct
+void test_vector_struct() {
+ // CHECK: %s = alloca %struct.ArrayOfVectorStruct, align 16
+ ArrayOfVectorStruct s;
+ s.elems[0].vec = (__m128){};
+}
>From a084b1c84d9fe6f93331278443bd6a07a432bef2 Mon Sep 17 00:00:00 2001
From: Zahira Ammarguellat <zahira.ammarguellat at intel.com>
Date: Fri, 28 Aug 2026 13:10:16 -0700
Subject: [PATCH 2/8] Added fp80 handling
---
clang/lib/AST/RecordLayoutBuilder.cpp | 155 ++++++++++++++----
.../pragma-pack-array-alignment-itanium.cpp | 46 +++++-
.../pragma-pack-array-alignment-msvc.cpp | 47 +++++-
3 files changed, 210 insertions(+), 38 deletions(-)
diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp
index 03a9318547fdea..184befbf64c8e6 100644
--- a/clang/lib/AST/RecordLayoutBuilder.cpp
+++ b/clang/lib/AST/RecordLayoutBuilder.cpp
@@ -781,12 +781,19 @@ class ItaniumRecordLayoutBuilder {
UpdateAlignment(NewAlignment, NewAlignment, NewAlignment);
}
- /// Check if a type contains vector types.
- bool TypeContainsVectors(QualType Ty);
+ /// Check if a type contains vector or x86_fp80 types.
+ bool TypeContainsVectorsOrFp80(QualType Ty);
- /// Get the natural alignment of vectors contained in a type, bypassing
- /// any pragma pack that may have been applied to enclosing structs.
- CharUnits GetNaturalVectorAlignment(QualType Ty);
+ /// Helper for TypeContainsVectorsOrFp80 that tracks array context.
+ bool TypeContainsVectorsOrFp80Impl(QualType Ty, bool InArray);
+
+ /// Get the natural alignment of vectors or x86_fp80 contained in a type,
+ /// bypassing any pragma pack that may have been applied to enclosing
+ /// structs.
+ CharUnits GetNaturalAlignment(QualType Ty);
+
+ /// Helper for GetNaturalAlignment that tracks array context.
+ CharUnits GetNaturalAlignmentImpl(QualType Ty, bool InArray);
/// Retrieve the externally-supplied field offset for the given
/// field.
@@ -1932,10 +1939,10 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D,
// structs), we need to use the natural alignment of the vectors, not the
// potentially pragma-pack-clamped alignment from the struct layout.
QualType FieldType = D->getType();
- if (!FieldType->isVectorType() && TypeContainsVectors(FieldType)) {
+ if (!FieldType->isVectorType() && TypeContainsVectorsOrFp80(FieldType)) {
// Get the natural vector alignment, bypassing any pragma pack on
// structs.
- CharUnits VecAlign = GetNaturalVectorAlignment(FieldType);
+ CharUnits VecAlign = GetNaturalAlignment(FieldType);
FieldAlign = std::max(FieldAlign, VecAlign);
}
@@ -2045,7 +2052,8 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D,
// unadjusted alignment to avoid inheriting pragma pack from the nested
// struct.
QualType BaseQualTy = QualType(BaseTy, 0);
- if (D->getType() != BaseQualTy && TypeContainsVectors(D->getType())) {
+ if (D->getType() != BaseQualTy &&
+ TypeContainsVectorsOrFp80(D->getType())) {
FieldAlign =
std::max(FieldAlign, FieldRecord.getUnadjustedAlignment());
PreferredAlign =
@@ -2076,7 +2084,7 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D,
QualType FieldType = D->getType();
// Only exempt arrays containing vectors, not direct vector fields.
bool IsArrayContainingVectors =
- !FieldType->isVectorType() && TypeContainsVectors(FieldType);
+ !FieldType->isVectorType() && TypeContainsVectorsOrFp80(FieldType);
if (!IsArrayContainingVectors) {
PackedFieldAlign = std::min(PackedFieldAlign, MaxFieldAlignment);
PreferredAlign = std::min(PreferredAlign, MaxFieldAlignment);
@@ -2259,20 +2267,38 @@ void ItaniumRecordLayoutBuilder::FinishLayout(const NamedDecl *D) {
}
}
-bool ItaniumRecordLayoutBuilder::TypeContainsVectors(QualType Ty) {
+bool ItaniumRecordLayoutBuilder::TypeContainsVectorsOrFp80(QualType Ty) {
+ QualType OrigTy = Ty;
+
// Strip through arrays.
while (const ArrayType *AT = Context.getAsArrayType(Ty))
Ty = AT->getElementType();
+ bool InArray = (Ty != OrigTy);
+ return TypeContainsVectorsOrFp80Impl(Ty, InArray);
+}
+
+bool ItaniumRecordLayoutBuilder::TypeContainsVectorsOrFp80Impl(
+ QualType Ty, bool InArray) {
// Direct vector type.
if (Ty->isVectorType())
return true;
- // Check if it's a record type with vector fields.
+ // x86_fp80 only matters if it's in an array, not a direct field.
+ if (InArray) {
+ if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) {
+ if (BT->getKind() == BuiltinType::LongDouble &&
+ &Context.getTargetInfo().getLongDoubleFormat() ==
+ &llvm::APFloat::x87DoubleExtended())
+ return true;
+ }
+ }
+
+ // Check if it's a record type with vector or x86_fp80 fields.
if (const RecordType *RT = Ty->getAs<RecordType>()) {
const RecordDecl *RD = RT->getDecl();
for (const FieldDecl *Field : RD->fields()) {
- if (TypeContainsVectors(Field->getType()))
+ if (TypeContainsVectorsOrFp80Impl(Field->getType(), InArray))
return true;
}
}
@@ -2280,23 +2306,42 @@ bool ItaniumRecordLayoutBuilder::TypeContainsVectors(QualType Ty) {
return false;
}
-CharUnits ItaniumRecordLayoutBuilder::GetNaturalVectorAlignment(QualType Ty) {
+CharUnits ItaniumRecordLayoutBuilder::GetNaturalAlignment(QualType Ty) {
+ QualType OrigTy = Ty;
+
// Strip through arrays.
while (const ArrayType *AT = Context.getAsArrayType(Ty))
Ty = AT->getElementType();
+ bool InArray = (Ty != OrigTy);
+ return GetNaturalAlignmentImpl(Ty, InArray);
+}
+
+CharUnits ItaniumRecordLayoutBuilder::GetNaturalAlignmentImpl(
+ QualType Ty, bool InArray) {
// Direct vector type - get its natural alignment.
if (Ty->isVectorType())
return Context.getTypeAlignInChars(Ty);
- // Record type - find the maximum vector alignment inside.
+ // x86_fp80 only matters if it's in an array, not a direct field.
+ if (InArray) {
+ if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) {
+ if (BT->getKind() == BuiltinType::LongDouble &&
+ &Context.getTargetInfo().getLongDoubleFormat() ==
+ &llvm::APFloat::x87DoubleExtended())
+ return Context.getTypeAlignInChars(Ty);
+ }
+ }
+
+ // Record type - find the maximum alignment inside.
if (const RecordType *RT = Ty->getAs<RecordType>()) {
const RecordDecl *RD = RT->getDecl();
CharUnits MaxAlign = CharUnits::One();
for (const FieldDecl *Field : RD->fields()) {
- if (TypeContainsVectors(Field->getType())) {
- CharUnits FieldVecAlign = GetNaturalVectorAlignment(Field->getType());
- MaxAlign = std::max(MaxAlign, FieldVecAlign);
+ if (TypeContainsVectorsOrFp80Impl(Field->getType(), InArray)) {
+ CharUnits FieldAlign = GetNaturalAlignmentImpl(Field->getType(),
+ InArray);
+ MaxAlign = std::max(MaxAlign, FieldAlign);
}
}
return MaxAlign;
@@ -2709,11 +2754,16 @@ struct MicrosoftRecordLayoutBuilder {
void computeVtorDispSet(
llvm::SmallPtrSetImpl<const CXXRecordDecl *> &HasVtorDispSet,
const CXXRecordDecl *RD) const;
- /// Check if a type (recursively) contains vector types.
- bool TypeContainsVectors(QualType Ty);
- /// Get the natural alignment of vectors contained in a type, bypassing
- /// any pragma pack that may have been applied to enclosing structs.
- CharUnits GetNaturalVectorAlignment(QualType Ty);
+ /// Check if a type (recursively) contains vector or x86_fp80 types.
+ bool TypeContainsVectorsOrFp80(QualType Ty);
+ /// Helper for TypeContainsVectorsOrFp80 that tracks array context.
+ bool TypeContainsVectorsOrFp80Impl(QualType Ty, bool InArray);
+ /// Get the natural alignment of vectors or x86_fp80 contained in a type,
+ /// bypassing any pragma pack that may have been applied to enclosing
+ /// structs.
+ CharUnits GetNaturalAlignment(QualType Ty);
+ /// Helper for GetNaturalAlignment that tracks array context.
+ CharUnits GetNaturalAlignmentImpl(QualType Ty, bool InArray);
const ASTContext &Context;
EmptySubobjectMap *EmptySubobjects;
@@ -2780,20 +2830,38 @@ struct MicrosoftRecordLayoutBuilder {
};
} // namespace
-bool MicrosoftRecordLayoutBuilder::TypeContainsVectors(QualType Ty) {
+bool MicrosoftRecordLayoutBuilder::TypeContainsVectorsOrFp80(QualType Ty) {
+ QualType OrigTy = Ty;
+
// Strip through arrays.
while (const ArrayType *AT = Context.getAsArrayType(Ty))
Ty = AT->getElementType();
+ bool InArray = (Ty != OrigTy);
+ return TypeContainsVectorsOrFp80Impl(Ty, InArray);
+}
+
+bool MicrosoftRecordLayoutBuilder::TypeContainsVectorsOrFp80Impl(
+ QualType Ty, bool InArray) {
// Direct vector type.
if (Ty->isVectorType())
return true;
- // Check if it's a record type with vector fields.
+ // x86_fp80 only matters if it's in an array, not a direct field.
+ if (InArray) {
+ if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) {
+ if (BT->getKind() == BuiltinType::LongDouble &&
+ &Context.getTargetInfo().getLongDoubleFormat() ==
+ &llvm::APFloat::x87DoubleExtended())
+ return true;
+ }
+ }
+
+ // Check if it's a record type with vector or x86_fp80 fields.
if (const RecordType *RT = Ty->getAs<RecordType>()) {
const RecordDecl *RD = RT->getDecl();
for (const FieldDecl *Field : RD->fields()) {
- if (TypeContainsVectors(Field->getType()))
+ if (TypeContainsVectorsOrFp80Impl(Field->getType(), InArray))
return true;
}
}
@@ -2801,23 +2869,42 @@ bool MicrosoftRecordLayoutBuilder::TypeContainsVectors(QualType Ty) {
return false;
}
-CharUnits MicrosoftRecordLayoutBuilder::GetNaturalVectorAlignment(QualType Ty) {
+CharUnits MicrosoftRecordLayoutBuilder::GetNaturalAlignment(QualType Ty) {
+ QualType OrigTy = Ty;
+
// Strip through arrays.
while (const ArrayType *AT = Context.getAsArrayType(Ty))
Ty = AT->getElementType();
+ bool InArray = (Ty != OrigTy);
+ return GetNaturalAlignmentImpl(Ty, InArray);
+}
+
+CharUnits MicrosoftRecordLayoutBuilder::GetNaturalAlignmentImpl(
+ QualType Ty, bool InArray) {
// Direct vector type - get its natural alignment.
if (Ty->isVectorType())
return Context.getTypeAlignInChars(Ty);
- // Record type - find the maximum vector alignment inside.
+ // x86_fp80 only matters if it's in an array, not a direct field.
+ if (InArray) {
+ if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) {
+ if (BT->getKind() == BuiltinType::LongDouble &&
+ &Context.getTargetInfo().getLongDoubleFormat() ==
+ &llvm::APFloat::x87DoubleExtended())
+ return Context.getTypeAlignInChars(Ty);
+ }
+ }
+
+ // Record type - find the maximum alignment inside.
if (const RecordType *RT = Ty->getAs<RecordType>()) {
const RecordDecl *RD = RT->getDecl();
CharUnits MaxAlign = CharUnits::One();
for (const FieldDecl *Field : RD->fields()) {
- if (TypeContainsVectors(Field->getType())) {
- CharUnits FieldVecAlign = GetNaturalVectorAlignment(Field->getType());
- MaxAlign = std::max(MaxAlign, FieldVecAlign);
+ if (TypeContainsVectorsOrFp80Impl(Field->getType(), InArray)) {
+ CharUnits FieldAlign = GetNaturalAlignmentImpl(Field->getType(),
+ InArray);
+ MaxAlign = std::max(MaxAlign, FieldAlign);
}
}
return MaxAlign;
@@ -2869,10 +2956,10 @@ MicrosoftRecordLayoutBuilder::getAdjustedElementInfo(
// structs), we need to use the natural alignment of the vectors, not the
// potentially pragma-pack-clamped alignment from the struct layout.
QualType FieldType = FD->getType();
- if (!FieldType->isVectorType() && TypeContainsVectors(FieldType)) {
+ if (!FieldType->isVectorType() && TypeContainsVectorsOrFp80(FieldType)) {
// Get the natural vector alignment, bypassing any pragma pack on
// structs.
- CharUnits VecAlign = GetNaturalVectorAlignment(FieldType);
+ CharUnits VecAlign = GetNaturalAlignment(FieldType);
Info.Alignment = std::max(Info.Alignment, VecAlign);
}
@@ -2904,7 +2991,7 @@ MicrosoftRecordLayoutBuilder::getAdjustedElementInfo(
// unadjusted alignment to avoid inheriting pragma pack from the nested
// struct.
QualType BaseTy = QualType(FD->getType()->getBaseElementTypeUnsafe(), 0);
- if (FD->getType() != BaseTy && TypeContainsVectors(FD->getType())) {
+ if (FD->getType() != BaseTy && TypeContainsVectorsOrFp80(FD->getType())) {
Info.Alignment =
std::max(Info.Alignment, Layout.getUnadjustedAlignment());
}
@@ -2923,7 +3010,7 @@ MicrosoftRecordLayoutBuilder::getAdjustedElementInfo(
QualType FieldType = FD->getType();
// Only exempt arrays containing vectors, not direct vector fields.
bool IsArrayContainingVectors =
- !FieldType->isVectorType() && TypeContainsVectors(FieldType);
+ !FieldType->isVectorType() && TypeContainsVectorsOrFp80(FieldType);
if (!IsArrayContainingVectors)
Info.Alignment = std::min(Info.Alignment, MaxFieldAlignment);
}
diff --git a/clang/test/CodeGen/pragma-pack-array-alignment-itanium.cpp b/clang/test/CodeGen/pragma-pack-array-alignment-itanium.cpp
index bdac5298211659..488a3b5851fcb2 100644
--- a/clang/test/CodeGen/pragma-pack-array-alignment-itanium.cpp
+++ b/clang/test/CodeGen/pragma-pack-array-alignment-itanium.cpp
@@ -1,8 +1,10 @@
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm -o - %s \
// RUN: | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -mlong-double-80 \
+// RUN: -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-FP80
-// Test that #pragma pack does not reduce natural type alignment for vector types
-// when used as array elements (Itanium ABI).
+// Test that #pragma pack does not reduce natural type alignment for vector
+// and x86_fp80 types when used as array elements (Itanium ABI).
typedef float __m128 __attribute__((__vector_size__(16)));
@@ -38,3 +40,43 @@ void test_vector_struct() {
ArrayOfVectorStruct s;
s.elems[0].vec = (__m128){};
}
+
+// Test x86_fp80 (long double with -mlong-double-80) arrays under pragma pack.
+struct Klass { long double a; };
+
+#pragma pack(push, 8)
+template<typename T, unsigned N>
+struct fp80_array {
+ T _Elems[N];
+
+ void fill(const T& val) {
+ for (unsigned i = 0; i < N; i++)
+ _Elems[i] = val;
+ }
+};
+#pragma pack(pop)
+
+// CHECK-FP80-LABEL: define {{.*}} @_Z15test_fp80_arrayv
+void test_fp80_array() {
+ // CHECK-FP80: %matrix = alloca %struct.fp80_array, align 16
+ fp80_array<Klass, 16> matrix;
+ matrix.fill({});
+}
+
+// Struct containing x86_fp80 under pragma pack.
+#pragma pack(push, 8)
+struct Fp80Struct {
+ long double val;
+};
+
+struct ArrayOfFp80Struct {
+ Fp80Struct elems[4];
+};
+#pragma pack(pop)
+
+// CHECK-FP80-LABEL: define {{.*}} @_Z16test_fp80_structv
+void test_fp80_struct() {
+ // CHECK-FP80: %s = alloca %struct.ArrayOfFp80Struct, align 16
+ ArrayOfFp80Struct s;
+ s.elems[0].val = 1.0L;
+}
diff --git a/clang/test/CodeGen/pragma-pack-array-alignment-msvc.cpp b/clang/test/CodeGen/pragma-pack-array-alignment-msvc.cpp
index bdea75d3862356..0b90301e41418e 100644
--- a/clang/test/CodeGen/pragma-pack-array-alignment-msvc.cpp
+++ b/clang/test/CodeGen/pragma-pack-array-alignment-msvc.cpp
@@ -1,8 +1,11 @@
// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -fms-extensions \
// RUN: -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -fms-extensions \
+// RUN: -mlong-double-80 -emit-llvm -o - %s | FileCheck %s \
+// RUN: --check-prefix=CHECK-FP80
-// Test that #pragma pack does not reduce natural type alignment for vector types
-// when used as array elements (matching MSVC behavior).
+// Test that #pragma pack does not reduce natural type alignment for vector
+// and x86_fp80 types when used as array elements (matching MSVC behavior).
typedef float __m128 __attribute__((__vector_size__(16)));
@@ -38,3 +41,43 @@ void test_vector_struct() {
ArrayOfVectorStruct s;
s.elems[0].vec = (__m128){};
}
+
+// Test x86_fp80 (long double with -mlong-double-80) arrays under pragma pack.
+struct Klass { long double a; };
+
+#pragma pack(push, 8)
+template<typename T, unsigned N>
+struct fp80_array {
+ T _Elems[N];
+
+ void fill(const T& val) {
+ for (unsigned i = 0; i < N; i++)
+ _Elems[i] = val;
+ }
+};
+#pragma pack(pop)
+
+// CHECK-FP80-LABEL: define {{.*}} @"?test_fp80_array
+void test_fp80_array() {
+ // CHECK-FP80: %matrix = alloca %struct.fp80_array, align 16
+ fp80_array<Klass, 16> matrix;
+ matrix.fill({});
+}
+
+// Struct containing x86_fp80 under pragma pack.
+#pragma pack(push, 8)
+struct Fp80Struct {
+ long double val;
+};
+
+struct ArrayOfFp80Struct {
+ Fp80Struct elems[4];
+};
+#pragma pack(pop)
+
+// CHECK-FP80-LABEL: define {{.*}} @"?test_fp80_struct
+void test_fp80_struct() {
+ // CHECK-FP80: %s = alloca %struct.ArrayOfFp80Struct, align 16
+ ArrayOfFp80Struct s;
+ s.elems[0].val = 1.0L;
+}
>From cfb1972568ccea0a071e320287e7023f55496690 Mon Sep 17 00:00:00 2001
From: Zahira Ammarguellat <zahira.ammarguellat at intel.com>
Date: Thu, 3 Sep 2026 13:25:45 -0700
Subject: [PATCH 3/8] Fixed LIT for real msvc support
---
.../test/CodeGen/pragma-pack-array-alignment-msvc.cpp | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/clang/test/CodeGen/pragma-pack-array-alignment-msvc.cpp b/clang/test/CodeGen/pragma-pack-array-alignment-msvc.cpp
index 0b90301e41418e..5d730dee0bc365 100644
--- a/clang/test/CodeGen/pragma-pack-array-alignment-msvc.cpp
+++ b/clang/test/CodeGen/pragma-pack-array-alignment-msvc.cpp
@@ -1,13 +1,14 @@
// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -fms-extensions \
-// RUN: -emit-llvm -o - %s | FileCheck %s
+// RUN: -ffreestanding -emit-llvm -o - %s | FileCheck %s
+
// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -fms-extensions \
-// RUN: -mlong-double-80 -emit-llvm -o - %s | FileCheck %s \
+// RUN: -ffreestanding -mlong-double-80 -emit-llvm -o - %s | FileCheck %s \
// RUN: --check-prefix=CHECK-FP80
// Test that #pragma pack does not reduce natural type alignment for vector
// and x86_fp80 types when used as array elements (matching MSVC behavior).
-typedef float __m128 __attribute__((__vector_size__(16)));
+#include <xmmintrin.h>
// Simple array-like struct with vector type under pragma pack.
#pragma pack(push, 8)
@@ -21,7 +22,7 @@ struct array {
void test_vector_array() {
// CHECK: %matrix = alloca %struct.array, align 16
array<__m128, 16> matrix;
- matrix._Elems[0] = (__m128){};
+ matrix._Elems[0] = _mm_setzero_ps();
}
// Struct containing vector under pragma pack.
@@ -39,7 +40,7 @@ struct ArrayOfVectorStruct {
void test_vector_struct() {
// CHECK: %s = alloca %struct.ArrayOfVectorStruct, align 16
ArrayOfVectorStruct s;
- s.elems[0].vec = (__m128){};
+ s.elems[0].vec = _mm_setzero_ps();
}
// Test x86_fp80 (long double with -mlong-double-80) arrays under pragma pack.
>From 67a3882075538b85cbb7806a2378435cb82319bb Mon Sep 17 00:00:00 2001
From: Zahira Ammarguellat <zahira.ammarguellat at intel.com>
Date: Thu, 3 Sep 2026 13:53:26 -0700
Subject: [PATCH 4/8] Fixed format
---
clang/lib/AST/RecordLayoutBuilder.cpp | 32 +++++++++++++--------------
1 file changed, 15 insertions(+), 17 deletions(-)
diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp
index 184befbf64c8e6..e804586b073f49 100644
--- a/clang/lib/AST/RecordLayoutBuilder.cpp
+++ b/clang/lib/AST/RecordLayoutBuilder.cpp
@@ -1709,9 +1709,8 @@ void ItaniumRecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
QualType FieldType = D->getType();
// Only exempt arrays of vectors from pragma pack, not direct vector
// fields.
- bool IsVectorArray =
- !FieldType->isVectorType() &&
- FieldType->getBaseElementTypeUnsafe()->isVectorType();
+ bool IsVectorArray = !FieldType->isVectorType() &&
+ FieldType->getBaseElementTypeUnsafe()->isVectorType();
if (!IsVectorArray) {
UnpackedFieldAlign =
std::min(UnpackedFieldAlign, MaxFieldAlignmentInBits);
@@ -2054,8 +2053,7 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D,
QualType BaseQualTy = QualType(BaseTy, 0);
if (D->getType() != BaseQualTy &&
TypeContainsVectorsOrFp80(D->getType())) {
- FieldAlign =
- std::max(FieldAlign, FieldRecord.getUnadjustedAlignment());
+ FieldAlign = std::max(FieldAlign, FieldRecord.getUnadjustedAlignment());
PreferredAlign =
std::max(PreferredAlign, FieldRecord.getUnadjustedAlignment());
}
@@ -2278,8 +2276,8 @@ bool ItaniumRecordLayoutBuilder::TypeContainsVectorsOrFp80(QualType Ty) {
return TypeContainsVectorsOrFp80Impl(Ty, InArray);
}
-bool ItaniumRecordLayoutBuilder::TypeContainsVectorsOrFp80Impl(
- QualType Ty, bool InArray) {
+bool ItaniumRecordLayoutBuilder::TypeContainsVectorsOrFp80Impl(QualType Ty
+ bool InArray) {
// Direct vector type.
if (Ty->isVectorType())
return true;
@@ -2317,8 +2315,8 @@ CharUnits ItaniumRecordLayoutBuilder::GetNaturalAlignment(QualType Ty) {
return GetNaturalAlignmentImpl(Ty, InArray);
}
-CharUnits ItaniumRecordLayoutBuilder::GetNaturalAlignmentImpl(
- QualType Ty, bool InArray) {
+CharUnits ItaniumRecordLayoutBuilder::GetNaturalAlignmentImpl(QualType Ty,
+ bool InArray) {
// Direct vector type - get its natural alignment.
if (Ty->isVectorType())
return Context.getTypeAlignInChars(Ty);
@@ -2339,8 +2337,8 @@ CharUnits ItaniumRecordLayoutBuilder::GetNaturalAlignmentImpl(
CharUnits MaxAlign = CharUnits::One();
for (const FieldDecl *Field : RD->fields()) {
if (TypeContainsVectorsOrFp80Impl(Field->getType(), InArray)) {
- CharUnits FieldAlign = GetNaturalAlignmentImpl(Field->getType(),
- InArray);
+ CharUnits FieldAlign =
+ GetNaturalAlignmentImpl(Field->getType(), InArray);
MaxAlign = std::max(MaxAlign, FieldAlign);
}
}
@@ -2841,8 +2839,8 @@ bool MicrosoftRecordLayoutBuilder::TypeContainsVectorsOrFp80(QualType Ty) {
return TypeContainsVectorsOrFp80Impl(Ty, InArray);
}
-bool MicrosoftRecordLayoutBuilder::TypeContainsVectorsOrFp80Impl(
- QualType Ty, bool InArray) {
+bool MicrosoftRecordLayoutBuilder::TypeContainsVectorsOrFp80Impl(QualType Ty,
+ bool InArray) {
// Direct vector type.
if (Ty->isVectorType())
return true;
@@ -2880,8 +2878,8 @@ CharUnits MicrosoftRecordLayoutBuilder::GetNaturalAlignment(QualType Ty) {
return GetNaturalAlignmentImpl(Ty, InArray);
}
-CharUnits MicrosoftRecordLayoutBuilder::GetNaturalAlignmentImpl(
- QualType Ty, bool InArray) {
+CharUnits MicrosoftRecordLayoutBuilder::GetNaturalAlignmentImpl(QualType Ty,
+ bool InArray) {
// Direct vector type - get its natural alignment.
if (Ty->isVectorType())
return Context.getTypeAlignInChars(Ty);
@@ -2902,8 +2900,8 @@ CharUnits MicrosoftRecordLayoutBuilder::GetNaturalAlignmentImpl(
CharUnits MaxAlign = CharUnits::One();
for (const FieldDecl *Field : RD->fields()) {
if (TypeContainsVectorsOrFp80Impl(Field->getType(), InArray)) {
- CharUnits FieldAlign = GetNaturalAlignmentImpl(Field->getType(),
- InArray);
+ CharUnits FieldAlign =
+ GetNaturalAlignmentImpl(Field->getType(), InArray);
MaxAlign = std::max(MaxAlign, FieldAlign);
}
}
>From 4c720c7a10589f40f0ca0a7c345845dc0dac7938 Mon Sep 17 00:00:00 2001
From: Zahira Ammarguellat <zahira.ammarguellat at intel.com>
Date: Thu, 3 Sep 2026 14:08:22 -0700
Subject: [PATCH 5/8] Fix build error
---
clang/lib/AST/RecordLayoutBuilder.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp
index e804586b073f49..a07150fc79c6da 100644
--- a/clang/lib/AST/RecordLayoutBuilder.cpp
+++ b/clang/lib/AST/RecordLayoutBuilder.cpp
@@ -2276,7 +2276,7 @@ bool ItaniumRecordLayoutBuilder::TypeContainsVectorsOrFp80(QualType Ty) {
return TypeContainsVectorsOrFp80Impl(Ty, InArray);
}
-bool ItaniumRecordLayoutBuilder::TypeContainsVectorsOrFp80Impl(QualType Ty
+bool ItaniumRecordLayoutBuilder::TypeContainsVectorsOrFp80Impl(QualType Ty,
bool InArray) {
// Direct vector type.
if (Ty->isVectorType())
>From 8ee1872f7684d70d9397cde02a253fee81a96310 Mon Sep 17 00:00:00 2001
From: Zahira Ammarguellat <zahira.ammarguellat at intel.com>
Date: Tue, 22 Sep 2026 11:35:45 -0700
Subject: [PATCH 6/8] Addressed review comments
---
clang/include/clang/AST/ASTContext.h | 4 +
clang/lib/AST/ASTContext.cpp | 30 +-
clang/lib/AST/RecordLayoutBuilder.cpp | 300 ++----------------
.../pragma-pack-array-alignment-itanium.cpp | 82 -----
4 files changed, 57 insertions(+), 359 deletions(-)
delete mode 100644 clang/test/CodeGen/pragma-pack-array-alignment-itanium.cpp
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index dd67c5d0410f81..55b3f0d9074058 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -183,6 +183,10 @@ enum class AlignRequirementKind {
/// The alignment comes from an alignment attribute on a enum type.
RequiredByEnum,
+
+ /// The type's natural alignment is preserved under #pragma pack in MSVC
+ /// record layout (e.g., vectors, x87 fp80).
+ ResistPragmaPack,
};
struct TypeInfo {
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index b502c4436de49d..b103aa5555d462 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -2059,7 +2059,11 @@ bool ASTContext::isPromotableIntegerType(QualType T) const {
}
bool ASTContext::isAlignmentRequired(const Type *T) const {
- return getTypeInfo(T).AlignRequirement != AlignRequirementKind::None;
+ AlignRequirementKind Kind = getTypeInfo(T).AlignRequirement;
+ // ResistPragmaPack is only meant to resist #pragma pack in MSVC record
+ // layout, not to trigger other "aligned attribute" behaviors.
+ return Kind != AlignRequirementKind::None &&
+ Kind != AlignRequirementKind::ResistPragmaPack;
}
bool ASTContext::isAlignmentRequired(QualType T) const {
@@ -2189,6 +2193,9 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
VT->getVectorKind() == VectorKind::RVVFixedLengthMask_4)
// Adjust the alignment for fixed-length RVV vectors.
Align = std::min<unsigned>(64, Width);
+ // Vector types have their natural alignment resist reduction by
+ // #pragma pack in MSVC record layout.
+ AlignRequirement = AlignRequirementKind::ResistPragmaPack;
break;
}
@@ -2350,6 +2357,11 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
Width = Target->getLongDoubleWidth();
Align = Target->getLongDoubleAlign();
}
+ // x87 extended precision (fp80) has its natural alignment resist
+ // reduction by #pragma pack in MSVC record layout.
+ if (&Target->getLongDoubleFormat() ==
+ &llvm::APFloat::x87DoubleExtended())
+ AlignRequirement = AlignRequirementKind::ResistPragmaPack;
break;
case BuiltinType::Float128:
if (Target->hasFloat128Type() || !getLangOpts().OpenMP ||
@@ -2547,9 +2559,19 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
const ASTRecordLayout &Layout = getASTRecordLayout(RD);
Width = toBits(Layout.getSize());
Align = toBits(Layout.getAlignment());
- AlignRequirement = RD->hasAttr<AlignedAttr>()
- ? AlignRequirementKind::RequiredByRecord
- : AlignRequirementKind::None;
+ if (RD->hasAttr<AlignedAttr>()) {
+ AlignRequirement = AlignRequirementKind::RequiredByRecord;
+ } else if (llvm::any_of(RD->fields(), [this](const FieldDecl *FD) {
+ return getTypeInfo(FD->getType()).AlignRequirement ==
+ AlignRequirementKind::ResistPragmaPack;
+ })) {
+ // Propagate ResistPragmaPack if any field has that requirement, so
+ // pragma pack applied to enclosing records won't reduce alignment for
+ // records containing vector or x87 fp80 types.
+ AlignRequirement = AlignRequirementKind::ResistPragmaPack;
+ } else {
+ AlignRequirement = AlignRequirementKind::None;
+ }
break;
}
diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp
index a07150fc79c6da..68652e2bdfd892 100644
--- a/clang/lib/AST/RecordLayoutBuilder.cpp
+++ b/clang/lib/AST/RecordLayoutBuilder.cpp
@@ -781,20 +781,6 @@ class ItaniumRecordLayoutBuilder {
UpdateAlignment(NewAlignment, NewAlignment, NewAlignment);
}
- /// Check if a type contains vector or x86_fp80 types.
- bool TypeContainsVectorsOrFp80(QualType Ty);
-
- /// Helper for TypeContainsVectorsOrFp80 that tracks array context.
- bool TypeContainsVectorsOrFp80Impl(QualType Ty, bool InArray);
-
- /// Get the natural alignment of vectors or x86_fp80 contained in a type,
- /// bypassing any pragma pack that may have been applied to enclosing
- /// structs.
- CharUnits GetNaturalAlignment(QualType Ty);
-
- /// Helper for GetNaturalAlignment that tracks array context.
- CharUnits GetNaturalAlignmentImpl(QualType Ty, bool InArray);
-
/// Retrieve the externally-supplied field offset for the given
/// field.
///
@@ -1702,23 +1688,13 @@ void ItaniumRecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
// But, if there's a #pragma pack in play, that takes precedent over
// even the 'aligned' attribute, for non-zero-width bitfields.
- // However, pragma pack should not reduce the natural alignment of vector
- // array elements.
unsigned MaxFieldAlignmentInBits = Context.toBits(MaxFieldAlignment);
if (!MaxFieldAlignment.isZero() && FieldSize) {
- QualType FieldType = D->getType();
- // Only exempt arrays of vectors from pragma pack, not direct vector
- // fields.
- bool IsVectorArray = !FieldType->isVectorType() &&
- FieldType->getBaseElementTypeUnsafe()->isVectorType();
- if (!IsVectorArray) {
- UnpackedFieldAlign =
- std::min(UnpackedFieldAlign, MaxFieldAlignmentInBits);
- if (FieldPacked)
- FieldAlign = UnpackedFieldAlign;
- else
- FieldAlign = std::min(FieldAlign, MaxFieldAlignmentInBits);
- }
+ UnpackedFieldAlign = std::min(UnpackedFieldAlign, MaxFieldAlignmentInBits);
+ if (FieldPacked)
+ FieldAlign = UnpackedFieldAlign;
+ else
+ FieldAlign = std::min(FieldAlign, MaxFieldAlignmentInBits);
}
// But, ms_struct just ignores all of that in unions, even explicit
@@ -1934,17 +1910,6 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D,
} else {
setDeclInfo(false /* IsIncompleteArrayType */);
- // If this is an array containing vectors (directly or in nested
- // structs), we need to use the natural alignment of the vectors, not the
- // potentially pragma-pack-clamped alignment from the struct layout.
- QualType FieldType = D->getType();
- if (!FieldType->isVectorType() && TypeContainsVectorsOrFp80(FieldType)) {
- // Get the natural vector alignment, bypassing any pragma pack on
- // structs.
- CharUnits VecAlign = GetNaturalAlignment(FieldType);
- FieldAlign = std::max(FieldAlign, VecAlign);
- }
-
// A potentially-overlapping field occupies its dsize or nvsize, whichever
// is larger.
if (D->isPotentiallyOverlapping()) {
@@ -2047,16 +2012,6 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D,
const RecordDecl *RD = RT->getDecl();
const ASTRecordLayout &FieldRecord = Context.getASTRecordLayout(RD);
PreferredAlign = FieldRecord.getPreferredAlignment();
- // If this is an array of records containing vectors, use the
- // unadjusted alignment to avoid inheriting pragma pack from the nested
- // struct.
- QualType BaseQualTy = QualType(BaseTy, 0);
- if (D->getType() != BaseQualTy &&
- TypeContainsVectorsOrFp80(D->getType())) {
- FieldAlign = std::max(FieldAlign, FieldRecord.getUnadjustedAlignment());
- PreferredAlign =
- std::max(PreferredAlign, FieldRecord.getUnadjustedAlignment());
- }
}
}
@@ -2074,20 +2029,10 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D,
UnpackedFieldAlign = std::max(UnpackedFieldAlign, MaxAlignmentInChars);
// The maximum field alignment overrides the aligned attribute.
- // However, pragma pack should not reduce the natural alignment of array
- // elements that contain vectors (either arrays of vectors, or arrays of
- // structs containing vectors). Direct vector fields ARE affected by pragma
- // pack.
if (!MaxFieldAlignment.isZero()) {
- QualType FieldType = D->getType();
- // Only exempt arrays containing vectors, not direct vector fields.
- bool IsArrayContainingVectors =
- !FieldType->isVectorType() && TypeContainsVectorsOrFp80(FieldType);
- if (!IsArrayContainingVectors) {
- PackedFieldAlign = std::min(PackedFieldAlign, MaxFieldAlignment);
- PreferredAlign = std::min(PreferredAlign, MaxFieldAlignment);
- UnpackedFieldAlign = std::min(UnpackedFieldAlign, MaxFieldAlignment);
- }
+ PackedFieldAlign = std::min(PackedFieldAlign, MaxFieldAlignment);
+ PreferredAlign = std::min(PreferredAlign, MaxFieldAlignment);
+ UnpackedFieldAlign = std::min(UnpackedFieldAlign, MaxFieldAlignment);
}
@@ -2265,89 +2210,6 @@ void ItaniumRecordLayoutBuilder::FinishLayout(const NamedDecl *D) {
}
}
-bool ItaniumRecordLayoutBuilder::TypeContainsVectorsOrFp80(QualType Ty) {
- QualType OrigTy = Ty;
-
- // Strip through arrays.
- while (const ArrayType *AT = Context.getAsArrayType(Ty))
- Ty = AT->getElementType();
-
- bool InArray = (Ty != OrigTy);
- return TypeContainsVectorsOrFp80Impl(Ty, InArray);
-}
-
-bool ItaniumRecordLayoutBuilder::TypeContainsVectorsOrFp80Impl(QualType Ty,
- bool InArray) {
- // Direct vector type.
- if (Ty->isVectorType())
- return true;
-
- // x86_fp80 only matters if it's in an array, not a direct field.
- if (InArray) {
- if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) {
- if (BT->getKind() == BuiltinType::LongDouble &&
- &Context.getTargetInfo().getLongDoubleFormat() ==
- &llvm::APFloat::x87DoubleExtended())
- return true;
- }
- }
-
- // Check if it's a record type with vector or x86_fp80 fields.
- if (const RecordType *RT = Ty->getAs<RecordType>()) {
- const RecordDecl *RD = RT->getDecl();
- for (const FieldDecl *Field : RD->fields()) {
- if (TypeContainsVectorsOrFp80Impl(Field->getType(), InArray))
- return true;
- }
- }
-
- return false;
-}
-
-CharUnits ItaniumRecordLayoutBuilder::GetNaturalAlignment(QualType Ty) {
- QualType OrigTy = Ty;
-
- // Strip through arrays.
- while (const ArrayType *AT = Context.getAsArrayType(Ty))
- Ty = AT->getElementType();
-
- bool InArray = (Ty != OrigTy);
- return GetNaturalAlignmentImpl(Ty, InArray);
-}
-
-CharUnits ItaniumRecordLayoutBuilder::GetNaturalAlignmentImpl(QualType Ty,
- bool InArray) {
- // Direct vector type - get its natural alignment.
- if (Ty->isVectorType())
- return Context.getTypeAlignInChars(Ty);
-
- // x86_fp80 only matters if it's in an array, not a direct field.
- if (InArray) {
- if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) {
- if (BT->getKind() == BuiltinType::LongDouble &&
- &Context.getTargetInfo().getLongDoubleFormat() ==
- &llvm::APFloat::x87DoubleExtended())
- return Context.getTypeAlignInChars(Ty);
- }
- }
-
- // Record type - find the maximum alignment inside.
- if (const RecordType *RT = Ty->getAs<RecordType>()) {
- const RecordDecl *RD = RT->getDecl();
- CharUnits MaxAlign = CharUnits::One();
- for (const FieldDecl *Field : RD->fields()) {
- if (TypeContainsVectorsOrFp80Impl(Field->getType(), InArray)) {
- CharUnits FieldAlign =
- GetNaturalAlignmentImpl(Field->getType(), InArray);
- MaxAlign = std::max(MaxAlign, FieldAlign);
- }
- }
- return MaxAlign;
- }
-
- return CharUnits::One();
-}
-
void ItaniumRecordLayoutBuilder::UpdateAlignment(
CharUnits NewAlignment, CharUnits UnpackedNewAlignment,
CharUnits PreferredNewAlignment) {
@@ -2752,16 +2614,6 @@ struct MicrosoftRecordLayoutBuilder {
void computeVtorDispSet(
llvm::SmallPtrSetImpl<const CXXRecordDecl *> &HasVtorDispSet,
const CXXRecordDecl *RD) const;
- /// Check if a type (recursively) contains vector or x86_fp80 types.
- bool TypeContainsVectorsOrFp80(QualType Ty);
- /// Helper for TypeContainsVectorsOrFp80 that tracks array context.
- bool TypeContainsVectorsOrFp80Impl(QualType Ty, bool InArray);
- /// Get the natural alignment of vectors or x86_fp80 contained in a type,
- /// bypassing any pragma pack that may have been applied to enclosing
- /// structs.
- CharUnits GetNaturalAlignment(QualType Ty);
- /// Helper for GetNaturalAlignment that tracks array context.
- CharUnits GetNaturalAlignmentImpl(QualType Ty, bool InArray);
const ASTContext &Context;
EmptySubobjectMap *EmptySubobjects;
@@ -2828,89 +2680,6 @@ struct MicrosoftRecordLayoutBuilder {
};
} // namespace
-bool MicrosoftRecordLayoutBuilder::TypeContainsVectorsOrFp80(QualType Ty) {
- QualType OrigTy = Ty;
-
- // Strip through arrays.
- while (const ArrayType *AT = Context.getAsArrayType(Ty))
- Ty = AT->getElementType();
-
- bool InArray = (Ty != OrigTy);
- return TypeContainsVectorsOrFp80Impl(Ty, InArray);
-}
-
-bool MicrosoftRecordLayoutBuilder::TypeContainsVectorsOrFp80Impl(QualType Ty,
- bool InArray) {
- // Direct vector type.
- if (Ty->isVectorType())
- return true;
-
- // x86_fp80 only matters if it's in an array, not a direct field.
- if (InArray) {
- if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) {
- if (BT->getKind() == BuiltinType::LongDouble &&
- &Context.getTargetInfo().getLongDoubleFormat() ==
- &llvm::APFloat::x87DoubleExtended())
- return true;
- }
- }
-
- // Check if it's a record type with vector or x86_fp80 fields.
- if (const RecordType *RT = Ty->getAs<RecordType>()) {
- const RecordDecl *RD = RT->getDecl();
- for (const FieldDecl *Field : RD->fields()) {
- if (TypeContainsVectorsOrFp80Impl(Field->getType(), InArray))
- return true;
- }
- }
-
- return false;
-}
-
-CharUnits MicrosoftRecordLayoutBuilder::GetNaturalAlignment(QualType Ty) {
- QualType OrigTy = Ty;
-
- // Strip through arrays.
- while (const ArrayType *AT = Context.getAsArrayType(Ty))
- Ty = AT->getElementType();
-
- bool InArray = (Ty != OrigTy);
- return GetNaturalAlignmentImpl(Ty, InArray);
-}
-
-CharUnits MicrosoftRecordLayoutBuilder::GetNaturalAlignmentImpl(QualType Ty,
- bool InArray) {
- // Direct vector type - get its natural alignment.
- if (Ty->isVectorType())
- return Context.getTypeAlignInChars(Ty);
-
- // x86_fp80 only matters if it's in an array, not a direct field.
- if (InArray) {
- if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) {
- if (BT->getKind() == BuiltinType::LongDouble &&
- &Context.getTargetInfo().getLongDoubleFormat() ==
- &llvm::APFloat::x87DoubleExtended())
- return Context.getTypeAlignInChars(Ty);
- }
- }
-
- // Record type - find the maximum alignment inside.
- if (const RecordType *RT = Ty->getAs<RecordType>()) {
- const RecordDecl *RD = RT->getDecl();
- CharUnits MaxAlign = CharUnits::One();
- for (const FieldDecl *Field : RD->fields()) {
- if (TypeContainsVectorsOrFp80Impl(Field->getType(), InArray)) {
- CharUnits FieldAlign =
- GetNaturalAlignmentImpl(Field->getType(), InArray);
- MaxAlign = std::max(MaxAlign, FieldAlign);
- }
- }
- return MaxAlign;
- }
-
- return CharUnits::One();
-}
-
MicrosoftRecordLayoutBuilder::ElementInfo
MicrosoftRecordLayoutBuilder::getAdjustedElementInfo(
const ASTRecordLayout &Layout) {
@@ -2949,26 +2718,23 @@ MicrosoftRecordLayoutBuilder::getAdjustedElementInfo(
auto TInfo =
Context.getTypeInfoInChars(FD->getType()->getUnqualifiedDesugaredType());
ElementInfo Info{TInfo.Width, TInfo.Align, CharUnits::Zero()};
-
- // If this is an array containing vectors (directly or in nested
- // structs), we need to use the natural alignment of the vectors, not the
- // potentially pragma-pack-clamped alignment from the struct layout.
- QualType FieldType = FD->getType();
- if (!FieldType->isVectorType() && TypeContainsVectorsOrFp80(FieldType)) {
- // Get the natural vector alignment, bypassing any pragma pack on
- // structs.
- CharUnits VecAlign = GetNaturalAlignment(FieldType);
- Info.Alignment = std::max(Info.Alignment, VecAlign);
- }
-
// Respect align attributes on the field.
CharUnits DirectFieldAlignment =
Context.toCharUnitsFromBits(FD->getMaxAlignment());
// The portion of the field's required alignment that comes from its type
// rather than from over-alignment applied directly to the field.
CharUnits FieldTypeRequiredAlignment = CharUnits::Zero();
- // Respect align attributes on the type.
- if (Context.isAlignmentRequired(FD->getType()))
+ // Types that resist #pragma pack (vectors, x87 fp80) contribute their
+ // natural alignment for the purpose of resisting pragma pack, but do not
+ // affect the record's required alignment.
+ CharUnits FieldTypePragmaPackResistantAlignment = CharUnits::Zero();
+ AlignRequirementKind FieldAlignReq =
+ Context.getTypeInfo(FD->getType()).AlignRequirement;
+ if (FieldAlignReq == AlignRequirementKind::ResistPragmaPack)
+ FieldTypePragmaPackResistantAlignment =
+ Context.getTypeAlignInChars(FD->getType());
+ else if (FieldAlignReq != AlignRequirementKind::None)
+ // Respect align attributes on the type.
FieldTypeRequiredAlignment = Context.getTypeAlignInChars(FD->getType());
// Respect attributes applied to subobjects of the field.
if (FD->isBitField())
@@ -2985,14 +2751,6 @@ MicrosoftRecordLayoutBuilder::getAdjustedElementInfo(
EndsWithZeroSizedObject = Layout.endsWithZeroSizedObject();
FieldTypeRequiredAlignment =
std::max(FieldTypeRequiredAlignment, Layout.getRequiredAlignment());
- // If this is an array of records containing vectors, use the
- // unadjusted alignment to avoid inheriting pragma pack from the nested
- // struct.
- QualType BaseTy = QualType(FD->getType()->getBaseElementTypeUnsafe(), 0);
- if (FD->getType() != BaseTy && TypeContainsVectorsOrFp80(FD->getType())) {
- Info.Alignment =
- std::max(Info.Alignment, Layout.getUnadjustedAlignment());
- }
}
// Capture required alignment as a side-effect.
RequiredAlignment =
@@ -3000,20 +2758,16 @@ MicrosoftRecordLayoutBuilder::getAdjustedElementInfo(
std::max(DirectFieldAlignment, FieldTypeRequiredAlignment));
}
// Respect pragma pack, attribute pack and declspec align
- // However, pragma pack should not reduce the natural alignment of array
- // elements that contain vectors (either arrays of vectors, or arrays of
- // structs containing vectors). Direct vector fields ARE affected by pragma
- // pack.
- if (!MaxFieldAlignment.isZero()) {
- QualType FieldType = FD->getType();
- // Only exempt arrays containing vectors, not direct vector fields.
- bool IsArrayContainingVectors =
- !FieldType->isVectorType() && TypeContainsVectorsOrFp80(FieldType);
- if (!IsArrayContainingVectors)
- Info.Alignment = std::min(Info.Alignment, MaxFieldAlignment);
- }
+ if (!MaxFieldAlignment.isZero())
+ Info.Alignment = std::min(Info.Alignment, MaxFieldAlignment);
if (FD->hasAttr<PackedAttr>())
Info.Alignment = CharUnits::One();
+ // Types that resist #pragma pack restore their natural alignment after
+ // pragma pack clamping, but only when neither the field nor the enclosing
+ // record is explicitly packed via __attribute__((packed)).
+ if (!FD->hasAttr<PackedAttr>() && !FD->getParent()->hasAttr<PackedAttr>())
+ Info.Alignment =
+ std::max(Info.Alignment, FieldTypePragmaPackResistantAlignment);
// The alignment used to update the record's alignment excludes over-alignment
// applied directly to the field; the alignment used for placement includes
// it. On targets that don't reuse over-aligned tail padding the two are the
diff --git a/clang/test/CodeGen/pragma-pack-array-alignment-itanium.cpp b/clang/test/CodeGen/pragma-pack-array-alignment-itanium.cpp
deleted file mode 100644
index 488a3b5851fcb2..00000000000000
--- a/clang/test/CodeGen/pragma-pack-array-alignment-itanium.cpp
+++ /dev/null
@@ -1,82 +0,0 @@
-// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm -o - %s \
-// RUN: | FileCheck %s
-// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -mlong-double-80 \
-// RUN: -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-FP80
-
-// Test that #pragma pack does not reduce natural type alignment for vector
-// and x86_fp80 types when used as array elements (Itanium ABI).
-
-typedef float __m128 __attribute__((__vector_size__(16)));
-
-// Simple array-like struct with vector type under pragma pack.
-#pragma pack(push, 8)
-template<typename T, unsigned N>
-struct array {
- T _Elems[N];
-};
-#pragma pack(pop)
-
-// CHECK-LABEL: define {{.*}} @_Z17test_vector_arrayv
-void test_vector_array() {
- // CHECK: %matrix = alloca %struct.array, align 16
- array<__m128, 16> matrix;
- matrix._Elems[0] = (__m128){};
-}
-
-// Struct containing vector under pragma pack.
-#pragma pack(push, 8)
-struct VectorStruct {
- __m128 vec;
-};
-
-struct ArrayOfVectorStruct {
- VectorStruct elems[4];
-};
-#pragma pack(pop)
-
-// CHECK-LABEL: define {{.*}} @_Z18test_vector_structv
-void test_vector_struct() {
- // CHECK: %s = alloca %struct.ArrayOfVectorStruct, align 16
- ArrayOfVectorStruct s;
- s.elems[0].vec = (__m128){};
-}
-
-// Test x86_fp80 (long double with -mlong-double-80) arrays under pragma pack.
-struct Klass { long double a; };
-
-#pragma pack(push, 8)
-template<typename T, unsigned N>
-struct fp80_array {
- T _Elems[N];
-
- void fill(const T& val) {
- for (unsigned i = 0; i < N; i++)
- _Elems[i] = val;
- }
-};
-#pragma pack(pop)
-
-// CHECK-FP80-LABEL: define {{.*}} @_Z15test_fp80_arrayv
-void test_fp80_array() {
- // CHECK-FP80: %matrix = alloca %struct.fp80_array, align 16
- fp80_array<Klass, 16> matrix;
- matrix.fill({});
-}
-
-// Struct containing x86_fp80 under pragma pack.
-#pragma pack(push, 8)
-struct Fp80Struct {
- long double val;
-};
-
-struct ArrayOfFp80Struct {
- Fp80Struct elems[4];
-};
-#pragma pack(pop)
-
-// CHECK-FP80-LABEL: define {{.*}} @_Z16test_fp80_structv
-void test_fp80_struct() {
- // CHECK-FP80: %s = alloca %struct.ArrayOfFp80Struct, align 16
- ArrayOfFp80Struct s;
- s.elems[0].val = 1.0L;
-}
>From e9ecab5a9584e31f1a02c903d140887bbb75140e Mon Sep 17 00:00:00 2001
From: Zahira Ammarguellat <zahira.ammarguellat at intel.com>
Date: Tue, 22 Sep 2026 12:22:19 -0700
Subject: [PATCH 7/8] Fix format
---
clang/lib/AST/ASTContext.cpp | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index b103aa5555d462..7c96512feb7688 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -2359,8 +2359,7 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
}
// x87 extended precision (fp80) has its natural alignment resist
// reduction by #pragma pack in MSVC record layout.
- if (&Target->getLongDoubleFormat() ==
- &llvm::APFloat::x87DoubleExtended())
+ if (&Target->getLongDoubleFormat() == &llvm::APFloat::x87DoubleExtended())
AlignRequirement = AlignRequirementKind::ResistPragmaPack;
break;
case BuiltinType::Float128:
>From 36995f132c2328e2bed2199af541d067b6724a79 Mon Sep 17 00:00:00 2001
From: Zahira Ammarguellat <zahira.ammarguellat at intel.com>
Date: Wed, 23 Sep 2026 07:05:54 -0700
Subject: [PATCH 8/8] Addressed review comments
---
clang/include/clang/AST/ASTContext.h | 6 ++++--
clang/include/clang/AST/RecordLayout.h | 15 +++++++++++++--
clang/lib/AST/ASTContext.cpp | 22 +++++++---------------
clang/lib/AST/RecordLayout.cpp | 21 +++++++++++----------
clang/lib/AST/RecordLayoutBuilder.cpp | 25 ++++++++++++++++++++-----
5 files changed, 55 insertions(+), 34 deletions(-)
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index 55b3f0d9074058..e35a48f64b0deb 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -199,7 +199,8 @@ struct TypeInfo {
AlignRequirementKind AlignRequirement)
: Width(Width), Align(Align), AlignRequirement(AlignRequirement) {}
bool isAlignRequired() {
- return AlignRequirement != AlignRequirementKind::None;
+ return AlignRequirement != AlignRequirementKind::None &&
+ AlignRequirement != AlignRequirementKind::ResistPragmaPack;
}
};
@@ -213,7 +214,8 @@ struct TypeInfoChars {
AlignRequirementKind AlignRequirement)
: Width(Width), Align(Align), AlignRequirement(AlignRequirement) {}
bool isAlignRequired() {
- return AlignRequirement != AlignRequirementKind::None;
+ return AlignRequirement != AlignRequirementKind::None &&
+ AlignRequirement != AlignRequirementKind::ResistPragmaPack;
}
};
diff --git a/clang/include/clang/AST/RecordLayout.h b/clang/include/clang/AST/RecordLayout.h
index 9af17df229b376..5ae2f94f062cfe 100644
--- a/clang/include/clang/AST/RecordLayout.h
+++ b/clang/include/clang/AST/RecordLayout.h
@@ -84,6 +84,10 @@ class ASTRecordLayout {
/// the __declspec(align()) trumps #pramga pack and must always be obeyed.
CharUnits RequiredAlignment;
+ /// Natural alignment of pragma-pack-resistant fields (vectors, x87 fp80),
+ /// or zero if none.
+ CharUnits PragmaPackResistantAlignment;
+
/// FieldOffsets - Array of field offsets in bits.
ASTVector<uint64_t> FieldOffsets;
@@ -157,7 +161,8 @@ class ASTRecordLayout {
ASTRecordLayout(const ASTContext &Ctx, CharUnits size, CharUnits alignment,
CharUnits preferredAlignment, CharUnits unadjustedAlignment,
- CharUnits requiredAlignment, CharUnits datasize,
+ CharUnits requiredAlignment,
+ CharUnits pragmaPackResistantAlignment, CharUnits datasize,
ArrayRef<uint64_t> fieldoffsets);
using BaseOffsetsMapTy = CXXRecordLayoutInfo::BaseOffsetsMapTy;
@@ -165,7 +170,8 @@ class ASTRecordLayout {
// Constructor for C++ records.
ASTRecordLayout(const ASTContext &Ctx, CharUnits size, CharUnits alignment,
CharUnits preferredAlignment, CharUnits unadjustedAlignment,
- CharUnits requiredAlignment, bool hasOwnVFPtr,
+ CharUnits requiredAlignment,
+ CharUnits pragmaPackResistantAlignment, bool hasOwnVFPtr,
bool hasExtendableVFPtr, CharUnits vbptroffset,
CharUnits datasize, ArrayRef<uint64_t> fieldoffsets,
CharUnits nonvirtualsize, CharUnits nonvirtualalignment,
@@ -327,6 +333,11 @@ class ASTRecordLayout {
CharUnits getRequiredAlignment() const { return RequiredAlignment; }
+ /// Get the natural alignment of pragma-pack-resistant fields.
+ CharUnits getPragmaPackResistantAlignment() const {
+ return PragmaPackResistantAlignment;
+ }
+
bool endsWithZeroSizedObject() const {
return CXXInfo && CXXInfo->EndsWithZeroSizedObject;
}
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 7c96512feb7688..3b32f4d5960ae1 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -2059,11 +2059,7 @@ bool ASTContext::isPromotableIntegerType(QualType T) const {
}
bool ASTContext::isAlignmentRequired(const Type *T) const {
- AlignRequirementKind Kind = getTypeInfo(T).AlignRequirement;
- // ResistPragmaPack is only meant to resist #pragma pack in MSVC record
- // layout, not to trigger other "aligned attribute" behaviors.
- return Kind != AlignRequirementKind::None &&
- Kind != AlignRequirementKind::ResistPragmaPack;
+ return getTypeInfo(T).isAlignRequired();
}
bool ASTContext::isAlignmentRequired(QualType T) const {
@@ -2558,19 +2554,15 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
const ASTRecordLayout &Layout = getASTRecordLayout(RD);
Width = toBits(Layout.getSize());
Align = toBits(Layout.getAlignment());
- if (RD->hasAttr<AlignedAttr>()) {
+ if (RD->hasAttr<AlignedAttr>())
AlignRequirement = AlignRequirementKind::RequiredByRecord;
- } else if (llvm::any_of(RD->fields(), [this](const FieldDecl *FD) {
- return getTypeInfo(FD->getType()).AlignRequirement ==
- AlignRequirementKind::ResistPragmaPack;
- })) {
- // Propagate ResistPragmaPack if any field has that requirement, so
- // pragma pack applied to enclosing records won't reduce alignment for
- // records containing vector or x87 fp80 types.
+ else if (!Layout.getPragmaPackResistantAlignment().isZero())
+ // Propagate ResistPragmaPack so pragma pack applied to enclosing
+ // records won't reduce alignment for records containing vector or
+ // x87 fp80 types.
AlignRequirement = AlignRequirementKind::ResistPragmaPack;
- } else {
+ else
AlignRequirement = AlignRequirementKind::None;
- }
break;
}
diff --git a/clang/lib/AST/RecordLayout.cpp b/clang/lib/AST/RecordLayout.cpp
index 314b24a1f319e7..b5fefb2b97724e 100644
--- a/clang/lib/AST/RecordLayout.cpp
+++ b/clang/lib/AST/RecordLayout.cpp
@@ -27,17 +27,16 @@ void ASTRecordLayout::Destroy(ASTContext &Ctx) {
Ctx.Deallocate(this);
}
-ASTRecordLayout::ASTRecordLayout(const ASTContext &Ctx, CharUnits size,
- CharUnits alignment,
- CharUnits preferredAlignment,
- CharUnits unadjustedAlignment,
- CharUnits requiredAlignment,
- CharUnits datasize,
- ArrayRef<uint64_t> fieldoffsets)
+ASTRecordLayout::ASTRecordLayout(
+ const ASTContext &Ctx, CharUnits size, CharUnits alignment,
+ CharUnits preferredAlignment, CharUnits unadjustedAlignment,
+ CharUnits requiredAlignment, CharUnits pragmaPackResistantAlignment,
+ CharUnits datasize, ArrayRef<uint64_t> fieldoffsets)
: Size(size), DataSize(datasize), Alignment(alignment),
PreferredAlignment(preferredAlignment),
UnadjustedAlignment(unadjustedAlignment),
- RequiredAlignment(requiredAlignment) {
+ RequiredAlignment(requiredAlignment),
+ PragmaPackResistantAlignment(pragmaPackResistantAlignment) {
FieldOffsets.append(Ctx, fieldoffsets.begin(), fieldoffsets.end());
}
@@ -45,8 +44,9 @@ ASTRecordLayout::ASTRecordLayout(const ASTContext &Ctx, CharUnits size,
ASTRecordLayout::ASTRecordLayout(
const ASTContext &Ctx, CharUnits size, CharUnits alignment,
CharUnits preferredAlignment, CharUnits unadjustedAlignment,
- CharUnits requiredAlignment, bool hasOwnVFPtr, bool hasExtendableVFPtr,
- CharUnits vbptroffset, CharUnits datasize, ArrayRef<uint64_t> fieldoffsets,
+ CharUnits requiredAlignment, CharUnits pragmaPackResistantAlignment,
+ bool hasOwnVFPtr, bool hasExtendableVFPtr, CharUnits vbptroffset,
+ CharUnits datasize, ArrayRef<uint64_t> fieldoffsets,
CharUnits nonvirtualsize, CharUnits nonvirtualalignment,
CharUnits preferrednvalignment, CharUnits nonrequirednvalignment,
CharUnits SizeOfLargestEmptySubobject, const CXXRecordDecl *PrimaryBase,
@@ -57,6 +57,7 @@ ASTRecordLayout::ASTRecordLayout(
PreferredAlignment(preferredAlignment),
UnadjustedAlignment(unadjustedAlignment),
RequiredAlignment(requiredAlignment),
+ PragmaPackResistantAlignment(pragmaPackResistantAlignment),
CXXInfo(new (Ctx) CXXRecordLayoutInfo) {
FieldOffsets.append(Ctx, fieldoffsets.begin(), fieldoffsets.end());
diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp
index 68652e2bdfd892..994c34f3421b1c 100644
--- a/clang/lib/AST/RecordLayoutBuilder.cpp
+++ b/clang/lib/AST/RecordLayoutBuilder.cpp
@@ -2633,6 +2633,9 @@ struct MicrosoftRecordLayoutBuilder {
/// The alignment of the record ignoring any over-alignment imposed via
/// __declspec(align()) / alignas on the record or its bases.
CharUnits NonRequiredAlignment;
+ /// Natural alignment of pragma-pack-resistant fields (vectors, x87 fp80),
+ /// or zero if none.
+ CharUnits PragmaPackResistantAlignment;
/// The size of the allocation of the currently active bitfield.
/// This value isn't meaningful unless LastFieldIsNonZeroWidthBitfield
/// is true.
@@ -2751,12 +2754,19 @@ MicrosoftRecordLayoutBuilder::getAdjustedElementInfo(
EndsWithZeroSizedObject = Layout.endsWithZeroSizedObject();
FieldTypeRequiredAlignment =
std::max(FieldTypeRequiredAlignment, Layout.getRequiredAlignment());
+ // Propagate pragma-pack-resistant alignment from nested records.
+ FieldTypePragmaPackResistantAlignment =
+ std::max(FieldTypePragmaPackResistantAlignment,
+ Layout.getPragmaPackResistantAlignment());
}
// Capture required alignment as a side-effect.
RequiredAlignment =
std::max(RequiredAlignment,
std::max(DirectFieldAlignment, FieldTypeRequiredAlignment));
}
+ // Capture pragma-pack-resistant alignment as a side-effect.
+ PragmaPackResistantAlignment = std::max(
+ PragmaPackResistantAlignment, FieldTypePragmaPackResistantAlignment);
// Respect pragma pack, attribute pack and declspec align
if (!MaxFieldAlignment.isZero())
Info.Alignment = std::min(Info.Alignment, MaxFieldAlignment);
@@ -3469,7 +3479,8 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
Builder.cxxLayout(RD);
NewEntry = new (*this) ASTRecordLayout(
*this, Builder.Size, Builder.Alignment, Builder.Alignment,
- Builder.Alignment, Builder.RequiredAlignment, Builder.HasOwnVFPtr,
+ Builder.Alignment, Builder.RequiredAlignment,
+ Builder.PragmaPackResistantAlignment, Builder.HasOwnVFPtr,
Builder.HasOwnVFPtr || Builder.PrimaryBase, Builder.VBPtrOffset,
Builder.DataSize, Builder.FieldOffsets, Builder.NonVirtualSize,
Builder.Alignment, Builder.Alignment, Builder.NonRequiredAlignment,
@@ -3481,7 +3492,8 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
Builder.layout(D);
NewEntry = new (*this) ASTRecordLayout(
*this, Builder.Size, Builder.Alignment, Builder.Alignment,
- Builder.Alignment, Builder.RequiredAlignment, Builder.Size,
+ Builder.Alignment, Builder.RequiredAlignment,
+ Builder.PragmaPackResistantAlignment, Builder.Size,
Builder.FieldOffsets);
}
} else {
@@ -3505,7 +3517,8 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
*this, Builder.getSize(), Builder.Alignment,
Builder.PreferredAlignment, Builder.UnadjustedAlignment,
/*RequiredAlignment : used by MS-ABI)*/
- Builder.Alignment, Builder.HasOwnVFPtr, RD->isDynamicClass(),
+ Builder.Alignment, /*PragmaPackResistantAlignment=*/CharUnits::Zero(),
+ Builder.HasOwnVFPtr, RD->isDynamicClass(),
CharUnits::fromQuantity(-1), DataSize, Builder.FieldOffsets,
NonVirtualSize, Builder.NonVirtualAlignment,
Builder.PreferredNVAlignment, Builder.NonVirtualAlignment,
@@ -3520,7 +3533,8 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
*this, Builder.getSize(), Builder.Alignment,
Builder.PreferredAlignment, Builder.UnadjustedAlignment,
/*RequiredAlignment : used by MS-ABI)*/
- Builder.Alignment, Builder.getSize(), Builder.FieldOffsets);
+ Builder.Alignment, /*PragmaPackResistantAlignment=*/CharUnits::Zero(),
+ Builder.getSize(), Builder.FieldOffsets);
}
}
@@ -3656,7 +3670,8 @@ ASTContext::getObjCLayout(const ObjCInterfaceDecl *D) const {
*this, Builder.getSize(), Builder.Alignment, Builder.PreferredAlignment,
Builder.UnadjustedAlignment,
/*RequiredAlignment : used by MS-ABI)*/
- Builder.Alignment, Builder.getDataSize(), Builder.FieldOffsets);
+ Builder.Alignment, /*PragmaPackResistantAlignment=*/CharUnits::Zero(),
+ Builder.getDataSize(), Builder.FieldOffsets);
ObjCLayouts[D] = NewEntry;
More information about the cfe-commits
mailing list