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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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;
 

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to