[ms-abi] Handle __declspec(align) on bitfields "properly"
__declspec(align), when applied to bitfields affects their perferred
alignment instead of their required alignment. We don't know why.
Also, #pragma pack(n) turns packing *off* if n is greater than the
pointer size. This is now observable because of the impact of
declspec(align) on bitfields.
llvm-svn: 198907
diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp
index ceb49ff..30293c2 100644
--- a/clang/lib/AST/RecordLayoutBuilder.cpp
+++ b/clang/lib/AST/RecordLayoutBuilder.cpp
@@ -2028,7 +2028,9 @@
// modes).
// * There is no concept of non-virtual alignment or any distinction between
// data size and non-virtual size.
-
+// * __declspec(align) on bitfields has the effect of changing the bitfield's
+// alignment instead of its required alignment. This has implications on how
+// it interacts with pragam pack.
namespace {
struct MicrosoftRecordLayoutBuilder {
@@ -2165,6 +2167,9 @@
MicrosoftRecordLayoutBuilder::getAdjustedElementInfo(
const FieldDecl *FD) {
ElementInfo Info;
+ // Respect align attributes.
+ CharUnits FieldRequiredAlignment =
+ Context.toCharUnitsFromBits(FD->getMaxAlignment());
// Respect attributes applied to subobjects of the field.
if (const RecordType *RT =
FD->getType()->getBaseElementTypeUnsafe()->getAs<RecordType>()) {
@@ -2183,6 +2188,8 @@
Context.getTypeInfoInChars(FD->getType());
Info.Size = FieldInfo.first;
Info.Alignment = FieldInfo.second;
+ if (FD->isBitField() && FD->getMaxAlignment() != 0)
+ Info.Alignment = std::max(Info.Alignment, FieldRequiredAlignment);
// Respect pragma pack.
if (!MaxFieldAlignment.isZero())
Info.Alignment = std::min(Info.Alignment, MaxFieldAlignment);
@@ -2190,13 +2197,13 @@
// Respect packed field attribute.
if (FD->hasAttr<PackedAttr>())
Info.Alignment = CharUnits::One();
- // Respect align attributes.
- CharUnits FieldRequiredAlignment =
- Context.toCharUnitsFromBits(FD->getMaxAlignment());
- // Take required alignment into account.
- Info.Alignment = std::max(Info.Alignment, FieldRequiredAlignment);
- // Capture required alignment as a side-effect.
- RequiredAlignment = std::max(RequiredAlignment, FieldRequiredAlignment);
+ // Take required alignment into account. __declspec(align) on bitfields
+ // impacts the alignment rather than the required alignment.
+ if (!FD->isBitField()) {
+ Info.Alignment = std::max(Info.Alignment, FieldRequiredAlignment);
+ // Capture required alignment as a side-effect.
+ RequiredAlignment = std::max(RequiredAlignment, FieldRequiredAlignment);
+ }
return Info;
}
@@ -2233,10 +2240,14 @@
MaxFieldAlignment = CharUnits::Zero();
// Honor the default struct packing maximum alignment flag.
if (unsigned DefaultMaxFieldAlignment = Context.getLangOpts().PackStruct)
- MaxFieldAlignment = CharUnits::fromQuantity(DefaultMaxFieldAlignment);
- // Honor the packing attribute.
- if (const MaxFieldAlignmentAttr *MFAA = RD->getAttr<MaxFieldAlignmentAttr>())
- MaxFieldAlignment = Context.toCharUnitsFromBits(MFAA->getAlignment());
+ MaxFieldAlignment = CharUnits::fromQuantity(DefaultMaxFieldAlignment);
+ // Honor the packing attribute. The MS-ABI ignores pragma pack if its larger
+ // than the pointer size.
+ if (const MaxFieldAlignmentAttr *MFAA = RD->getAttr<MaxFieldAlignmentAttr>()){
+ unsigned PackedAlignment = MFAA->getAlignment();
+ if (PackedAlignment <= Context.getTargetInfo().getPointerWidth(0))
+ MaxFieldAlignment = Context.toCharUnitsFromBits(PackedAlignment);
+ }
// Packed attribute forces max field alignment to be 1.
if (RD->hasAttr<PackedAttr>())
MaxFieldAlignment = CharUnits::One();
@@ -2335,18 +2346,18 @@
const CXXRecordDecl *BaseDecl,
const ASTRecordLayout &BaseLayout,
const ASTRecordLayout *&PreviousBaseLayout) {
- // Insert padding between two bases if the left first one is zero sized or
- // contains a zero sized subobject and the right is zero sized or one leads
- // with a zero sized base.
- if (PreviousBaseLayout && PreviousBaseLayout->hasZeroSizedSubObject() &&
- BaseLayout.leadsWithZeroSizedBase())
- Size++;
- ElementInfo Info = getAdjustedElementInfo(BaseLayout);
- CharUnits BaseOffset = Size.RoundUpToAlignment(Info.Alignment);
- Bases.insert(std::make_pair(BaseDecl, BaseOffset));
- Size = BaseOffset + BaseLayout.getDataSize();
- updateAlignment(Info.Alignment);
- PreviousBaseLayout = &BaseLayout;
+ // Insert padding between two bases if the left first one is zero sized or
+ // contains a zero sized subobject and the right is zero sized or one leads
+ // with a zero sized base.
+ if (PreviousBaseLayout && PreviousBaseLayout->hasZeroSizedSubObject() &&
+ BaseLayout.leadsWithZeroSizedBase())
+ Size++;
+ ElementInfo Info = getAdjustedElementInfo(BaseLayout);
+ CharUnits BaseOffset = Size.RoundUpToAlignment(Info.Alignment);
+ Bases.insert(std::make_pair(BaseDecl, BaseOffset));
+ Size = BaseOffset + BaseLayout.getDataSize();
+ updateAlignment(Info.Alignment);
+ PreviousBaseLayout = &BaseLayout;
VBPtrOffset = Size;
}
@@ -2598,7 +2609,7 @@
Size = Size.RoundUpToAlignment(VtorDispAlignment) + VtorDispSize;
// Insert the virtual base.
ElementInfo Info = getAdjustedElementInfo(BaseLayout);
- CharUnits BaseOffset = Size.RoundUpToAlignment(Info.Alignment);
+ CharUnits BaseOffset = Size.RoundUpToAlignment(Info.Alignment);
VBases.insert(std::make_pair(BaseDecl,
ASTRecordLayout::VBaseInfo(BaseOffset, HasVtordisp)));
Size = BaseOffset + BaseLayout.getDataSize();