summaryrefslogtreecommitdiffstats
path: root/lib/AST/RecordLayoutBuilder.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/AST/RecordLayoutBuilder.cpp')
-rw-r--r--lib/AST/RecordLayoutBuilder.cpp221
1 files changed, 146 insertions, 75 deletions
diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp
index 0d070a4..2101a55 100644
--- a/lib/AST/RecordLayoutBuilder.cpp
+++ b/lib/AST/RecordLayoutBuilder.cpp
@@ -55,6 +55,52 @@ struct BaseSubobjectInfo {
const BaseSubobjectInfo *Derived;
};
+/// \brief Externally provided layout. Typically used when the AST source, such
+/// as DWARF, lacks all the information that was available at compile time, such
+/// as alignment attributes on fields and pragmas in effect.
+struct ExternalLayout {
+ ExternalLayout() : Size(0), Align(0) {}
+
+ /// \brief Overall record size in bits.
+ uint64_t Size;
+
+ /// \brief Overall record alignment in bits.
+ uint64_t Align;
+
+ /// \brief Record field offsets in bits.
+ llvm::DenseMap<const FieldDecl *, uint64_t> FieldOffsets;
+
+ /// \brief Direct, non-virtual base offsets.
+ llvm::DenseMap<const CXXRecordDecl *, CharUnits> BaseOffsets;
+
+ /// \brief Virtual base offsets.
+ llvm::DenseMap<const CXXRecordDecl *, CharUnits> VirtualBaseOffsets;
+
+ /// Get the offset of the given field. The external source must provide
+ /// entries for all fields in the record.
+ uint64_t getExternalFieldOffset(const FieldDecl *FD) {
+ assert(FieldOffsets.count(FD) &&
+ "Field does not have an external offset");
+ return FieldOffsets[FD];
+ }
+
+ bool getExternalNVBaseOffset(const CXXRecordDecl *RD, CharUnits &BaseOffset) {
+ auto Known = BaseOffsets.find(RD);
+ if (Known == BaseOffsets.end())
+ return false;
+ BaseOffset = Known->second;
+ return true;
+ }
+
+ bool getExternalVBaseOffset(const CXXRecordDecl *RD, CharUnits &BaseOffset) {
+ auto Known = VirtualBaseOffsets.find(RD);
+ if (Known == VirtualBaseOffsets.end())
+ return false;
+ BaseOffset = Known->second;
+ return true;
+ }
+};
+
/// EmptySubobjectMap - Keeps track of which empty subobjects exist at different
/// offsets while laying out a C++ class.
class EmptySubobjectMap {
@@ -541,7 +587,7 @@ protected:
/// \brief Whether the external AST source has provided a layout for this
/// record.
- unsigned ExternalLayout : 1;
+ unsigned UseExternalLayout : 1;
/// \brief Whether we need to infer alignment, even when we have an
/// externally-provided layout.
@@ -607,26 +653,14 @@ protected:
/// avoid visiting virtual bases more than once.
llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBases;
- /// \brief Externally-provided size.
- uint64_t ExternalSize;
-
- /// \brief Externally-provided alignment.
- uint64_t ExternalAlign;
-
- /// \brief Externally-provided field offsets.
- llvm::DenseMap<const FieldDecl *, uint64_t> ExternalFieldOffsets;
-
- /// \brief Externally-provided direct, non-virtual base offsets.
- llvm::DenseMap<const CXXRecordDecl *, CharUnits> ExternalBaseOffsets;
-
- /// \brief Externally-provided virtual base offsets.
- llvm::DenseMap<const CXXRecordDecl *, CharUnits> ExternalVirtualBaseOffsets;
+ /// Valid if UseExternalLayout is true.
+ ExternalLayout External;
RecordLayoutBuilder(const ASTContext &Context,
EmptySubobjectMap *EmptySubobjects)
: Context(Context), EmptySubobjects(EmptySubobjects), Size(0),
Alignment(CharUnits::One()), UnpackedAlignment(CharUnits::One()),
- ExternalLayout(false), InferAlignment(false),
+ UseExternalLayout(false), InferAlignment(false),
Packed(false), IsUnion(false), IsMac68kAlign(false), IsMsStruct(false),
UnfilledBitsInLastUnit(0), LastBitfieldTypeSize(0),
MaxFieldAlignment(CharUnits::Zero()),
@@ -748,8 +782,8 @@ protected:
void setDataSize(CharUnits NewSize) { DataSize = Context.toBits(NewSize); }
void setDataSize(uint64_t NewSize) { DataSize = NewSize; }
- RecordLayoutBuilder(const RecordLayoutBuilder &) LLVM_DELETED_FUNCTION;
- void operator=(const RecordLayoutBuilder &) LLVM_DELETED_FUNCTION;
+ RecordLayoutBuilder(const RecordLayoutBuilder &) = delete;
+ void operator=(const RecordLayoutBuilder &) = delete;
};
} // end anonymous namespace
@@ -1134,21 +1168,12 @@ CharUnits RecordLayoutBuilder::LayoutBase(const BaseSubobjectInfo *Base) {
// Query the external layout to see if it provides an offset.
bool HasExternalLayout = false;
- if (ExternalLayout) {
+ if (UseExternalLayout) {
llvm::DenseMap<const CXXRecordDecl *, CharUnits>::iterator Known;
- if (Base->IsVirtual) {
- Known = ExternalVirtualBaseOffsets.find(Base->Class);
- if (Known != ExternalVirtualBaseOffsets.end()) {
- Offset = Known->second;
- HasExternalLayout = true;
- }
- } else {
- Known = ExternalBaseOffsets.find(Base->Class);
- if (Known != ExternalBaseOffsets.end()) {
- Offset = Known->second;
- HasExternalLayout = true;
- }
- }
+ if (Base->IsVirtual)
+ HasExternalLayout = External.getExternalNVBaseOffset(Base->Class, Offset);
+ else
+ HasExternalLayout = External.getExternalVBaseOffset(Base->Class, Offset);
}
CharUnits UnpackedBaseAlign = Layout.getNonVirtualAlignment();
@@ -1235,18 +1260,15 @@ void RecordLayoutBuilder::InitializeLayout(const Decl *D) {
// If there is an external AST source, ask it for the various offsets.
if (const RecordDecl *RD = dyn_cast<RecordDecl>(D))
- if (ExternalASTSource *External = Context.getExternalSource()) {
- ExternalLayout = External->layoutRecordType(RD,
- ExternalSize,
- ExternalAlign,
- ExternalFieldOffsets,
- ExternalBaseOffsets,
- ExternalVirtualBaseOffsets);
-
+ if (ExternalASTSource *Source = Context.getExternalSource()) {
+ UseExternalLayout = Source->layoutRecordType(
+ RD, External.Size, External.Align, External.FieldOffsets,
+ External.BaseOffsets, External.VirtualBaseOffsets);
+
// Update based on external alignment.
- if (ExternalLayout) {
- if (ExternalAlign > 0) {
- Alignment = Context.toCharUnitsFromBits(ExternalAlign);
+ if (UseExternalLayout) {
+ if (External.Align > 0) {
+ Alignment = Context.toCharUnitsFromBits(External.Align);
} else {
// The external source didn't have alignment information; infer it.
InferAlignment = true;
@@ -1588,7 +1610,7 @@ void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
// If we're using external layout, give the external layout a chance
// to override this information.
- if (ExternalLayout)
+ if (UseExternalLayout)
FieldOffset = updateExternalFieldOffset(D, FieldOffset);
// Okay, place the bitfield at the calculated offset.
@@ -1604,7 +1626,7 @@ void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
FieldAlign = UnpackedFieldAlign = 1;
// Diagnose differences in layout due to padding or packing.
- if (!ExternalLayout)
+ if (!UseExternalLayout)
CheckFieldPadding(FieldOffset, UnpaddedFieldOffset, UnpackedFieldOffset,
UnpackedFieldAlign, FieldPacked, D);
@@ -1727,7 +1749,7 @@ void RecordLayoutBuilder::LayoutField(const FieldDecl *D,
UnpackedFieldOffset =
UnpackedFieldOffset.RoundUpToAlignment(UnpackedFieldAlign);
- if (ExternalLayout) {
+ if (UseExternalLayout) {
FieldOffset = Context.toCharUnitsFromBits(
updateExternalFieldOffset(D, Context.toBits(FieldOffset)));
@@ -1750,7 +1772,7 @@ void RecordLayoutBuilder::LayoutField(const FieldDecl *D,
// Place this field at the current location.
FieldOffsets.push_back(Context.toBits(FieldOffset));
- if (!ExternalLayout)
+ if (!UseExternalLayout)
CheckFieldPadding(Context.toBits(FieldOffset), UnpaddedFieldOffset,
Context.toBits(UnpackedFieldOffset),
Context.toBits(UnpackedFieldAlign), FieldPacked, D);
@@ -1802,15 +1824,15 @@ void RecordLayoutBuilder::FinishLayout(const NamedDecl *D) {
uint64_t RoundedSize
= llvm::RoundUpToAlignment(getSizeInBits(), Context.toBits(Alignment));
- if (ExternalLayout) {
+ if (UseExternalLayout) {
// If we're inferring alignment, and the external size is smaller than
// our size after we've rounded up to alignment, conservatively set the
// alignment to 1.
- if (InferAlignment && ExternalSize < RoundedSize) {
+ if (InferAlignment && External.Size < RoundedSize) {
Alignment = CharUnits::One();
InferAlignment = false;
}
- setSize(ExternalSize);
+ setSize(External.Size);
return;
}
@@ -1846,18 +1868,18 @@ void RecordLayoutBuilder::UpdateAlignment(CharUnits NewAlignment,
CharUnits UnpackedNewAlignment) {
// The alignment is not modified when using 'mac68k' alignment or when
// we have an externally-supplied layout that also provides overall alignment.
- if (IsMac68kAlign || (ExternalLayout && !InferAlignment))
+ if (IsMac68kAlign || (UseExternalLayout && !InferAlignment))
return;
if (NewAlignment > Alignment) {
- assert(llvm::isPowerOf2_32(NewAlignment.getQuantity() &&
- "Alignment not a power of 2"));
+ assert(llvm::isPowerOf2_64(NewAlignment.getQuantity()) &&
+ "Alignment not a power of 2");
Alignment = NewAlignment;
}
if (UnpackedNewAlignment > UnpackedAlignment) {
- assert(llvm::isPowerOf2_32(UnpackedNewAlignment.getQuantity() &&
- "Alignment not a power of 2"));
+ assert(llvm::isPowerOf2_64(UnpackedNewAlignment.getQuantity()) &&
+ "Alignment not a power of 2");
UnpackedAlignment = UnpackedNewAlignment;
}
}
@@ -1865,11 +1887,8 @@ void RecordLayoutBuilder::UpdateAlignment(CharUnits NewAlignment,
uint64_t
RecordLayoutBuilder::updateExternalFieldOffset(const FieldDecl *Field,
uint64_t ComputedOffset) {
- assert(ExternalFieldOffsets.find(Field) != ExternalFieldOffsets.end() &&
- "Field does not have an external offset");
-
- uint64_t ExternalFieldOffset = ExternalFieldOffsets[Field];
-
+ uint64_t ExternalFieldOffset = External.getExternalFieldOffset(Field);
+
if (InferAlignment && ExternalFieldOffset < ComputedOffset) {
// The externally-supplied field offset is before the field offset we
// computed. Assume that the structure is packed.
@@ -2152,9 +2171,8 @@ struct MicrosoftRecordLayoutBuilder {
typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits> BaseOffsetsMapTy;
MicrosoftRecordLayoutBuilder(const ASTContext &Context) : Context(Context) {}
private:
- MicrosoftRecordLayoutBuilder(const MicrosoftRecordLayoutBuilder &)
- LLVM_DELETED_FUNCTION;
- void operator=(const MicrosoftRecordLayoutBuilder &) LLVM_DELETED_FUNCTION;
+ MicrosoftRecordLayoutBuilder(const MicrosoftRecordLayoutBuilder &) = delete;
+ void operator=(const MicrosoftRecordLayoutBuilder &) = delete;
public:
void layout(const RecordDecl *RD);
void cxxLayout(const CXXRecordDecl *RD);
@@ -2252,6 +2270,13 @@ public:
/// \brief True if this class is zero sized or first base is zero sized or
/// has this property. Only used for MS-ABI.
bool LeadsWithZeroSizedBase : 1;
+
+ /// \brief True if the external AST source provided a layout for this record.
+ bool UseExternalLayout : 1;
+
+ /// \brief The layout provided by the external AST source. Only active if
+ /// UseExternalLayout is true.
+ ExternalLayout External;
};
} // namespace
@@ -2354,8 +2379,9 @@ void MicrosoftRecordLayoutBuilder::initializeLayout(const RecordDecl *RD) {
// In 64-bit mode we always perform an alignment step after laying out vbases.
// In 32-bit mode we do not. The check to see if we need to perform alignment
// checks the RequiredAlignment field and performs alignment if it isn't 0.
- RequiredAlignment = Context.getTargetInfo().getPointerWidth(0) == 64 ?
- CharUnits::One() : CharUnits::Zero();
+ RequiredAlignment = Context.getTargetInfo().getTriple().isArch64Bit()
+ ? CharUnits::One()
+ : CharUnits::Zero();
// Compute the maximum field alignment.
MaxFieldAlignment = CharUnits::Zero();
// Honor the default struct packing maximum alignment flag.
@@ -2371,6 +2397,13 @@ void MicrosoftRecordLayoutBuilder::initializeLayout(const RecordDecl *RD) {
// Packed attribute forces max field alignment to be 1.
if (RD->hasAttr<PackedAttr>())
MaxFieldAlignment = CharUnits::One();
+
+ // Try to respect the external layout if present.
+ UseExternalLayout = false;
+ if (ExternalASTSource *Source = Context.getExternalSource())
+ UseExternalLayout = Source->layoutRecordType(
+ RD, External.Size, External.Align, External.FieldOffsets,
+ External.BaseOffsets, External.VirtualBaseOffsets);
}
void
@@ -2385,7 +2418,8 @@ MicrosoftRecordLayoutBuilder::initializeCXXLayout(const CXXRecordDecl *RD) {
// injection.
PointerInfo.Size =
Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0));
- PointerInfo.Alignment = PointerInfo.Size;
+ PointerInfo.Alignment =
+ Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerAlign(0));
// Respect pragma pack.
if (!MaxFieldAlignment.isZero())
PointerInfo.Alignment = std::min(PointerInfo.Alignment, MaxFieldAlignment);
@@ -2475,7 +2509,18 @@ void MicrosoftRecordLayoutBuilder::layoutNonVirtualBase(
BaseLayout.leadsWithZeroSizedBase())
Size++;
ElementInfo Info = getAdjustedElementInfo(BaseLayout);
- CharUnits BaseOffset = Size.RoundUpToAlignment(Info.Alignment);
+ CharUnits BaseOffset;
+
+ // Respect the external AST source base offset, if present.
+ bool FoundBase = false;
+ if (UseExternalLayout) {
+ FoundBase = External.getExternalNVBaseOffset(BaseDecl, BaseOffset);
+ if (FoundBase)
+ assert(BaseOffset >= Size && "base offset already allocated");
+ }
+
+ if (!FoundBase)
+ BaseOffset = Size.RoundUpToAlignment(Info.Alignment);
Bases.insert(std::make_pair(BaseDecl, BaseOffset));
Size = BaseOffset + BaseLayout.getNonVirtualSize();
PreviousBaseLayout = &BaseLayout;
@@ -2499,7 +2544,14 @@ void MicrosoftRecordLayoutBuilder::layoutField(const FieldDecl *FD) {
placeFieldAtOffset(CharUnits::Zero());
Size = std::max(Size, Info.Size);
} else {
- CharUnits FieldOffset = Size.RoundUpToAlignment(Info.Alignment);
+ CharUnits FieldOffset;
+ if (UseExternalLayout) {
+ FieldOffset =
+ Context.toCharUnitsFromBits(External.getExternalFieldOffset(FD));
+ assert(FieldOffset >= Size && "field offset already allocated");
+ } else {
+ FieldOffset = Size.RoundUpToAlignment(Info.Alignment);
+ }
placeFieldAtOffset(FieldOffset);
Size = FieldOffset + Info.Size;
}
@@ -2573,14 +2625,16 @@ void MicrosoftRecordLayoutBuilder::injectVBPtr(const CXXRecordDecl *RD) {
CharUnits InjectionSite = VBPtrOffset;
// But before we do, make sure it's properly aligned.
VBPtrOffset = VBPtrOffset.RoundUpToAlignment(PointerInfo.Alignment);
+ // Shift everything after the vbptr down, unless we're using an external
+ // layout.
+ if (UseExternalLayout)
+ return;
// Determine where the first field should be laid out after the vbptr.
CharUnits FieldStart = VBPtrOffset + PointerInfo.Size;
// Make sure that the amount we push the fields back by is a multiple of the
// alignment.
CharUnits Offset = (FieldStart - InjectionSite).RoundUpToAlignment(
std::max(RequiredAlignment, Alignment));
- // Increase the size of the object and push back all fields by the offset
- // amount.
Size += Offset;
for (uint64_t &FieldOffset : FieldOffsets)
FieldOffset += Context.toBits(Offset);
@@ -2647,7 +2701,18 @@ void MicrosoftRecordLayoutBuilder::layoutVirtualBases(const CXXRecordDecl *RD) {
}
// Insert the virtual base.
ElementInfo Info = getAdjustedElementInfo(BaseLayout);
- CharUnits BaseOffset = Size.RoundUpToAlignment(Info.Alignment);
+ CharUnits BaseOffset;
+
+ // Respect the external AST source base offset, if present.
+ bool FoundBase = false;
+ if (UseExternalLayout) {
+ FoundBase = External.getExternalVBaseOffset(BaseDecl, BaseOffset);
+ if (FoundBase)
+ assert(BaseOffset >= Size && "base offset already allocated");
+ }
+ if (!FoundBase)
+ BaseOffset = Size.RoundUpToAlignment(Info.Alignment);
+
VBases.insert(std::make_pair(BaseDecl,
ASTRecordLayout::VBaseInfo(BaseOffset, HasVtordisp)));
Size = BaseOffset + BaseLayout.getNonVirtualSize();
@@ -2677,6 +2742,12 @@ void MicrosoftRecordLayoutBuilder::finalizeLayout(const RecordDecl *RD) {
else
Size = MinEmptyStructSize;
}
+
+ if (UseExternalLayout) {
+ Size = Context.toCharUnitsFromBits(External.Size);
+ if (External.Align)
+ Alignment = Context.toCharUnitsFromBits(External.Align);
+ }
}
// Recursively walks the non-virtual bases of a class and determines if any of
@@ -2815,7 +2886,7 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
const ASTRecordLayout *NewEntry = nullptr;
- if (isMsLayout(D) && !D->getASTContext().getExternalSource()) {
+ if (isMsLayout(D)) {
NewEntry = BuildMicrosoftASTRecordLayout(D);
} else if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
EmptySubobjectMap EmptySubobjects(*this, RD);
@@ -2905,11 +2976,11 @@ void ASTContext::setNonKeyFunction(const CXXMethodDecl *Method) {
// Look up the cache entry. Since we're working with the first
// declaration, its parent must be the class definition, which is
// the correct key for the KeyFunctions hash.
- llvm::DenseMap<const CXXRecordDecl*, LazyDeclPtr>::iterator
- I = KeyFunctions.find(Method->getParent());
+ const auto &Map = KeyFunctions;
+ auto I = Map.find(Method->getParent());
// If it's not cached, there's nothing to do.
- if (I == KeyFunctions.end()) return;
+ if (I == Map.end()) return;
// If it is cached, check whether it's the target method, and if so,
// remove it from the cache. Note, the call to 'get' might invalidate
OpenPOWER on IntegriCloud