summaryrefslogtreecommitdiffstats
path: root/lib/AST/RecordLayoutBuilder.cpp
diff options
context:
space:
mode:
authordim <dim@FreeBSD.org>2013-04-08 18:45:10 +0000
committerdim <dim@FreeBSD.org>2013-04-08 18:45:10 +0000
commitc72c57c9e9b69944e3e009cd5e209634839581d3 (patch)
tree4fc2f184c499d106f29a386c452b49e5197bf63d /lib/AST/RecordLayoutBuilder.cpp
parent5b20025c30d23d521e12c1f33ec8fa6b821952cd (diff)
downloadFreeBSD-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.cpp135
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';
}
OpenPOWER on IntegriCloud