aboutsummaryrefslogtreecommitdiff
path: root/lib/AST/RecordLayoutBuilder.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/AST/RecordLayoutBuilder.cpp')
-rw-r--r--lib/AST/RecordLayoutBuilder.cpp649
1 files changed, 409 insertions, 240 deletions
diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp
index 13fae299d877..cf14eba1405d 100644
--- a/lib/AST/RecordLayoutBuilder.cpp
+++ b/lib/AST/RecordLayoutBuilder.cpp
@@ -8,12 +8,14 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/Attr.h"
+#include "clang/AST/CXXInheritance.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
#include "clang/AST/RecordLayout.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/Sema/SemaDiagnostic.h"
#include "llvm/Support/Format.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/Support/MathExtras.h"
@@ -55,62 +57,71 @@ struct BaseSubobjectInfo {
/// EmptySubobjectMap - Keeps track of which empty subobjects exist at different
/// offsets while laying out a C++ class.
class EmptySubobjectMap {
- ASTContext &Context;
-
+ const ASTContext &Context;
+ uint64_t CharWidth;
+
/// Class - The class whose empty entries we're keeping track of.
const CXXRecordDecl *Class;
/// EmptyClassOffsets - A map from offsets to empty record decls.
typedef llvm::SmallVector<const CXXRecordDecl *, 1> ClassVectorTy;
- typedef llvm::DenseMap<uint64_t, ClassVectorTy> EmptyClassOffsetsMapTy;
+ typedef llvm::DenseMap<CharUnits, ClassVectorTy> EmptyClassOffsetsMapTy;
EmptyClassOffsetsMapTy EmptyClassOffsets;
/// MaxEmptyClassOffset - The highest offset known to contain an empty
/// base subobject.
- uint64_t MaxEmptyClassOffset;
+ CharUnits MaxEmptyClassOffset;
/// ComputeEmptySubobjectSizes - Compute the size of the largest base or
/// member subobject that is empty.
void ComputeEmptySubobjectSizes();
- void AddSubobjectAtOffset(const CXXRecordDecl *RD, uint64_t Offset);
+ void AddSubobjectAtOffset(const CXXRecordDecl *RD, CharUnits Offset);
void UpdateEmptyBaseSubobjects(const BaseSubobjectInfo *Info,
- uint64_t Offset, bool PlacingEmptyBase);
+ CharUnits Offset, bool PlacingEmptyBase);
void UpdateEmptyFieldSubobjects(const CXXRecordDecl *RD,
const CXXRecordDecl *Class,
- uint64_t Offset);
- void UpdateEmptyFieldSubobjects(const FieldDecl *FD, uint64_t Offset);
+ CharUnits Offset);
+ void UpdateEmptyFieldSubobjects(const FieldDecl *FD, CharUnits Offset);
/// AnyEmptySubobjectsBeyondOffset - Returns whether there are any empty
/// subobjects beyond the given offset.
- bool AnyEmptySubobjectsBeyondOffset(uint64_t Offset) const {
+ bool AnyEmptySubobjectsBeyondOffset(CharUnits Offset) const {
return Offset <= MaxEmptyClassOffset;
}
+ CharUnits
+ getFieldOffset(const ASTRecordLayout &Layout, unsigned FieldNo) const {
+ uint64_t FieldOffset = Layout.getFieldOffset(FieldNo);
+ assert(FieldOffset % CharWidth == 0 &&
+ "Field offset not at char boundary!");
+
+ return Context.toCharUnitsFromBits(FieldOffset);
+ }
+
protected:
- bool CanPlaceSubobjectAtOffset(const CXXRecordDecl *RD,
- uint64_t Offset) const;
+ bool CanPlaceSubobjectAtOffset(const CXXRecordDecl *RD,
+ CharUnits Offset) const;
bool CanPlaceBaseSubobjectAtOffset(const BaseSubobjectInfo *Info,
- uint64_t Offset);
+ CharUnits Offset);
bool CanPlaceFieldSubobjectAtOffset(const CXXRecordDecl *RD,
const CXXRecordDecl *Class,
- uint64_t Offset) const;
+ CharUnits Offset) const;
bool CanPlaceFieldSubobjectAtOffset(const FieldDecl *FD,
- uint64_t Offset) const;
+ CharUnits Offset) const;
public:
/// This holds the size of the largest empty subobject (either a base
/// or a member). Will be zero if the record being built doesn't contain
/// any empty classes.
- uint64_t SizeOfLargestEmptySubobject;
+ CharUnits SizeOfLargestEmptySubobject;
- EmptySubobjectMap(ASTContext &Context, const CXXRecordDecl *Class)
- : Context(Context), Class(Class), MaxEmptyClassOffset(0),
- SizeOfLargestEmptySubobject(0) {
+ EmptySubobjectMap(const ASTContext &Context, const CXXRecordDecl *Class)
+ : Context(Context), CharWidth(Context.getCharWidth()), Class(Class) {
ComputeEmptySubobjectSizes();
}
@@ -119,11 +130,11 @@ public:
/// Returns false if placing the record will result in two components
/// (direct or indirect) of the same type having the same offset.
bool CanPlaceBaseAtOffset(const BaseSubobjectInfo *Info,
- uint64_t Offset);
+ CharUnits Offset);
/// CanPlaceFieldAtOffset - Return whether a field can be placed at the given
/// offset.
- bool CanPlaceFieldAtOffset(const FieldDecl *FD, uint64_t Offset);
+ bool CanPlaceFieldAtOffset(const FieldDecl *FD, CharUnits Offset);
};
void EmptySubobjectMap::ComputeEmptySubobjectSizes() {
@@ -133,7 +144,7 @@ void EmptySubobjectMap::ComputeEmptySubobjectSizes() {
const CXXRecordDecl *BaseDecl =
cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
- uint64_t EmptySize = 0;
+ CharUnits EmptySize;
const ASTRecordLayout &Layout = Context.getASTRecordLayout(BaseDecl);
if (BaseDecl->isEmpty()) {
// If the class decl is empty, get its size.
@@ -143,8 +154,8 @@ void EmptySubobjectMap::ComputeEmptySubobjectSizes() {
EmptySize = Layout.getSizeOfLargestEmptySubobject();
}
- SizeOfLargestEmptySubobject = std::max(SizeOfLargestEmptySubobject,
- EmptySize);
+ if (EmptySize > SizeOfLargestEmptySubobject)
+ SizeOfLargestEmptySubobject = EmptySize;
}
// Check the fields.
@@ -159,7 +170,7 @@ void EmptySubobjectMap::ComputeEmptySubobjectSizes() {
if (!RT)
continue;
- uint64_t EmptySize = 0;
+ CharUnits EmptySize;
const CXXRecordDecl *MemberDecl = cast<CXXRecordDecl>(RT->getDecl());
const ASTRecordLayout &Layout = Context.getASTRecordLayout(MemberDecl);
if (MemberDecl->isEmpty()) {
@@ -170,14 +181,14 @@ void EmptySubobjectMap::ComputeEmptySubobjectSizes() {
EmptySize = Layout.getSizeOfLargestEmptySubobject();
}
- SizeOfLargestEmptySubobject = std::max(SizeOfLargestEmptySubobject,
- EmptySize);
+ if (EmptySize > SizeOfLargestEmptySubobject)
+ SizeOfLargestEmptySubobject = EmptySize;
}
}
bool
EmptySubobjectMap::CanPlaceSubobjectAtOffset(const CXXRecordDecl *RD,
- uint64_t Offset) const {
+ CharUnits Offset) const {
// We only need to check empty bases.
if (!RD->isEmpty())
return true;
@@ -195,24 +206,27 @@ EmptySubobjectMap::CanPlaceSubobjectAtOffset(const CXXRecordDecl *RD,
}
void EmptySubobjectMap::AddSubobjectAtOffset(const CXXRecordDecl *RD,
- uint64_t Offset) {
+ CharUnits Offset) {
// We only care about empty bases.
if (!RD->isEmpty())
return;
+ // If we have empty structures inside an union, we can assign both
+ // the same offset. Just avoid pushing them twice in the list.
ClassVectorTy& Classes = EmptyClassOffsets[Offset];
- assert(std::find(Classes.begin(), Classes.end(), RD) == Classes.end() &&
- "Duplicate empty class detected!");
-
+ if (std::find(Classes.begin(), Classes.end(), RD) != Classes.end())
+ return;
+
Classes.push_back(RD);
// Update the empty class offset.
- MaxEmptyClassOffset = std::max(MaxEmptyClassOffset, Offset);
+ if (Offset > MaxEmptyClassOffset)
+ MaxEmptyClassOffset = Offset;
}
bool
-EmptySubobjectMap::CanPlaceBaseSubobjectAtOffset(const BaseSubobjectInfo *Info,
- uint64_t Offset) {
+EmptySubobjectMap::CanPlaceBaseSubobjectAtOffset(const BaseSubobjectInfo *Info,
+ CharUnits Offset) {
// We don't have to keep looking past the maximum offset that's known to
// contain an empty class.
if (!AnyEmptySubobjectsBeyondOffset(Offset))
@@ -228,7 +242,7 @@ EmptySubobjectMap::CanPlaceBaseSubobjectAtOffset(const BaseSubobjectInfo *Info,
if (Base->IsVirtual)
continue;
- uint64_t BaseOffset = Offset + Layout.getBaseClassOffset(Base->Class);
+ CharUnits BaseOffset = Offset + Layout.getBaseClassOffset(Base->Class);
if (!CanPlaceBaseSubobjectAtOffset(Base, BaseOffset))
return false;
@@ -248,8 +262,10 @@ EmptySubobjectMap::CanPlaceBaseSubobjectAtOffset(const BaseSubobjectInfo *Info,
for (CXXRecordDecl::field_iterator I = Info->Class->field_begin(),
E = Info->Class->field_end(); I != E; ++I, ++FieldNo) {
const FieldDecl *FD = *I;
-
- uint64_t FieldOffset = Offset + Layout.getFieldOffset(FieldNo);
+ if (FD->isBitField())
+ continue;
+
+ CharUnits FieldOffset = Offset + getFieldOffset(Layout, FieldNo);
if (!CanPlaceFieldSubobjectAtOffset(FD, FieldOffset))
return false;
}
@@ -258,7 +274,7 @@ EmptySubobjectMap::CanPlaceBaseSubobjectAtOffset(const BaseSubobjectInfo *Info,
}
void EmptySubobjectMap::UpdateEmptyBaseSubobjects(const BaseSubobjectInfo *Info,
- uint64_t Offset,
+ CharUnits Offset,
bool PlacingEmptyBase) {
if (!PlacingEmptyBase && Offset >= SizeOfLargestEmptySubobject) {
// We know that the only empty subobjects that can conflict with empty
@@ -278,7 +294,7 @@ void EmptySubobjectMap::UpdateEmptyBaseSubobjects(const BaseSubobjectInfo *Info,
if (Base->IsVirtual)
continue;
- uint64_t BaseOffset = Offset + Layout.getBaseClassOffset(Base->Class);
+ CharUnits BaseOffset = Offset + Layout.getBaseClassOffset(Base->Class);
UpdateEmptyBaseSubobjects(Base, BaseOffset, PlacingEmptyBase);
}
@@ -295,17 +311,19 @@ void EmptySubobjectMap::UpdateEmptyBaseSubobjects(const BaseSubobjectInfo *Info,
for (CXXRecordDecl::field_iterator I = Info->Class->field_begin(),
E = Info->Class->field_end(); I != E; ++I, ++FieldNo) {
const FieldDecl *FD = *I;
+ if (FD->isBitField())
+ continue;
- uint64_t FieldOffset = Offset + Layout.getFieldOffset(FieldNo);
+ CharUnits FieldOffset = Offset + getFieldOffset(Layout, FieldNo);
UpdateEmptyFieldSubobjects(FD, FieldOffset);
}
}
bool EmptySubobjectMap::CanPlaceBaseAtOffset(const BaseSubobjectInfo *Info,
- uint64_t Offset) {
+ CharUnits Offset) {
// If we know this class doesn't have any empty subobjects we don't need to
// bother checking.
- if (!SizeOfLargestEmptySubobject)
+ if (SizeOfLargestEmptySubobject.isZero())
return true;
if (!CanPlaceBaseSubobjectAtOffset(Info, Offset))
@@ -320,7 +338,7 @@ bool EmptySubobjectMap::CanPlaceBaseAtOffset(const BaseSubobjectInfo *Info,
bool
EmptySubobjectMap::CanPlaceFieldSubobjectAtOffset(const CXXRecordDecl *RD,
const CXXRecordDecl *Class,
- uint64_t Offset) const {
+ CharUnits Offset) const {
// We don't have to keep looking past the maximum offset that's known to
// contain an empty class.
if (!AnyEmptySubobjectsBeyondOffset(Offset))
@@ -340,7 +358,7 @@ EmptySubobjectMap::CanPlaceFieldSubobjectAtOffset(const CXXRecordDecl *RD,
const CXXRecordDecl *BaseDecl =
cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
- uint64_t BaseOffset = Offset + Layout.getBaseClassOffset(BaseDecl);
+ CharUnits BaseOffset = Offset + Layout.getBaseClassOffset(BaseDecl);
if (!CanPlaceFieldSubobjectAtOffset(BaseDecl, Class, BaseOffset))
return false;
}
@@ -352,7 +370,7 @@ EmptySubobjectMap::CanPlaceFieldSubobjectAtOffset(const CXXRecordDecl *RD,
const CXXRecordDecl *VBaseDecl =
cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
- uint64_t VBaseOffset = Offset + Layout.getVBaseClassOffset(VBaseDecl);
+ CharUnits VBaseOffset = Offset + Layout.getVBaseClassOffset(VBaseDecl);
if (!CanPlaceFieldSubobjectAtOffset(VBaseDecl, Class, VBaseOffset))
return false;
}
@@ -363,8 +381,10 @@ EmptySubobjectMap::CanPlaceFieldSubobjectAtOffset(const CXXRecordDecl *RD,
for (CXXRecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();
I != E; ++I, ++FieldNo) {
const FieldDecl *FD = *I;
-
- uint64_t FieldOffset = Offset + Layout.getFieldOffset(FieldNo);
+ if (FD->isBitField())
+ continue;
+
+ CharUnits FieldOffset = Offset + getFieldOffset(Layout, FieldNo);
if (!CanPlaceFieldSubobjectAtOffset(FD, FieldOffset))
return false;
@@ -373,8 +393,9 @@ EmptySubobjectMap::CanPlaceFieldSubobjectAtOffset(const CXXRecordDecl *RD,
return true;
}
-bool EmptySubobjectMap::CanPlaceFieldSubobjectAtOffset(const FieldDecl *FD,
- uint64_t Offset) const {
+bool
+EmptySubobjectMap::CanPlaceFieldSubobjectAtOffset(const FieldDecl *FD,
+ CharUnits Offset) const {
// We don't have to keep looking past the maximum offset that's known to
// contain an empty class.
if (!AnyEmptySubobjectsBeyondOffset(Offset))
@@ -397,7 +418,7 @@ bool EmptySubobjectMap::CanPlaceFieldSubobjectAtOffset(const FieldDecl *FD,
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
uint64_t NumElements = Context.getConstantArrayElementCount(AT);
- uint64_t ElementOffset = Offset;
+ CharUnits ElementOffset = Offset;
for (uint64_t I = 0; I != NumElements; ++I) {
// We don't have to keep looking past the maximum offset that's known to
// contain an empty class.
@@ -415,7 +436,8 @@ bool EmptySubobjectMap::CanPlaceFieldSubobjectAtOffset(const FieldDecl *FD,
}
bool
-EmptySubobjectMap::CanPlaceFieldAtOffset(const FieldDecl *FD, uint64_t Offset) {
+EmptySubobjectMap::CanPlaceFieldAtOffset(const FieldDecl *FD,
+ CharUnits Offset) {
if (!CanPlaceFieldSubobjectAtOffset(FD, Offset))
return false;
@@ -427,7 +449,7 @@ EmptySubobjectMap::CanPlaceFieldAtOffset(const FieldDecl *FD, uint64_t Offset) {
void EmptySubobjectMap::UpdateEmptyFieldSubobjects(const CXXRecordDecl *RD,
const CXXRecordDecl *Class,
- uint64_t Offset) {
+ CharUnits Offset) {
// We know that the only empty subobjects that can conflict with empty
// field subobjects are subobjects of empty bases that can be placed at offset
// zero. Because of this, we only need to keep track of empty field
@@ -449,7 +471,7 @@ void EmptySubobjectMap::UpdateEmptyFieldSubobjects(const CXXRecordDecl *RD,
const CXXRecordDecl *BaseDecl =
cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
- uint64_t BaseOffset = Offset + Layout.getBaseClassOffset(BaseDecl);
+ CharUnits BaseOffset = Offset + Layout.getBaseClassOffset(BaseDecl);
UpdateEmptyFieldSubobjects(BaseDecl, Class, BaseOffset);
}
@@ -460,7 +482,7 @@ void EmptySubobjectMap::UpdateEmptyFieldSubobjects(const CXXRecordDecl *RD,
const CXXRecordDecl *VBaseDecl =
cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
- uint64_t VBaseOffset = Offset + Layout.getVBaseClassOffset(VBaseDecl);
+ CharUnits VBaseOffset = Offset + Layout.getVBaseClassOffset(VBaseDecl);
UpdateEmptyFieldSubobjects(VBaseDecl, Class, VBaseOffset);
}
}
@@ -470,15 +492,17 @@ void EmptySubobjectMap::UpdateEmptyFieldSubobjects(const CXXRecordDecl *RD,
for (CXXRecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();
I != E; ++I, ++FieldNo) {
const FieldDecl *FD = *I;
-
- uint64_t FieldOffset = Offset + Layout.getFieldOffset(FieldNo);
+ if (FD->isBitField())
+ continue;
+
+ CharUnits FieldOffset = Offset + getFieldOffset(Layout, FieldNo);
UpdateEmptyFieldSubobjects(FD, FieldOffset);
}
}
void EmptySubobjectMap::UpdateEmptyFieldSubobjects(const FieldDecl *FD,
- uint64_t Offset) {
+ CharUnits Offset) {
QualType T = FD->getType();
if (const RecordType *RT = T->getAs<RecordType>()) {
const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
@@ -497,7 +521,7 @@ void EmptySubobjectMap::UpdateEmptyFieldSubobjects(const FieldDecl *FD,
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
uint64_t NumElements = Context.getConstantArrayElementCount(AT);
- uint64_t ElementOffset = Offset;
+ CharUnits ElementOffset = Offset;
for (uint64_t I = 0; I != NumElements; ++I) {
// We know that the only empty subobjects that can conflict with empty
@@ -519,7 +543,7 @@ protected:
// FIXME: Remove this and make the appropriate fields public.
friend class clang::ASTContext;
- ASTContext &Context;
+ const ASTContext &Context;
EmptySubobjectMap *EmptySubobjects;
@@ -527,7 +551,10 @@ protected:
uint64_t Size;
/// Alignment - The current alignment of the record layout.
- unsigned Alignment;
+ CharUnits Alignment;
+
+ /// \brief The alignment if attribute packed is not used.
+ CharUnits UnpackedAlignment;
llvm::SmallVector<uint64_t, 16> FieldOffsets;
@@ -545,13 +572,13 @@ protected:
/// MaxFieldAlignment - The maximum allowed field alignment. This is set by
/// #pragma pack.
- unsigned MaxFieldAlignment;
+ CharUnits MaxFieldAlignment;
/// DataSize - The data size of the record being laid out.
uint64_t DataSize;
- uint64_t NonVirtualSize;
- unsigned NonVirtualAlignment;
+ CharUnits NonVirtualSize;
+ CharUnits NonVirtualAlignment;
/// PrimaryBase - the primary base class (if one exists) of the class
/// we're laying out.
@@ -561,7 +588,7 @@ protected:
/// out is virtual.
bool PrimaryBaseIsVirtual;
- typedef llvm::DenseMap<const CXXRecordDecl *, uint64_t> BaseOffsetsMapTy;
+ typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits> BaseOffsetsMapTy;
/// Bases - base classes and their offsets in the record.
BaseOffsetsMapTy Bases;
@@ -571,7 +598,7 @@ protected:
/// IndirectPrimaryBases - Virtual base classes, direct or indirect, that are
/// primary base classes for some other direct or indirect base class.
- llvm::SmallSet<const CXXRecordDecl*, 32> IndirectPrimaryBases;
+ CXXIndirectPrimaryBaseSet IndirectPrimaryBases;
/// FirstNearlyEmptyVBase - The first nearly empty virtual base class in
/// inheritance graph order. Used for determining the primary base class.
@@ -581,11 +608,14 @@ protected:
/// avoid visiting virtual bases more than once.
llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBases;
- RecordLayoutBuilder(ASTContext &Context, EmptySubobjectMap *EmptySubobjects)
- : Context(Context), EmptySubobjects(EmptySubobjects), Size(0), Alignment(8),
- Packed(false), IsUnion(false), IsMac68kAlign(false),
- UnfilledBitsInLastByte(0), MaxFieldAlignment(0), DataSize(0),
- NonVirtualSize(0), NonVirtualAlignment(8), PrimaryBase(0),
+ RecordLayoutBuilder(const ASTContext &Context, EmptySubobjectMap
+ *EmptySubobjects)
+ : Context(Context), EmptySubobjects(EmptySubobjects), Size(0),
+ Alignment(CharUnits::One()), UnpackedAlignment(Alignment),
+ Packed(false), IsUnion(false), IsMac68kAlign(false),
+ UnfilledBitsInLastByte(0), MaxFieldAlignment(CharUnits::Zero()),
+ DataSize(0), NonVirtualSize(CharUnits::Zero()),
+ NonVirtualAlignment(CharUnits::One()), PrimaryBase(0),
PrimaryBaseIsVirtual(false), FirstNearlyEmptyVBase(0) { }
void Layout(const RecordDecl *D);
@@ -594,7 +624,8 @@ protected:
void LayoutFields(const RecordDecl *D);
void LayoutField(const FieldDecl *D);
- void LayoutWideBitField(uint64_t FieldSize, uint64_t TypeSize);
+ void LayoutWideBitField(uint64_t FieldSize, uint64_t TypeSize,
+ bool FieldPacked, const FieldDecl *D);
void LayoutBitField(const FieldDecl *D);
/// BaseSubobjectInfoAllocator - Allocator for BaseSubobjectInfo objects.
@@ -628,13 +659,6 @@ protected:
virtual uint64_t GetVirtualPointersSize(const CXXRecordDecl *RD) const;
- /// IdentifyPrimaryBases - Identify all virtual base classes, direct or
- /// indirect, that are primary base classes for some other direct or indirect
- /// base class.
- void IdentifyPrimaryBases(const CXXRecordDecl *RD);
-
- virtual bool IsNearlyEmpty(const CXXRecordDecl *RD) const;
-
/// LayoutNonVirtualBases - Determines the primary base class (if any) and
/// lays it out. Will then proceed to lay out all non-virtual base clasess.
void LayoutNonVirtualBases(const CXXRecordDecl *RD);
@@ -642,8 +666,8 @@ protected:
/// LayoutNonVirtualBase - Lays out a single non-virtual base.
void LayoutNonVirtualBase(const BaseSubobjectInfo *Base);
- void AddPrimaryVirtualBaseOffsets(const BaseSubobjectInfo *Info,
- uint64_t Offset);
+ void AddPrimaryVirtualBaseOffsets(const BaseSubobjectInfo *Info,
+ CharUnits Offset);
/// LayoutVirtualBases - Lays out all the virtual bases.
void LayoutVirtualBases(const CXXRecordDecl *RD,
@@ -653,17 +677,26 @@ protected:
void LayoutVirtualBase(const BaseSubobjectInfo *Base);
/// LayoutBase - Will lay out a base and return the offset where it was
- /// placed, in bits.
- uint64_t LayoutBase(const BaseSubobjectInfo *Base);
+ /// placed, in chars.
+ CharUnits LayoutBase(const BaseSubobjectInfo *Base);
/// InitializeLayout - Initialize record layout for the given record decl.
void InitializeLayout(const Decl *D);
/// FinishLayout - Finalize record layout. Adjust record size based on the
/// alignment.
- void FinishLayout();
+ void FinishLayout(const NamedDecl *D);
+
+ void UpdateAlignment(CharUnits NewAlignment, CharUnits UnpackedNewAlignment);
+ void UpdateAlignment(CharUnits NewAlignment) {
+ UpdateAlignment(NewAlignment, NewAlignment);
+ }
+
+ void CheckFieldPadding(uint64_t Offset, uint64_t UnpaddedOffset,
+ uint64_t UnpackedOffset, unsigned UnpackedAlign,
+ bool isPacked, const FieldDecl *D);
- void UpdateAlignment(unsigned NewAlignment);
+ DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID);
RecordLayoutBuilder(const RecordLayoutBuilder&); // DO NOT IMPLEMENT
void operator=(const RecordLayoutBuilder&); // DO NOT IMPLEMENT
@@ -674,42 +707,6 @@ public:
};
} // end anonymous namespace
-/// IsNearlyEmpty - Indicates when a class has a vtable pointer, but
-/// no other data.
-bool RecordLayoutBuilder::IsNearlyEmpty(const CXXRecordDecl *RD) const {
- // FIXME: Audit the corners
- if (!RD->isDynamicClass())
- return false;
- const ASTRecordLayout &BaseInfo = Context.getASTRecordLayout(RD);
- if (BaseInfo.getNonVirtualSize() == Context.Target.getPointerWidth(0))
- return true;
- return false;
-}
-
-void RecordLayoutBuilder::IdentifyPrimaryBases(const CXXRecordDecl *RD) {
- const ASTRecordLayout::PrimaryBaseInfo &BaseInfo =
- Context.getASTRecordLayout(RD).getPrimaryBaseInfo();
-
- // If the record has a primary base class that is virtual, add it to the set
- // of primary bases.
- if (BaseInfo.isVirtual())
- IndirectPrimaryBases.insert(BaseInfo.getBase());
-
- // Now traverse all bases and find primary bases for them.
- for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
- e = RD->bases_end(); i != e; ++i) {
- assert(!i->getType()->isDependentType() &&
- "Cannot layout class with dependent bases.");
- const CXXRecordDecl *Base =
- cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
-
- // Only bases with virtual bases participate in computing the
- // indirect primary virtual base classes.
- if (Base->getNumVBases())
- IdentifyPrimaryBases(Base);
- }
-}
-
void
RecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD) {
for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
@@ -721,7 +718,7 @@ RecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD) {
cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
// Check if this is a nearly empty virtual base.
- if (I->isVirtual() && IsNearlyEmpty(Base)) {
+ if (I->isVirtual() && Context.isNearlyEmpty(Base)) {
// If it's not an indirect primary base, then we've found our primary
// base.
if (!IndirectPrimaryBases.count(Base)) {
@@ -754,14 +751,7 @@ void RecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) {
// Compute all the primary virtual bases for all of our direct and
// indirect bases, and record all their primary virtual base classes.
- for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
- e = RD->bases_end(); i != e; ++i) {
- assert(!i->getType()->isDependentType() &&
- "Cannot lay out class with dependent bases.");
- const CXXRecordDecl *Base =
- cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
- IdentifyPrimaryBases(Base);
- }
+ RD->getIndirectPrimaryBases(IndirectPrimaryBases);
// If the record has a dynamic base class, attempt to choose a primary base
// class. It is the first (in direct base class order) non-virtual dynamic
@@ -809,8 +799,18 @@ void RecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) {
Size += GetVirtualPointersSize(RD);
DataSize = Size;
+ CharUnits UnpackedBaseAlign =
+ Context.toCharUnitsFromBits(Context.Target.getPointerAlign(0));
+ CharUnits BaseAlign = (Packed) ? CharUnits::One() : UnpackedBaseAlign;
+
+ // The maximum field alignment overrides base align.
+ if (!MaxFieldAlignment.isZero()) {
+ BaseAlign = std::min(BaseAlign, MaxFieldAlignment);
+ UnpackedBaseAlign = std::min(UnpackedBaseAlign, MaxFieldAlignment);
+ }
+
// Update the alignment.
- UpdateAlignment(Context.Target.getPointerAlign(0));
+ UpdateAlignment(BaseAlign, UnpackedBaseAlign);
}
BaseSubobjectInfo *
@@ -845,7 +845,7 @@ RecordLayoutBuilder::ComputeBaseSubobjectInfo(const CXXRecordDecl *RD,
// Check if this base has a primary virtual base.
if (RD->getNumVBases()) {
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
- if (Layout.getPrimaryBaseWasVirtual()) {
+ if (Layout.isPrimaryBaseVirtual()) {
// This base does have a primary virtual base.
PrimaryVirtualBase = Layout.getPrimaryBase();
assert(PrimaryVirtualBase && "Didn't have a primary virtual base!");
@@ -977,7 +977,7 @@ RecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) {
void RecordLayoutBuilder::LayoutNonVirtualBase(const BaseSubobjectInfo *Base) {
// Layout the base.
- uint64_t Offset = LayoutBase(Base);
+ CharUnits Offset = LayoutBase(Base);
// Add its base class offset.
assert(!Bases.count(Base->Class) && "base offset already exists!");
@@ -988,7 +988,7 @@ void RecordLayoutBuilder::LayoutNonVirtualBase(const BaseSubobjectInfo *Base) {
void
RecordLayoutBuilder::AddPrimaryVirtualBaseOffsets(const BaseSubobjectInfo *Info,
- uint64_t Offset) {
+ CharUnits Offset) {
// This base isn't interesting, it has no virtual bases.
if (!Info->Class->getNumVBases())
return;
@@ -1016,7 +1016,7 @@ RecordLayoutBuilder::AddPrimaryVirtualBaseOffsets(const BaseSubobjectInfo *Info,
if (Base->IsVirtual)
continue;
- uint64_t BaseOffset = Offset + Layout.getBaseClassOffset(Base->Class);
+ CharUnits BaseOffset = Offset + Layout.getBaseClassOffset(Base->Class);
AddPrimaryVirtualBaseOffsets(Base, BaseOffset);
}
}
@@ -1033,7 +1033,7 @@ RecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD,
} else {
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
PrimaryBase = Layout.getPrimaryBase();
- PrimaryBaseIsVirtual = Layout.getPrimaryBaseWasVirtual();
+ PrimaryBaseIsVirtual = Layout.isPrimaryBaseVirtual();
}
for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
@@ -1074,7 +1074,7 @@ void RecordLayoutBuilder::LayoutVirtualBase(const BaseSubobjectInfo *Base) {
assert(!Base->Derived && "Trying to lay out a primary virtual base!");
// Layout the base.
- uint64_t Offset = LayoutBase(Base);
+ CharUnits Offset = LayoutBase(Base);
// Add its base class offset.
assert(!VBases.count(Base->Class) && "vbase offset already exists!");
@@ -1083,38 +1083,48 @@ void RecordLayoutBuilder::LayoutVirtualBase(const BaseSubobjectInfo *Base) {
AddPrimaryVirtualBaseOffsets(Base, Offset);
}
-uint64_t RecordLayoutBuilder::LayoutBase(const BaseSubobjectInfo *Base) {
+CharUnits RecordLayoutBuilder::LayoutBase(const BaseSubobjectInfo *Base) {
const ASTRecordLayout &Layout = Context.getASTRecordLayout(Base->Class);
// If we have an empty base class, try to place it at offset 0.
if (Base->Class->isEmpty() &&
- EmptySubobjects->CanPlaceBaseAtOffset(Base, 0)) {
- Size = std::max(Size, Layout.getSize());
+ EmptySubobjects->CanPlaceBaseAtOffset(Base, CharUnits::Zero())) {
+ uint64_t RecordSizeInBits = Context.toBits(Layout.getSize());
+ Size = std::max(Size, RecordSizeInBits);
- return 0;
+ return CharUnits::Zero();
}
- unsigned BaseAlign = Layout.getNonVirtualAlign();
+ CharUnits UnpackedBaseAlign = Layout.getNonVirtualAlign();
+ CharUnits BaseAlign = (Packed) ? CharUnits::One() : UnpackedBaseAlign;
+
+ // The maximum field alignment overrides base align.
+ if (!MaxFieldAlignment.isZero()) {
+ BaseAlign = std::min(BaseAlign, MaxFieldAlignment);
+ UnpackedBaseAlign = std::min(UnpackedBaseAlign, MaxFieldAlignment);
+ }
// Round up the current record size to the base's alignment boundary.
- uint64_t Offset = llvm::RoundUpToAlignment(DataSize, BaseAlign);
+ uint64_t Offset =
+ llvm::RoundUpToAlignment(DataSize, Context.toBits(BaseAlign));
// Try to place the base.
- while (!EmptySubobjects->CanPlaceBaseAtOffset(Base, Offset))
- Offset += BaseAlign;
+ while (!EmptySubobjects->CanPlaceBaseAtOffset(Base,
+ Context.toCharUnitsFromBits(Offset)))
+ Offset += Context.toBits(BaseAlign);
if (!Base->Class->isEmpty()) {
// Update the data size.
- DataSize = Offset + Layout.getNonVirtualSize();
+ DataSize = Offset + Context.toBits(Layout.getNonVirtualSize());
Size = std::max(Size, DataSize);
} else
- Size = std::max(Size, Offset + Layout.getSize());
+ Size = std::max(Size, Offset + Context.toBits(Layout.getSize()));
// Remember max struct/class alignment.
- UpdateAlignment(BaseAlign);
+ UpdateAlignment(BaseAlign, UnpackedBaseAlign);
- return Offset;
+ return Context.toCharUnitsFromBits(Offset);
}
void RecordLayoutBuilder::InitializeLayout(const Decl *D) {
@@ -1129,14 +1139,14 @@ void RecordLayoutBuilder::InitializeLayout(const Decl *D) {
// to bit-fields, but gcc appears not to follow that.
if (D->hasAttr<AlignMac68kAttr>()) {
IsMac68kAlign = true;
- MaxFieldAlignment = 2 * 8;
- Alignment = 2 * 8;
+ MaxFieldAlignment = CharUnits::fromQuantity(2);
+ Alignment = CharUnits::fromQuantity(2);
} else {
if (const MaxFieldAlignmentAttr *MFAA = D->getAttr<MaxFieldAlignmentAttr>())
- MaxFieldAlignment = MFAA->getAlignment();
+ MaxFieldAlignment = Context.toCharUnitsFromBits(MFAA->getAlignment());
if (unsigned MaxAlign = D->getMaxAlignment())
- UpdateAlignment(MaxAlign);
+ UpdateAlignment(Context.toCharUnitsFromBits(MaxAlign));
}
}
@@ -1146,7 +1156,7 @@ void RecordLayoutBuilder::Layout(const RecordDecl *D) {
// Finally, round the size of the total struct up to the alignment of the
// struct itself.
- FinishLayout();
+ FinishLayout(D);
}
void RecordLayoutBuilder::Layout(const CXXRecordDecl *RD) {
@@ -1157,7 +1167,7 @@ void RecordLayoutBuilder::Layout(const CXXRecordDecl *RD) {
LayoutFields(RD);
- NonVirtualSize = Size;
+ NonVirtualSize = Context.toCharUnitsFromBits(Size);
NonVirtualAlignment = Alignment;
// Lay out the virtual bases and add the primary virtual base offsets.
@@ -1167,7 +1177,7 @@ void RecordLayoutBuilder::Layout(const CXXRecordDecl *RD) {
// Finally, round the size of the total struct up to the alignment of the
// struct itself.
- FinishLayout();
+ FinishLayout(RD);
#ifndef NDEBUG
// Check that we have base offsets for all bases.
@@ -1201,7 +1211,7 @@ void RecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D) {
// We start laying out ivars not at the end of the superclass
// structure, but at the next byte following the last field.
- Size = llvm::RoundUpToAlignment(SL.getDataSize(), 8);
+ Size = Context.toBits(SL.getDataSize());
DataSize = Size;
}
@@ -1215,7 +1225,7 @@ void RecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D) {
// Finally, round the size of the total struct up to the alignment of the
// struct itself.
- FinishLayout();
+ FinishLayout(D);
}
void RecordLayoutBuilder::LayoutFields(const RecordDecl *D) {
@@ -1227,7 +1237,9 @@ void RecordLayoutBuilder::LayoutFields(const RecordDecl *D) {
}
void RecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize,
- uint64_t TypeSize) {
+ uint64_t TypeSize,
+ bool FieldPacked,
+ const FieldDecl *D) {
assert(Context.getLangOptions().CPlusPlus &&
"Can only have wide bit-fields in C++!");
@@ -1258,6 +1270,7 @@ void RecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize,
UnfilledBitsInLastByte = 0;
uint64_t FieldOffset;
+ uint64_t UnpaddedFieldOffset = DataSize - UnfilledBitsInLastByte;
if (IsUnion) {
DataSize = std::max(DataSize, FieldSize);
@@ -1276,16 +1289,20 @@ void RecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize,
// Place this field at the current location.
FieldOffsets.push_back(FieldOffset);
+ CheckFieldPadding(FieldOffset, UnpaddedFieldOffset, FieldOffset,
+ TypeAlign, FieldPacked, D);
+
// Update the size.
Size = std::max(Size, DataSize);
// Remember max struct/class alignment.
- UpdateAlignment(TypeAlign);
+ UpdateAlignment(Context.toCharUnitsFromBits(TypeAlign));
}
void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
bool FieldPacked = Packed || D->hasAttr<PackedAttr>();
- uint64_t FieldOffset = IsUnion ? 0 : (DataSize - UnfilledBitsInLastByte);
+ uint64_t UnpaddedFieldOffset = DataSize - UnfilledBitsInLastByte;
+ uint64_t FieldOffset = IsUnion ? 0 : UnpaddedFieldOffset;
uint64_t FieldSize = D->getBitWidth()->EvaluateAsInt(Context).getZExtValue();
std::pair<uint64_t, unsigned> FieldInfo = Context.getTypeInfo(D->getType());
@@ -1293,29 +1310,48 @@ void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
unsigned FieldAlign = FieldInfo.second;
if (FieldSize > TypeSize) {
- LayoutWideBitField(FieldSize, TypeSize);
+ LayoutWideBitField(FieldSize, TypeSize, FieldPacked, D);
return;
}
+ // The align if the field is not packed. This is to check if the attribute
+ // was unnecessary (-Wpacked).
+ unsigned UnpackedFieldAlign = FieldAlign;
+ uint64_t UnpackedFieldOffset = FieldOffset;
+ if (!Context.Target.useBitFieldTypeAlignment())
+ UnpackedFieldAlign = 1;
+
if (FieldPacked || !Context.Target.useBitFieldTypeAlignment())
FieldAlign = 1;
FieldAlign = std::max(FieldAlign, D->getMaxAlignment());
+ UnpackedFieldAlign = std::max(UnpackedFieldAlign, D->getMaxAlignment());
// The maximum field alignment overrides the aligned attribute.
- if (MaxFieldAlignment)
- FieldAlign = std::min(FieldAlign, MaxFieldAlignment);
+ if (!MaxFieldAlignment.isZero()) {
+ unsigned MaxFieldAlignmentInBits = Context.toBits(MaxFieldAlignment);
+ FieldAlign = std::min(FieldAlign, MaxFieldAlignmentInBits);
+ UnpackedFieldAlign = std::min(UnpackedFieldAlign, MaxFieldAlignmentInBits);
+ }
// Check if we need to add padding to give the field the correct alignment.
if (FieldSize == 0 || (FieldOffset & (FieldAlign-1)) + FieldSize > TypeSize)
FieldOffset = llvm::RoundUpToAlignment(FieldOffset, FieldAlign);
+ if (FieldSize == 0 ||
+ (UnpackedFieldOffset & (UnpackedFieldAlign-1)) + FieldSize > TypeSize)
+ UnpackedFieldOffset = llvm::RoundUpToAlignment(UnpackedFieldOffset,
+ UnpackedFieldAlign);
+
// Padding members don't affect overall alignment.
if (!D->getIdentifier())
- FieldAlign = 1;
+ FieldAlign = UnpackedFieldAlign = 1;
// Place this field at the current location.
FieldOffsets.push_back(FieldOffset);
+ CheckFieldPadding(FieldOffset, UnpaddedFieldOffset, UnpackedFieldOffset,
+ UnpackedFieldAlign, FieldPacked, D);
+
// Update DataSize to include the last byte containing (part of) the bitfield.
if (IsUnion) {
// FIXME: I think FieldSize should be TypeSize here.
@@ -1331,7 +1367,8 @@ void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
Size = std::max(Size, DataSize);
// Remember max struct/class alignment.
- UpdateAlignment(FieldAlign);
+ UpdateAlignment(Context.toCharUnitsFromBits(FieldAlign),
+ Context.toCharUnitsFromBits(UnpackedFieldAlign));
}
void RecordLayoutBuilder::LayoutField(const FieldDecl *D) {
@@ -1340,42 +1377,74 @@ void RecordLayoutBuilder::LayoutField(const FieldDecl *D) {
return;
}
+ uint64_t UnpaddedFieldOffset = DataSize - UnfilledBitsInLastByte;
+
// Reset the unfilled bits.
UnfilledBitsInLastByte = 0;
bool FieldPacked = Packed || D->hasAttr<PackedAttr>();
- uint64_t FieldOffset = IsUnion ? 0 : DataSize;
- uint64_t FieldSize;
- unsigned FieldAlign;
+ CharUnits FieldOffset =
+ IsUnion ? CharUnits::Zero() : Context.toCharUnitsFromBits(DataSize);
+ CharUnits FieldSize;
+ CharUnits FieldAlign;
if (D->getType()->isIncompleteArrayType()) {
// This is a flexible array member; we can't directly
// query getTypeInfo about these, so we figure it out here.
// Flexible array members don't have any size, but they
// have to be aligned appropriately for their element type.
- FieldSize = 0;
+ FieldSize = CharUnits::Zero();
const ArrayType* ATy = Context.getAsArrayType(D->getType());
- FieldAlign = Context.getTypeAlign(ATy->getElementType());
+ FieldAlign = Context.getTypeAlignInChars(ATy->getElementType());
} else if (const ReferenceType *RT = D->getType()->getAs<ReferenceType>()) {
unsigned AS = RT->getPointeeType().getAddressSpace();
- FieldSize = Context.Target.getPointerWidth(AS);
- FieldAlign = Context.Target.getPointerAlign(AS);
+ FieldSize =
+ Context.toCharUnitsFromBits(Context.Target.getPointerWidth(AS));
+ FieldAlign =
+ Context.toCharUnitsFromBits(Context.Target.getPointerAlign(AS));
} else {
- std::pair<uint64_t, unsigned> FieldInfo = Context.getTypeInfo(D->getType());
+ std::pair<CharUnits, CharUnits> FieldInfo =
+ Context.getTypeInfoInChars(D->getType());
FieldSize = FieldInfo.first;
FieldAlign = FieldInfo.second;
+
+ if (Context.getLangOptions().MSBitfields) {
+ // If MS bitfield layout is required, figure out what type is being
+ // laid out and align the field to the width of that type.
+
+ // Resolve all typedefs down to their base type and round up the field
+ // alignment if necessary.
+ QualType T = Context.getBaseElementType(D->getType());
+ if (const BuiltinType *BTy = T->getAs<BuiltinType>()) {
+ CharUnits TypeSize = Context.getTypeSizeInChars(BTy);
+ if (TypeSize > FieldAlign)
+ FieldAlign = TypeSize;
+ }
+ }
}
+ // The align if the field is not packed. This is to check if the attribute
+ // was unnecessary (-Wpacked).
+ CharUnits UnpackedFieldAlign = FieldAlign;
+ CharUnits UnpackedFieldOffset = FieldOffset;
+
if (FieldPacked)
- FieldAlign = 8;
- FieldAlign = std::max(FieldAlign, D->getMaxAlignment());
+ FieldAlign = CharUnits::One();
+ CharUnits MaxAlignmentInChars =
+ Context.toCharUnitsFromBits(D->getMaxAlignment());
+ FieldAlign = std::max(FieldAlign, MaxAlignmentInChars);
+ UnpackedFieldAlign = std::max(UnpackedFieldAlign, MaxAlignmentInChars);
// The maximum field alignment overrides the aligned attribute.
- if (MaxFieldAlignment)
+ if (!MaxFieldAlignment.isZero()) {
FieldAlign = std::min(FieldAlign, MaxFieldAlignment);
+ UnpackedFieldAlign = std::min(UnpackedFieldAlign, MaxFieldAlignment);
+ }
// Round up the current record size to the field's alignment boundary.
- FieldOffset = llvm::RoundUpToAlignment(FieldOffset, FieldAlign);
+ FieldOffset = FieldOffset.RoundUpToAlignment(FieldAlign);
+ UnpackedFieldOffset =
+ UnpackedFieldOffset.RoundUpToAlignment(UnpackedFieldAlign);
if (!IsUnion && EmptySubobjects) {
// Check if we can place the field at this offset.
@@ -1386,41 +1455,130 @@ void RecordLayoutBuilder::LayoutField(const FieldDecl *D) {
}
// Place this field at the current location.
- FieldOffsets.push_back(FieldOffset);
+ FieldOffsets.push_back(Context.toBits(FieldOffset));
+
+ CheckFieldPadding(Context.toBits(FieldOffset), UnpaddedFieldOffset,
+ Context.toBits(UnpackedFieldOffset),
+ Context.toBits(UnpackedFieldAlign), FieldPacked, D);
// Reserve space for this field.
+ uint64_t FieldSizeInBits = Context.toBits(FieldSize);
if (IsUnion)
- Size = std::max(Size, FieldSize);
+ Size = std::max(Size, FieldSizeInBits);
else
- Size = FieldOffset + FieldSize;
+ Size = Context.toBits(FieldOffset) + FieldSizeInBits;
// Update the data size.
DataSize = Size;
// Remember max struct/class alignment.
- UpdateAlignment(FieldAlign);
+ UpdateAlignment(FieldAlign, UnpackedFieldAlign);
}
-void RecordLayoutBuilder::FinishLayout() {
+void RecordLayoutBuilder::FinishLayout(const NamedDecl *D) {
// In C++, records cannot be of size 0.
- if (Context.getLangOptions().CPlusPlus && Size == 0)
- Size = 8;
+ if (Context.getLangOptions().CPlusPlus && Size == 0) {
+ if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
+ // Compatibility with gcc requires a class (pod or non-pod)
+ // which is not empty but of size 0; such as having fields of
+ // array of zero-length, remains of Size 0
+ if (RD->isEmpty())
+ Size = 8;
+ }
+ else
+ Size = 8;
+ }
// Finally, round the size of the record up to the alignment of the
// record itself.
- Size = llvm::RoundUpToAlignment(Size, Alignment);
+ uint64_t UnpaddedSize = Size - UnfilledBitsInLastByte;
+ uint64_t UnpackedSize =
+ llvm::RoundUpToAlignment(Size, Context.toBits(UnpackedAlignment));
+ Size = llvm::RoundUpToAlignment(Size, Context.toBits(Alignment));
+
+ unsigned CharBitNum = Context.Target.getCharWidth();
+ if (const RecordDecl *RD = dyn_cast<RecordDecl>(D)) {
+ // Warn if padding was introduced to the struct/class/union.
+ if (Size > UnpaddedSize) {
+ unsigned PadSize = Size - UnpaddedSize;
+ bool InBits = true;
+ if (PadSize % CharBitNum == 0) {
+ PadSize = PadSize / CharBitNum;
+ InBits = false;
+ }
+ Diag(RD->getLocation(), diag::warn_padded_struct_size)
+ << Context.getTypeDeclType(RD)
+ << PadSize
+ << (InBits ? 1 : 0) /*(byte|bit)*/ << (PadSize > 1); // plural or not
+ }
+
+ // Warn if we packed it unnecessarily. If the alignment is 1 byte don't
+ // bother since there won't be alignment issues.
+ if (Packed && UnpackedAlignment > CharUnits::One() && Size == UnpackedSize)
+ Diag(D->getLocation(), diag::warn_unnecessary_packed)
+ << Context.getTypeDeclType(RD);
+ }
}
-void RecordLayoutBuilder::UpdateAlignment(unsigned NewAlignment) {
+void RecordLayoutBuilder::UpdateAlignment(CharUnits NewAlignment,
+ CharUnits UnpackedNewAlignment) {
// The alignment is not modified when using 'mac68k' alignment.
if (IsMac68kAlign)
return;
- if (NewAlignment <= Alignment)
+ if (NewAlignment > Alignment) {
+ assert(llvm::isPowerOf2_32(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"));
+ UnpackedAlignment = UnpackedNewAlignment;
+ }
+}
+
+void RecordLayoutBuilder::CheckFieldPadding(uint64_t Offset,
+ uint64_t UnpaddedOffset,
+ uint64_t UnpackedOffset,
+ unsigned UnpackedAlign,
+ bool isPacked,
+ const FieldDecl *D) {
+ // We let objc ivars without warning, objc interfaces generally are not used
+ // for padding tricks.
+ if (isa<ObjCIvarDecl>(D))
return;
- assert(llvm::isPowerOf2_32(NewAlignment && "Alignment not a power of 2"));
+ unsigned CharBitNum = Context.Target.getCharWidth();
- Alignment = NewAlignment;
+ // Warn if padding was introduced to the struct/class.
+ if (!IsUnion && Offset > UnpaddedOffset) {
+ unsigned PadSize = Offset - UnpaddedOffset;
+ bool InBits = true;
+ if (PadSize % CharBitNum == 0) {
+ PadSize = PadSize / CharBitNum;
+ InBits = false;
+ }
+ if (D->getIdentifier())
+ Diag(D->getLocation(), diag::warn_padded_struct_field)
+ << (D->getParent()->isStruct() ? 0 : 1) // struct|class
+ << Context.getTypeDeclType(D->getParent())
+ << PadSize
+ << (InBits ? 1 : 0) /*(byte|bit)*/ << (PadSize > 1) // plural or not
+ << D->getIdentifier();
+ else
+ Diag(D->getLocation(), diag::warn_padded_struct_anon_field)
+ << (D->getParent()->isStruct() ? 0 : 1) // struct|class
+ << Context.getTypeDeclType(D->getParent())
+ << PadSize
+ << (InBits ? 1 : 0) /*(byte|bit)*/ << (PadSize > 1); // plural or not
+ }
+
+ // Warn if we packed it unnecessarily. If the alignment is 1 byte don't
+ // bother since there won't be alignment issues.
+ if (isPacked && UnpackedAlign > CharBitNum && Offset == UnpackedOffset)
+ Diag(D->getLocation(), diag::warn_unnecessary_packed)
+ << D->getIdentifier();
}
const CXXMethodDecl *
@@ -1435,6 +1593,13 @@ RecordLayoutBuilder::ComputeKeyFunction(const CXXRecordDecl *RD) {
if (RD->isInAnonymousNamespace())
return 0;
+ // Template instantiations don't have key functions,see Itanium C++ ABI 5.2.6.
+ // Same behavior as GCC.
+ TemplateSpecializationKind TSK = RD->getTemplateSpecializationKind();
+ if (TSK == TSK_ImplicitInstantiation ||
+ TSK == TSK_ExplicitInstantiationDefinition)
+ return 0;
+
for (CXXRecordDecl::method_iterator I = RD->method_begin(),
E = RD->method_end(); I != E; ++I) {
const CXXMethodDecl *MD = *I;
@@ -1463,26 +1628,21 @@ RecordLayoutBuilder::ComputeKeyFunction(const CXXRecordDecl *RD) {
return 0;
}
-// This class implements layout specific to the Microsoft ABI.
-class MSRecordLayoutBuilder: public RecordLayoutBuilder {
-public:
- MSRecordLayoutBuilder(ASTContext& Ctx, EmptySubobjectMap *EmptySubobjects):
- RecordLayoutBuilder(Ctx, EmptySubobjects) {}
-
- virtual bool IsNearlyEmpty(const CXXRecordDecl *RD) const;
- virtual uint64_t GetVirtualPointersSize(const CXXRecordDecl *RD) const;
-};
+DiagnosticBuilder
+RecordLayoutBuilder::Diag(SourceLocation Loc, unsigned DiagID) {
+ return Context.getDiagnostics().Report(Loc, DiagID);
+}
-bool MSRecordLayoutBuilder::IsNearlyEmpty(const CXXRecordDecl *RD) const {
- // FIXME: Audit the corners
- if (!RD->isDynamicClass())
- return false;
- const ASTRecordLayout &BaseInfo = Context.getASTRecordLayout(RD);
- // In the Microsoft ABI, classes can have one or two vtable pointers.
- if (BaseInfo.getNonVirtualSize() == Context.Target.getPointerWidth(0) ||
- BaseInfo.getNonVirtualSize() == Context.Target.getPointerWidth(0) * 2)
- return true;
- return false;
+namespace {
+ // This class implements layout specific to the Microsoft ABI.
+ class MSRecordLayoutBuilder : public RecordLayoutBuilder {
+ public:
+ MSRecordLayoutBuilder(const ASTContext& Ctx,
+ EmptySubobjectMap *EmptySubobjects) :
+ RecordLayoutBuilder(Ctx, EmptySubobjects) {}
+
+ virtual uint64_t GetVirtualPointersSize(const CXXRecordDecl *RD) const;
+ };
}
uint64_t
@@ -1497,7 +1657,8 @@ MSRecordLayoutBuilder::GetVirtualPointersSize(const CXXRecordDecl *RD) const {
/// getASTRecordLayout - Get or compute information about the layout of the
/// specified record (struct/union/class), which indicates its size and field
/// position information.
-const ASTRecordLayout &ASTContext::getASTRecordLayout(const RecordDecl *D) {
+const ASTRecordLayout &
+ASTContext::getASTRecordLayout(const RecordDecl *D) const {
D = D->getDefinition();
assert(D && "Cannot get layout of forward declarations!");
@@ -1531,12 +1692,16 @@ const ASTRecordLayout &ASTContext::getASTRecordLayout(const RecordDecl *D) {
// FIXME: This should be done in FinalizeLayout.
uint64_t DataSize =
IsPODForThePurposeOfLayout ? Builder->Size : Builder->DataSize;
- uint64_t NonVirtualSize =
- IsPODForThePurposeOfLayout ? DataSize : Builder->NonVirtualSize;
+ CharUnits NonVirtualSize =
+ IsPODForThePurposeOfLayout ?
+ toCharUnitsFromBits(DataSize) : Builder->NonVirtualSize;
+ CharUnits RecordSize = toCharUnitsFromBits(Builder->Size);
NewEntry =
- new (*this) ASTRecordLayout(*this, Builder->Size, Builder->Alignment,
- DataSize, Builder->FieldOffsets.data(),
+ new (*this) ASTRecordLayout(*this, RecordSize,
+ Builder->Alignment,
+ toCharUnitsFromBits(DataSize),
+ Builder->FieldOffsets.data(),
Builder->FieldOffsets.size(),
NonVirtualSize,
Builder->NonVirtualAlignment,
@@ -1548,9 +1713,12 @@ const ASTRecordLayout &ASTContext::getASTRecordLayout(const RecordDecl *D) {
RecordLayoutBuilder Builder(*this, /*EmptySubobjects=*/0);
Builder.Layout(D);
+ CharUnits RecordSize = toCharUnitsFromBits(Builder.Size);
+
NewEntry =
- new (*this) ASTRecordLayout(*this, Builder.Size, Builder.Alignment,
- Builder.Size,
+ new (*this) ASTRecordLayout(*this, RecordSize,
+ Builder.Alignment,
+ toCharUnitsFromBits(Builder.Size),
Builder.FieldOffsets.data(),
Builder.FieldOffsets.size());
}
@@ -1572,9 +1740,6 @@ const CXXMethodDecl *ASTContext::getKeyFunction(const CXXRecordDecl *RD) {
const CXXMethodDecl *&Entry = KeyFunctions[RD];
if (!Entry)
Entry = RecordLayoutBuilder::ComputeKeyFunction(RD);
- else
- assert(Entry == RecordLayoutBuilder::ComputeKeyFunction(RD) &&
- "Key function changed!");
return Entry;
}
@@ -1586,7 +1751,7 @@ const CXXMethodDecl *ASTContext::getKeyFunction(const CXXRecordDecl *RD) {
/// implementation. This may differ by including synthesized ivars.
const ASTRecordLayout &
ASTContext::getObjCLayout(const ObjCInterfaceDecl *D,
- const ObjCImplementationDecl *Impl) {
+ const ObjCImplementationDecl *Impl) const {
assert(!D->isForwardDecl() && "Invalid interface decl!");
// Look up this layout, if already laid out, return what we have.
@@ -1609,9 +1774,12 @@ ASTContext::getObjCLayout(const ObjCInterfaceDecl *D,
RecordLayoutBuilder Builder(*this, /*EmptySubobjects=*/0);
Builder.Layout(D);
+ CharUnits RecordSize = toCharUnitsFromBits(Builder.Size);
+
const ASTRecordLayout *NewEntry =
- new (*this) ASTRecordLayout(*this, Builder.Size, Builder.Alignment,
- Builder.DataSize,
+ new (*this) ASTRecordLayout(*this, RecordSize,
+ Builder.Alignment,
+ toCharUnitsFromBits(Builder.DataSize),
Builder.FieldOffsets.data(),
Builder.FieldOffsets.size());
@@ -1621,18 +1789,18 @@ ASTContext::getObjCLayout(const ObjCInterfaceDecl *D,
}
static void PrintOffset(llvm::raw_ostream &OS,
- uint64_t Offset, unsigned IndentLevel) {
- OS << llvm::format("%4d | ", Offset);
+ CharUnits Offset, unsigned IndentLevel) {
+ OS << llvm::format("%4d | ", Offset.getQuantity());
OS.indent(IndentLevel * 2);
}
static void DumpCXXRecordLayout(llvm::raw_ostream &OS,
- const CXXRecordDecl *RD, ASTContext &C,
- uint64_t Offset,
+ const CXXRecordDecl *RD, const ASTContext &C,
+ CharUnits Offset,
unsigned IndentLevel,
const char* Description,
bool IncludeVirtualBases) {
- const ASTRecordLayout &Info = C.getASTRecordLayout(RD);
+ const ASTRecordLayout &Layout = C.getASTRecordLayout(RD);
PrintOffset(OS, Offset, IndentLevel);
OS << C.getTypeDeclType(const_cast<CXXRecordDecl *>(RD)).getAsString();
@@ -1644,7 +1812,7 @@ static void DumpCXXRecordLayout(llvm::raw_ostream &OS,
IndentLevel++;
- const CXXRecordDecl *PrimaryBase = Info.getPrimaryBase();
+ const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
// Vtable pointer.
if (RD->isDynamicClass() && !PrimaryBase) {
@@ -1662,7 +1830,7 @@ static void DumpCXXRecordLayout(llvm::raw_ostream &OS,
const CXXRecordDecl *Base =
cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
- uint64_t BaseOffset = Offset + Info.getBaseClassOffset(Base) / 8;
+ CharUnits BaseOffset = Offset + Layout.getBaseClassOffset(Base);
DumpCXXRecordLayout(OS, Base, C, BaseOffset, IndentLevel,
Base == PrimaryBase ? "(primary base)" : "(base)",
@@ -1674,7 +1842,8 @@ static void DumpCXXRecordLayout(llvm::raw_ostream &OS,
for (CXXRecordDecl::field_iterator I = RD->field_begin(),
E = RD->field_end(); I != E; ++I, ++FieldNo) {
const FieldDecl *Field = *I;
- uint64_t FieldOffset = Offset + Info.getFieldOffset(FieldNo) / 8;
+ CharUnits FieldOffset = Offset +
+ C.toCharUnitsFromBits(Layout.getFieldOffset(FieldNo));
if (const RecordType *RT = Field->getType()->getAs<RecordType>()) {
if (const CXXRecordDecl *D = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
@@ -1699,27 +1868,27 @@ static void DumpCXXRecordLayout(llvm::raw_ostream &OS,
const CXXRecordDecl *VBase =
cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
- uint64_t VBaseOffset = Offset + Info.getVBaseClassOffset(VBase) / 8;
+ CharUnits VBaseOffset = Offset + Layout.getVBaseClassOffset(VBase);
DumpCXXRecordLayout(OS, VBase, C, VBaseOffset, IndentLevel,
VBase == PrimaryBase ?
"(primary virtual base)" : "(virtual base)",
/*IncludeVirtualBases=*/false);
}
- OS << " sizeof=" << Info.getSize() / 8;
- OS << ", dsize=" << Info.getDataSize() / 8;
- OS << ", align=" << Info.getAlignment() / 8 << '\n';
- OS << " nvsize=" << Info.getNonVirtualSize() / 8;
- OS << ", nvalign=" << Info.getNonVirtualAlign() / 8 << '\n';
+ OS << " sizeof=" << Layout.getSize().getQuantity();
+ OS << ", dsize=" << Layout.getDataSize().getQuantity();
+ OS << ", align=" << Layout.getAlignment().getQuantity() << '\n';
+ OS << " nvsize=" << Layout.getNonVirtualSize().getQuantity();
+ OS << ", nvalign=" << Layout.getNonVirtualAlign().getQuantity() << '\n';
OS << '\n';
}
void ASTContext::DumpRecordLayout(const RecordDecl *RD,
- llvm::raw_ostream &OS) {
+ llvm::raw_ostream &OS) const {
const ASTRecordLayout &Info = getASTRecordLayout(RD);
if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD))
- return DumpCXXRecordLayout(OS, CXXRD, *this, 0, 0, 0,
+ return DumpCXXRecordLayout(OS, CXXRD, *this, CharUnits(), 0, 0,
/*IncludeVirtualBases=*/true);
OS << "Type: " << getTypeDeclType(RD).getAsString() << "\n";
@@ -1727,9 +1896,9 @@ void ASTContext::DumpRecordLayout(const RecordDecl *RD,
RD->dump();
OS << "\nLayout: ";
OS << "<ASTRecordLayout\n";
- OS << " Size:" << Info.getSize() << "\n";
- OS << " DataSize:" << Info.getDataSize() << "\n";
- OS << " Alignment:" << Info.getAlignment() << "\n";
+ OS << " Size:" << toBits(Info.getSize()) << "\n";
+ OS << " DataSize:" << toBits(Info.getDataSize()) << "\n";
+ OS << " Alignment:" << toBits(Info.getAlignment()) << "\n";
OS << " FieldOffsets: [";
for (unsigned i = 0, e = Info.getFieldCount(); i != e; ++i) {
if (i) OS << ", ";