diff options
author | dim <dim@FreeBSD.org> | 2013-04-08 18:45:10 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2013-04-08 18:45:10 +0000 |
commit | c72c57c9e9b69944e3e009cd5e209634839581d3 (patch) | |
tree | 4fc2f184c499d106f29a386c452b49e5197bf63d /lib/AST/RecordLayoutBuilder.cpp | |
parent | 5b20025c30d23d521e12c1f33ec8fa6b821952cd (diff) | |
download | FreeBSD-src-c72c57c9e9b69944e3e009cd5e209634839581d3.zip FreeBSD-src-c72c57c9e9b69944e3e009cd5e209634839581d3.tar.gz |
Vendor import of clang trunk r178860:
http://llvm.org/svn/llvm-project/cfe/trunk@178860
Diffstat (limited to 'lib/AST/RecordLayoutBuilder.cpp')
-rw-r--r-- | lib/AST/RecordLayoutBuilder.cpp | 135 |
1 files changed, 109 insertions, 26 deletions
diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp index 4dfffc4..42c3ba3 100644 --- a/lib/AST/RecordLayoutBuilder.cpp +++ b/lib/AST/RecordLayoutBuilder.cpp @@ -7,6 +7,7 @@ // //===----------------------------------------------------------------------===// +#include "clang/AST/RecordLayout.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Attr.h" #include "clang/AST/CXXInheritance.h" @@ -14,13 +15,12 @@ #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" #include "llvm/Support/CrashRecoveryContext.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/MathExtras.h" using namespace clang; @@ -676,8 +676,12 @@ protected: bool FieldPacked, const FieldDecl *D); void LayoutBitField(const FieldDecl *D); + TargetCXXABI getCXXABI() const { + return Context.getTargetInfo().getCXXABI(); + } + bool isMicrosoftCXXABI() const { - return Context.getTargetInfo().getCXXABI() == CXXABI_Microsoft; + return getCXXABI().isMicrosoft(); } void MSLayoutVirtualBases(const CXXRecordDecl *RD); @@ -791,8 +795,6 @@ protected: RecordLayoutBuilder(const RecordLayoutBuilder &) LLVM_DELETED_FUNCTION; void operator=(const RecordLayoutBuilder &) LLVM_DELETED_FUNCTION; -public: - static const CXXMethodDecl *ComputeKeyFunction(const CXXRecordDecl *RD); }; } // end anonymous namespace @@ -2343,8 +2345,8 @@ void RecordLayoutBuilder::CheckFieldPadding(uint64_t Offset, << D->getIdentifier(); } -const CXXMethodDecl * -RecordLayoutBuilder::ComputeKeyFunction(const CXXRecordDecl *RD) { +static const CXXMethodDecl *computeKeyFunction(ASTContext &Context, + const CXXRecordDecl *RD) { // If a class isn't polymorphic it doesn't have a key function. if (!RD->isPolymorphic()) return 0; @@ -2362,6 +2364,9 @@ RecordLayoutBuilder::ComputeKeyFunction(const CXXRecordDecl *RD) { TSK == TSK_ExplicitInstantiationDefinition) return 0; + bool allowInlineFunctions = + Context.getTargetInfo().getCXXABI().canKeyFunctionBeInline(); + for (CXXRecordDecl::method_iterator I = RD->method_begin(), E = RD->method_end(); I != E; ++I) { const CXXMethodDecl *MD = *I; @@ -2387,6 +2392,13 @@ RecordLayoutBuilder::ComputeKeyFunction(const CXXRecordDecl *RD) { if (!MD->isUserProvided()) continue; + // In certain ABIs, ignore functions with out-of-line inline definitions. + if (!allowInlineFunctions) { + const FunctionDecl *Def; + if (MD->hasBody(Def) && Def->isInlineSpecified()) + continue; + } + // We found it. return MD; } @@ -2399,6 +2411,48 @@ RecordLayoutBuilder::Diag(SourceLocation Loc, unsigned DiagID) { return Context.getDiagnostics().Report(Loc, DiagID); } +/// Does the target C++ ABI require us to skip over the tail-padding +/// of the given class (considering it as a base class) when allocating +/// objects? +static bool mustSkipTailPadding(TargetCXXABI ABI, const CXXRecordDecl *RD) { + switch (ABI.getTailPaddingUseRules()) { + case TargetCXXABI::AlwaysUseTailPadding: + return false; + + case TargetCXXABI::UseTailPaddingUnlessPOD03: + // FIXME: To the extent that this is meant to cover the Itanium ABI + // rules, we should implement the restrictions about over-sized + // bitfields: + // + // http://mentorembedded.github.com/cxx-abi/abi.html#POD : + // In general, a type is considered a POD for the purposes of + // layout if it is a POD type (in the sense of ISO C++ + // [basic.types]). However, a POD-struct or POD-union (in the + // sense of ISO C++ [class]) with a bitfield member whose + // declared width is wider than the declared type of the + // bitfield is not a POD for the purpose of layout. Similarly, + // an array type is not a POD for the purpose of layout if the + // element type of the array is not a POD for the purpose of + // layout. + // + // Where references to the ISO C++ are made in this paragraph, + // the Technical Corrigendum 1 version of the standard is + // intended. + return RD->isPOD(); + + case TargetCXXABI::UseTailPaddingUnlessPOD11: + // This is equivalent to RD->getTypeForDecl().isCXX11PODType(), + // but with a lot of abstraction penalty stripped off. This does + // assume that these properties are set correctly even in C++98 + // mode; fortunately, that is true because we want to assign + // consistently semantics to the type-traits intrinsics (or at + // least as many of them as possible). + return RD->isTrivial() && RD->isStandardLayout(); + } + + llvm_unreachable("bad tail-padding use kind"); +} + /// getASTRecordLayout - Get or compute information about the layout of the /// specified record (struct/union/class), which indicates its size and field /// position information. @@ -2443,18 +2497,17 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const { Builder.Layout(RD); } - // FIXME: This is not always correct. See the part about bitfields at - // http://www.codesourcery.com/public/cxx-abi/abi.html#POD for more info. - // FIXME: IsPODForThePurposeOfLayout should be stored in the record layout. - // This does not affect the calculations of MSVC layouts - bool IsPODForThePurposeOfLayout = - (!Builder.isMicrosoftCXXABI() && cast<CXXRecordDecl>(D)->isPOD()); + // In certain situations, we are allowed to lay out objects in the + // tail-padding of base classes. This is ABI-dependent. + // FIXME: this should be stored in the record layout. + bool skipTailPadding = + mustSkipTailPadding(getTargetInfo().getCXXABI(), cast<CXXRecordDecl>(D)); // FIXME: This should be done in FinalizeLayout. CharUnits DataSize = - IsPODForThePurposeOfLayout ? Builder.getSize() : Builder.getDataSize(); + skipTailPadding ? Builder.getSize() : Builder.getDataSize(); CharUnits NonVirtualSize = - IsPODForThePurposeOfLayout ? DataSize : Builder.NonVirtualSize; + skipTailPadding ? DataSize : Builder.NonVirtualSize; NewEntry = new (*this) ASTRecordLayout(*this, Builder.getSize(), @@ -2492,15 +2545,37 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const { return *NewEntry; } -const CXXMethodDecl *ASTContext::getKeyFunction(const CXXRecordDecl *RD) { +const CXXMethodDecl *ASTContext::getCurrentKeyFunction(const CXXRecordDecl *RD) { + assert(RD->getDefinition() && "Cannot get key function for forward decl!"); RD = cast<CXXRecordDecl>(RD->getDefinition()); - assert(RD && "Cannot get key function for forward declarations!"); - const CXXMethodDecl *&Entry = KeyFunctions[RD]; - if (!Entry) - Entry = RecordLayoutBuilder::ComputeKeyFunction(RD); + const CXXMethodDecl *&entry = KeyFunctions[RD]; + if (!entry) { + entry = computeKeyFunction(*this, RD); + } - return Entry; + return entry; +} + +void ASTContext::setNonKeyFunction(const CXXMethodDecl *method) { + assert(method == method->getFirstDeclaration() && + "not working with method declaration from class definition"); + + // 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*, const CXXMethodDecl*>::iterator + i = KeyFunctions.find(method->getParent()); + + // If it's not cached, there's nothing to do. + if (i == KeyFunctions.end()) return; + + // If it is cached, check whether it's the target method, and if so, + // remove it from the cache. + if (i->second == method) { + // FIXME: remember that we did this for module / chained PCH state? + KeyFunctions.erase(i); + } } static uint64_t getFieldOffset(const ASTContext &C, const FieldDecl *FD) { @@ -2577,6 +2652,11 @@ static void PrintOffset(raw_ostream &OS, OS.indent(IndentLevel * 2); } +static void PrintIndentNoOffset(raw_ostream &OS, unsigned IndentLevel) { + OS << " | "; + OS.indent(IndentLevel * 2); +} + static void DumpCXXRecordLayout(raw_ostream &OS, const CXXRecordDecl *RD, const ASTContext &C, CharUnits Offset, @@ -2601,7 +2681,7 @@ static void DumpCXXRecordLayout(raw_ostream &OS, // Vtable pointer. if (RD->isDynamicClass() && !PrimaryBase && - C.getTargetInfo().getCXXABI() != CXXABI_Microsoft) { + !C.getTargetInfo().getCXXABI().isMicrosoft()) { PrintOffset(OS, Offset, IndentLevel); OS << '(' << *RD << " vtable pointer)\n"; } @@ -2680,11 +2760,14 @@ static void DumpCXXRecordLayout(raw_ostream &OS, /*IncludeVirtualBases=*/false); } - OS << " sizeof=" << Layout.getSize().getQuantity(); + PrintIndentNoOffset(OS, IndentLevel - 1); + 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'; + + PrintIndentNoOffset(OS, IndentLevel - 1); + OS << " nvsize=" << Layout.getNonVirtualSize().getQuantity(); + OS << ", nvalign=" << Layout.getNonVirtualAlign().getQuantity() << "]\n"; OS << '\n'; } |