summaryrefslogtreecommitdiffstats
path: root/lib/AST
diff options
context:
space:
mode:
Diffstat (limited to 'lib/AST')
-rw-r--r--lib/AST/ASTContext.cpp70
-rw-r--r--lib/AST/ASTImporter.cpp28
-rw-r--r--lib/AST/CMakeLists.txt1
-rw-r--r--lib/AST/Decl.cpp75
-rw-r--r--lib/AST/DeclBase.cpp1
-rw-r--r--lib/AST/DeclCXX.cpp256
-rw-r--r--lib/AST/DeclFriend.cpp41
-rw-r--r--lib/AST/DeclObjC.cpp104
-rw-r--r--lib/AST/Expr.cpp10
-rw-r--r--lib/AST/Makefile2
-rw-r--r--lib/AST/RecordLayout.cpp37
-rw-r--r--lib/AST/RecordLayoutBuilder.cpp400
-rw-r--r--lib/AST/RecordLayoutBuilder.h58
-rw-r--r--lib/AST/TypePrinter.cpp7
14 files changed, 633 insertions, 457 deletions
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 26b10b5..8230cde 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -423,10 +423,15 @@ namespace {
/// (which requires a < after the Doxygen-comment delimiter). Otherwise,
/// we only return true when we find a non-member comment.
static bool
-isDoxygenComment(SourceManager &SourceMgr, SourceRange Comment,
+isDoxygenComment(SourceManager &SourceMgr, SourceRange Comment,
bool Member = false) {
+ bool Invalid = false;
const char *BufferStart
- = SourceMgr.getBufferData(SourceMgr.getFileID(Comment.getBegin())).first;
+ = SourceMgr.getBufferData(SourceMgr.getFileID(Comment.getBegin()),
+ &Invalid).data();
+ if (Invalid)
+ return false;
+
const char *Start = BufferStart + SourceMgr.getFileOffset(Comment.getBegin());
const char* End = BufferStart + SourceMgr.getFileOffset(Comment.getEnd());
@@ -488,9 +493,12 @@ const char *ASTContext::getCommentForDecl(const Decl *D) {
// beginning of the file buffer.
std::pair<FileID, unsigned> DeclStartDecomp
= SourceMgr.getDecomposedLoc(DeclStartLoc);
+ bool Invalid = false;
const char *FileBufferStart
- = SourceMgr.getBufferData(DeclStartDecomp.first).first;
-
+ = SourceMgr.getBufferData(DeclStartDecomp.first, &Invalid).data();
+ if (Invalid)
+ return 0;
+
// First check whether we have a comment for a member.
if (LastComment != Comments.end() &&
!isa<TagDecl>(D) && !isa<NamespaceDecl>(D) &&
@@ -971,22 +979,10 @@ void ASTContext::ShallowCollectObjCIvars(const ObjCInterfaceDecl *OI,
CollectNonClassIvars(OI, Ivars);
}
-void ASTContext::CollectProtocolSynthesizedIvars(const ObjCProtocolDecl *PD,
- llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars) {
- for (ObjCContainerDecl::prop_iterator I = PD->prop_begin(),
- E = PD->prop_end(); I != E; ++I)
- if (ObjCIvarDecl *Ivar = (*I)->getPropertyIvarDecl())
- Ivars.push_back(Ivar);
-
- // Also look into nested protocols.
- for (ObjCProtocolDecl::protocol_iterator P = PD->protocol_begin(),
- E = PD->protocol_end(); P != E; ++P)
- CollectProtocolSynthesizedIvars(*P, Ivars);
-}
-
/// CollectNonClassIvars -
/// This routine collects all other ivars which are not declared in the class.
-/// This includes synthesized ivars and those in class's implementation.
+/// This includes synthesized ivars (via @synthesize) and those in
+// class's @implementation.
///
void ASTContext::CollectNonClassIvars(const ObjCInterfaceDecl *OI,
llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars) {
@@ -997,21 +993,9 @@ void ASTContext::CollectNonClassIvars(const ObjCInterfaceDecl *OI,
Ivars.push_back(*I);
}
}
-
- for (ObjCInterfaceDecl::prop_iterator I = OI->prop_begin(),
- E = OI->prop_end(); I != E; ++I) {
- if (ObjCIvarDecl *Ivar = (*I)->getPropertyIvarDecl())
- Ivars.push_back(Ivar);
- }
- // Also look into interface's protocol list for properties declared
- // in the protocol and whose ivars are synthesized.
- for (ObjCInterfaceDecl::protocol_iterator P = OI->protocol_begin(),
- PE = OI->protocol_end(); P != PE; ++P) {
- ObjCProtocolDecl *PD = (*P);
- CollectProtocolSynthesizedIvars(PD, Ivars);
- }
- // Also add any ivar defined in this class's implementation
+ // Also add any ivar defined in this class's implementation. This
+ // includes synthesized ivars.
if (ObjCImplementationDecl *ImplDecl = OI->getImplementation()) {
for (ObjCImplementationDecl::ivar_iterator I = ImplDecl->ivar_begin(),
E = ImplDecl->ivar_end(); I != E; ++I)
@@ -4760,7 +4744,8 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) {
return QualType();
case Type::Vector:
// FIXME: The merged type should be an ExtVector!
- if (areCompatVectorTypes(LHS->getAs<VectorType>(), RHS->getAs<VectorType>()))
+ if (areCompatVectorTypes(LHSCan->getAs<VectorType>(),
+ RHSCan->getAs<VectorType>()))
return LHS;
return QualType();
case Type::ObjCInterface: {
@@ -4997,13 +4982,24 @@ static QualType DecodeTypeFromStr(const char *&Str, ASTContext &Context,
Done = false;
while (!Done) {
- switch (*Str++) {
+ switch (char c = *Str++) {
default: Done = true; --Str; break;
case '*':
- Type = Context.getPointerType(Type);
- break;
case '&':
- Type = Context.getLValueReferenceType(Type);
+ {
+ // Both pointers and references can have their pointee types
+ // qualified with an address space.
+ char *End;
+ unsigned AddrSpace = strtoul(Str, &End, 10);
+ if (End != Str && AddrSpace != 0) {
+ Type = Context.getAddrSpaceQualType(Type, AddrSpace);
+ Str = End;
+ }
+ }
+ if (c == '*')
+ Type = Context.getPointerType(Type);
+ else
+ Type = Context.getLValueReferenceType(Type);
break;
// FIXME: There's no way to have a built-in with an rvalue ref arg.
case 'C':
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index d9c0d7b..dd2528a 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -1592,6 +1592,12 @@ Decl *ASTNodeImporter::VisitEnumDecl(EnumDecl *D) {
Name.getAsIdentifierInfo(),
Importer.Import(D->getTagKeywordLoc()),
0);
+ // Import the qualifier, if any.
+ if (D->getQualifier()) {
+ NestedNameSpecifier *NNS = Importer.Import(D->getQualifier());
+ SourceRange NNSRange = Importer.Import(D->getQualifierRange());
+ D2->setQualifierInfo(NNS, NNSRange);
+ }
D2->setAccess(D->getAccess());
D2->setLexicalDeclContext(LexicalDC);
Importer.Imported(D, D2);
@@ -1734,6 +1740,12 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
Name.getAsIdentifierInfo(),
Importer.Import(D->getTagKeywordLoc()));
}
+ // Import the qualifier, if any.
+ if (D->getQualifier()) {
+ NestedNameSpecifier *NNS = Importer.Import(D->getQualifier());
+ SourceRange NNSRange = Importer.Import(D->getQualifierRange());
+ D2->setQualifierInfo(NNS, NNSRange);
+ }
D2->setLexicalDeclContext(LexicalDC);
LexicalDC->addDecl(D2);
}
@@ -1900,6 +1912,13 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
D->isInlineSpecified(),
D->hasWrittenPrototype());
}
+
+ // Import the qualifier, if any.
+ if (D->getQualifier()) {
+ NestedNameSpecifier *NNS = Importer.Import(D->getQualifier());
+ SourceRange NNSRange = Importer.Import(D->getQualifierRange());
+ ToFunction->setQualifierInfo(NNS, NNSRange);
+ }
ToFunction->setAccess(D->getAccess());
ToFunction->setLexicalDeclContext(LexicalDC);
Importer.Imported(D, ToFunction);
@@ -2110,6 +2129,12 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) {
VarDecl *ToVar = VarDecl::Create(Importer.getToContext(), DC, Loc,
Name.getAsIdentifierInfo(), T, TInfo,
D->getStorageClass());
+ // Import the qualifier, if any.
+ if (D->getQualifier()) {
+ NestedNameSpecifier *NNS = Importer.Import(D->getQualifier());
+ SourceRange NNSRange = Importer.Import(D->getQualifierRange());
+ ToVar->setQualifierInfo(NNS, NNSRange);
+ }
ToVar->setAccess(D->getAccess());
ToVar->setLexicalDeclContext(LexicalDC);
Importer.Imported(D, ToVar);
@@ -2176,6 +2201,7 @@ Decl *ASTNodeImporter::VisitParmVarDecl(ParmVarDecl *D) {
Loc, Name.getAsIdentifierInfo(),
T, TInfo, D->getStorageClass(),
/*FIXME: Default argument*/ 0);
+ ToParm->setHasInheritedDefaultArg(D->hasInheritedDefaultArg());
return Importer.Imported(D, ToParm);
}
@@ -3063,7 +3089,7 @@ FileID ASTImporter::Import(FileID FromID) {
FromSLoc.getFile().getFileCharacteristic());
} else {
// FIXME: We want to re-use the existing MemoryBuffer!
- const llvm::MemoryBuffer *FromBuf = Cache->getBuffer();
+ const llvm::MemoryBuffer *FromBuf = Cache->getBuffer(getDiags());
llvm::MemoryBuffer *ToBuf
= llvm::MemoryBuffer::getMemBufferCopy(FromBuf->getBufferStart(),
FromBuf->getBufferEnd(),
diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt
index 2f1a6af..3408a1e 100644
--- a/lib/AST/CMakeLists.txt
+++ b/lib/AST/CMakeLists.txt
@@ -11,6 +11,7 @@ add_clang_library(clangAST
Decl.cpp
DeclBase.cpp
DeclCXX.cpp
+ DeclFriend.cpp
DeclGroup.cpp
DeclObjC.cpp
DeclPrinter.cpp
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 23f5fba..f568d1c 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -495,9 +495,16 @@ NamedDecl *NamedDecl::getUnderlyingDecl() {
// DeclaratorDecl Implementation
//===----------------------------------------------------------------------===//
+DeclaratorDecl::~DeclaratorDecl() {}
+void DeclaratorDecl::Destroy(ASTContext &C) {
+ if (hasExtInfo())
+ C.Deallocate(getExtInfo());
+ ValueDecl::Destroy(C);
+}
+
SourceLocation DeclaratorDecl::getTypeSpecStartLoc() const {
if (DeclInfo) {
- TypeLoc TL = DeclInfo->getTypeLoc();
+ TypeLoc TL = getTypeSourceInfo()->getTypeLoc();
while (true) {
TypeLoc NextTL = TL.getNextTypeLoc();
if (!NextTL)
@@ -508,6 +515,36 @@ SourceLocation DeclaratorDecl::getTypeSpecStartLoc() const {
return SourceLocation();
}
+void DeclaratorDecl::setQualifierInfo(NestedNameSpecifier *Qualifier,
+ SourceRange QualifierRange) {
+ if (Qualifier) {
+ // Make sure the extended decl info is allocated.
+ if (!hasExtInfo()) {
+ // Save (non-extended) type source info pointer.
+ TypeSourceInfo *savedTInfo = DeclInfo.get<TypeSourceInfo*>();
+ // Allocate external info struct.
+ DeclInfo = new (getASTContext()) ExtInfo;
+ // Restore savedTInfo into (extended) decl info.
+ getExtInfo()->TInfo = savedTInfo;
+ }
+ // Set qualifier info.
+ getExtInfo()->NNS = Qualifier;
+ getExtInfo()->NNSRange = QualifierRange;
+ }
+ else {
+ // Here Qualifier == 0, i.e., we are removing the qualifier (if any).
+ assert(QualifierRange.isInvalid());
+ if (hasExtInfo()) {
+ // Save type source info pointer.
+ TypeSourceInfo *savedTInfo = getExtInfo()->TInfo;
+ // Deallocate the extended decl info.
+ getASTContext().Deallocate(getExtInfo());
+ // Restore savedTInfo into (non-extended) decl info.
+ DeclInfo = savedTInfo;
+ }
+ }
+}
+
//===----------------------------------------------------------------------===//
// VarDecl Implementation
//===----------------------------------------------------------------------===//
@@ -542,7 +579,7 @@ void VarDecl::Destroy(ASTContext& C) {
}
}
this->~VarDecl();
- C.Deallocate((void *)this);
+ DeclaratorDecl::Destroy(C);
}
VarDecl::~VarDecl() {
@@ -818,7 +855,7 @@ void FunctionDecl::Destroy(ASTContext& C) {
C.Deallocate(ParamInfo);
- Decl::Destroy(C);
+ DeclaratorDecl::Destroy(C);
}
void FunctionDecl::getNameForDiagnostic(std::string &S,
@@ -1348,6 +1385,12 @@ bool FieldDecl::isAnonymousStructOrUnion() const {
// TagDecl Implementation
//===----------------------------------------------------------------------===//
+void TagDecl::Destroy(ASTContext &C) {
+ if (hasExtInfo())
+ C.Deallocate(getExtInfo());
+ TypeDecl::Destroy(C);
+}
+
SourceRange TagDecl::getSourceRange() const {
SourceLocation E = RBraceLoc.isValid() ? RBraceLoc : getLocation();
return SourceRange(TagKeywordLoc, E);
@@ -1409,6 +1452,26 @@ TagDecl::TagKind TagDecl::getTagKindForTypeSpec(unsigned TypeSpec) {
}
}
+void TagDecl::setQualifierInfo(NestedNameSpecifier *Qualifier,
+ SourceRange QualifierRange) {
+ if (Qualifier) {
+ // Make sure the extended qualifier info is allocated.
+ if (!hasExtInfo())
+ TypedefDeclOrQualifier = new (getASTContext()) ExtInfo;
+ // Set qualifier info.
+ getExtInfo()->NNS = Qualifier;
+ getExtInfo()->NNSRange = QualifierRange;
+ }
+ else {
+ // Here Qualifier == 0, i.e., we are removing the qualifier (if any).
+ assert(QualifierRange.isInvalid());
+ if (hasExtInfo()) {
+ getASTContext().Deallocate(getExtInfo());
+ TypedefDeclOrQualifier = (TypedefDecl*) 0;
+ }
+ }
+}
+
//===----------------------------------------------------------------------===//
// EnumDecl Implementation
//===----------------------------------------------------------------------===//
@@ -1422,7 +1485,7 @@ EnumDecl *EnumDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L,
}
void EnumDecl::Destroy(ASTContext& C) {
- Decl::Destroy(C);
+ TagDecl::Destroy(C);
}
void EnumDecl::completeDefinition(QualType NewType,
@@ -1529,7 +1592,7 @@ void NamespaceDecl::Destroy(ASTContext& C) {
// together. They are all top-level Decls.
this->~NamespaceDecl();
- C.Deallocate((void *)this);
+ Decl::Destroy(C);
}
@@ -1563,7 +1626,7 @@ EnumConstantDecl *EnumConstantDecl::Create(ASTContext &C, EnumDecl *CD,
void EnumConstantDecl::Destroy(ASTContext& C) {
if (Init) Init->Destroy(C);
- Decl::Destroy(C);
+ ValueDecl::Destroy(C);
}
TypedefDecl *TypedefDecl::Create(ASTContext &C, DeclContext *DC,
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index a949534..1aac7cf 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -15,6 +15,7 @@
#include "clang/AST/Decl.h"
#include "clang/AST/DeclContextInternals.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclFriend.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/ExternalASTSource.h"
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index 7f4ad34..37f7479 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -33,7 +33,7 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D)
HasTrivialCopyConstructor(true), HasTrivialCopyAssignment(true),
HasTrivialDestructor(true), ComputedVisibleConversions(false),
Bases(0), NumBases(0), VBases(0), NumVBases(0),
- Definition(D) {
+ Definition(D), FirstFriend(0) {
}
CXXRecordDecl::CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC,
@@ -318,105 +318,128 @@ void CXXRecordDecl::addedAssignmentOperator(ASTContext &Context,
data().PlainOldData = false;
}
-void
-CXXRecordDecl::collectConversionFunctions(
- llvm::SmallPtrSet<CanQualType, 8>& ConversionsTypeSet) const
-{
- const UnresolvedSetImpl *Cs = getConversionFunctions();
- for (UnresolvedSetImpl::iterator I = Cs->begin(), E = Cs->end();
- I != E; ++I) {
- NamedDecl *TopConv = *I;
- CanQualType TConvType;
- if (FunctionTemplateDecl *TConversionTemplate =
- dyn_cast<FunctionTemplateDecl>(TopConv))
- TConvType =
- getASTContext().getCanonicalType(
- TConversionTemplate->getTemplatedDecl()->getResultType());
- else
- TConvType =
- getASTContext().getCanonicalType(
- cast<CXXConversionDecl>(TopConv)->getConversionType());
- ConversionsTypeSet.insert(TConvType);
- }
-}
-
-/// getNestedVisibleConversionFunctions - imports unique conversion
-/// functions from base classes into the visible conversion function
-/// list of the class 'RD'. This is a private helper method.
-/// TopConversionsTypeSet is the set of conversion functions of the class
-/// we are interested in. HiddenConversionTypes is set of conversion functions
-/// of the immediate derived class which hides the conversion functions found
-/// in current class.
-void
-CXXRecordDecl::getNestedVisibleConversionFunctions(CXXRecordDecl *RD,
- const llvm::SmallPtrSet<CanQualType, 8> &TopConversionsTypeSet,
- const llvm::SmallPtrSet<CanQualType, 8> &HiddenConversionTypes)
-{
- bool inTopClass = (RD == this);
- QualType ClassType = getASTContext().getTypeDeclType(this);
- if (const RecordType *Record = ClassType->getAs<RecordType>()) {
- const UnresolvedSetImpl *Cs
- = cast<CXXRecordDecl>(Record->getDecl())->getConversionFunctions();
-
- for (UnresolvedSetImpl::iterator I = Cs->begin(), E = Cs->end();
- I != E; ++I) {
- NamedDecl *Conv = *I;
- // Only those conversions not exact match of conversions in current
- // class are candidateconversion routines.
- CanQualType ConvType;
- if (FunctionTemplateDecl *ConversionTemplate =
- dyn_cast<FunctionTemplateDecl>(Conv))
- ConvType =
- getASTContext().getCanonicalType(
- ConversionTemplate->getTemplatedDecl()->getResultType());
- else
- ConvType =
- getASTContext().getCanonicalType(
- cast<CXXConversionDecl>(Conv)->getConversionType());
- // We only add conversion functions found in the base class if they
- // are not hidden by those found in HiddenConversionTypes which are
- // the conversion functions in its derived class.
- if (inTopClass ||
- (!TopConversionsTypeSet.count(ConvType) &&
- !HiddenConversionTypes.count(ConvType)) ) {
- if (FunctionTemplateDecl *ConversionTemplate =
- dyn_cast<FunctionTemplateDecl>(Conv))
- RD->addVisibleConversionFunction(ConversionTemplate);
+static CanQualType GetConversionType(ASTContext &Context, NamedDecl *Conv) {
+ QualType T;
+ if (FunctionTemplateDecl *ConvTemp = dyn_cast<FunctionTemplateDecl>(Conv))
+ T = ConvTemp->getTemplatedDecl()->getResultType();
+ else
+ T = cast<CXXConversionDecl>(Conv)->getConversionType();
+ return Context.getCanonicalType(T);
+}
+
+/// Collect the visible conversions of a base class.
+///
+/// \param Base a base class of the class we're considering
+/// \param InVirtual whether this base class is a virtual base (or a base
+/// of a virtual base)
+/// \param Access the access along the inheritance path to this base
+/// \param ParentHiddenTypes the conversions provided by the inheritors
+/// of this base
+/// \param Output the set to which to add conversions from non-virtual bases
+/// \param VOutput the set to which to add conversions from virtual bases
+/// \param HiddenVBaseCs the set of conversions which were hidden in a
+/// virtual base along some inheritance path
+static void CollectVisibleConversions(ASTContext &Context,
+ CXXRecordDecl *Record,
+ bool InVirtual,
+ AccessSpecifier Access,
+ const llvm::SmallPtrSet<CanQualType, 8> &ParentHiddenTypes,
+ UnresolvedSetImpl &Output,
+ UnresolvedSetImpl &VOutput,
+ llvm::SmallPtrSet<NamedDecl*, 8> &HiddenVBaseCs) {
+ // The set of types which have conversions in this class or its
+ // subclasses. As an optimization, we don't copy the derived set
+ // unless it might change.
+ const llvm::SmallPtrSet<CanQualType, 8> *HiddenTypes = &ParentHiddenTypes;
+ llvm::SmallPtrSet<CanQualType, 8> HiddenTypesBuffer;
+
+ // Collect the direct conversions and figure out which conversions
+ // will be hidden in the subclasses.
+ UnresolvedSetImpl &Cs = *Record->getConversionFunctions();
+ if (!Cs.empty()) {
+ HiddenTypesBuffer = ParentHiddenTypes;
+ HiddenTypes = &HiddenTypesBuffer;
+
+ for (UnresolvedSetIterator I = Cs.begin(), E = Cs.end(); I != E; ++I) {
+ bool Hidden =
+ !HiddenTypesBuffer.insert(GetConversionType(Context, I.getDecl()));
+
+ // If this conversion is hidden and we're in a virtual base,
+ // remember that it's hidden along some inheritance path.
+ if (Hidden && InVirtual)
+ HiddenVBaseCs.insert(cast<NamedDecl>(I.getDecl()->getCanonicalDecl()));
+
+ // If this conversion isn't hidden, add it to the appropriate output.
+ else if (!Hidden) {
+ AccessSpecifier IAccess
+ = CXXRecordDecl::MergeAccess(Access, I.getAccess());
+
+ if (InVirtual)
+ VOutput.addDecl(I.getDecl(), IAccess);
else
- RD->addVisibleConversionFunction(cast<CXXConversionDecl>(Conv));
+ Output.addDecl(I.getDecl(), IAccess);
}
}
}
- if (getNumBases() == 0 && getNumVBases() == 0)
- return;
+ // Collect information recursively from any base classes.
+ for (CXXRecordDecl::base_class_iterator
+ I = Record->bases_begin(), E = Record->bases_end(); I != E; ++I) {
+ const RecordType *RT = I->getType()->getAs<RecordType>();
+ if (!RT) continue;
- llvm::SmallPtrSet<CanQualType, 8> ConversionFunctions;
- if (!inTopClass)
- collectConversionFunctions(ConversionFunctions);
+ AccessSpecifier BaseAccess
+ = CXXRecordDecl::MergeAccess(Access, I->getAccessSpecifier());
+ bool BaseInVirtual = InVirtual || I->isVirtual();
- for (CXXRecordDecl::base_class_iterator VBase = vbases_begin(),
- E = vbases_end(); VBase != E; ++VBase) {
- if (const RecordType *RT = VBase->getType()->getAs<RecordType>()) {
- CXXRecordDecl *VBaseClassDecl
- = cast<CXXRecordDecl>(RT->getDecl());
- VBaseClassDecl->getNestedVisibleConversionFunctions(RD,
- TopConversionsTypeSet,
- (inTopClass ? TopConversionsTypeSet : ConversionFunctions));
- }
+ CXXRecordDecl *Base = cast<CXXRecordDecl>(RT->getDecl());
+ CollectVisibleConversions(Context, Base, BaseInVirtual, BaseAccess,
+ *HiddenTypes, Output, VOutput, HiddenVBaseCs);
}
- for (CXXRecordDecl::base_class_iterator Base = bases_begin(),
- E = bases_end(); Base != E; ++Base) {
- if (Base->isVirtual())
- continue;
- if (const RecordType *RT = Base->getType()->getAs<RecordType>()) {
- CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(RT->getDecl());
+}
- BaseClassDecl->getNestedVisibleConversionFunctions(RD,
- TopConversionsTypeSet,
- (inTopClass ? TopConversionsTypeSet : ConversionFunctions));
- }
+/// Collect the visible conversions of a class.
+///
+/// This would be extremely straightforward if it weren't for virtual
+/// bases. It might be worth special-casing that, really.
+static void CollectVisibleConversions(ASTContext &Context,
+ CXXRecordDecl *Record,
+ UnresolvedSetImpl &Output) {
+ // The collection of all conversions in virtual bases that we've
+ // found. These will be added to the output as long as they don't
+ // appear in the hidden-conversions set.
+ UnresolvedSet<8> VBaseCs;
+
+ // The set of conversions in virtual bases that we've determined to
+ // be hidden.
+ llvm::SmallPtrSet<NamedDecl*, 8> HiddenVBaseCs;
+
+ // The set of types hidden by classes derived from this one.
+ llvm::SmallPtrSet<CanQualType, 8> HiddenTypes;
+
+ // Go ahead and collect the direct conversions and add them to the
+ // hidden-types set.
+ UnresolvedSetImpl &Cs = *Record->getConversionFunctions();
+ Output.append(Cs.begin(), Cs.end());
+ for (UnresolvedSetIterator I = Cs.begin(), E = Cs.end(); I != E; ++I)
+ HiddenTypes.insert(GetConversionType(Context, I.getDecl()));
+
+ // Recursively collect conversions from base classes.
+ for (CXXRecordDecl::base_class_iterator
+ I = Record->bases_begin(), E = Record->bases_end(); I != E; ++I) {
+ const RecordType *RT = I->getType()->getAs<RecordType>();
+ if (!RT) continue;
+
+ CollectVisibleConversions(Context, cast<CXXRecordDecl>(RT->getDecl()),
+ I->isVirtual(), I->getAccessSpecifier(),
+ HiddenTypes, Output, VBaseCs, HiddenVBaseCs);
+ }
+
+ // Add any unhidden conversions provided by virtual bases.
+ for (UnresolvedSetIterator I = VBaseCs.begin(), E = VBaseCs.end();
+ I != E; ++I) {
+ if (!HiddenVBaseCs.count(cast<NamedDecl>(I.getDecl()->getCanonicalDecl())))
+ Output.addDecl(I.getDecl(), I.getAccess());
}
}
@@ -429,37 +452,27 @@ const UnresolvedSetImpl *CXXRecordDecl::getVisibleConversionFunctions() {
// If visible conversion list is already evaluated, return it.
if (data().ComputedVisibleConversions)
return &data().VisibleConversions;
- llvm::SmallPtrSet<CanQualType, 8> TopConversionsTypeSet;
- collectConversionFunctions(TopConversionsTypeSet);
- getNestedVisibleConversionFunctions(this, TopConversionsTypeSet,
- TopConversionsTypeSet);
+ CollectVisibleConversions(getASTContext(), this, data().VisibleConversions);
data().ComputedVisibleConversions = true;
return &data().VisibleConversions;
}
-void CXXRecordDecl::addVisibleConversionFunction(
- CXXConversionDecl *ConvDecl) {
- assert(!ConvDecl->getDescribedFunctionTemplate() &&
- "Conversion function templates should cast to FunctionTemplateDecl.");
- data().VisibleConversions.addDecl(ConvDecl);
-}
-
-void CXXRecordDecl::addVisibleConversionFunction(
- FunctionTemplateDecl *ConvDecl) {
- assert(isa<CXXConversionDecl>(ConvDecl->getTemplatedDecl()) &&
- "Function template is not a conversion function template");
- data().VisibleConversions.addDecl(ConvDecl);
-}
-
void CXXRecordDecl::addConversionFunction(CXXConversionDecl *ConvDecl) {
assert(!ConvDecl->getDescribedFunctionTemplate() &&
"Conversion function templates should cast to FunctionTemplateDecl.");
+ assert(ConvDecl->getDeclContext() == this &&
+ "conversion function does not belong to this record");
+
+ // We intentionally don't use the decl's access here because it
+ // hasn't been set yet. That's really just a misdesign in Sema.
data().Conversions.addDecl(ConvDecl);
}
void CXXRecordDecl::addConversionFunction(FunctionTemplateDecl *ConvDecl) {
assert(isa<CXXConversionDecl>(ConvDecl->getTemplatedDecl()) &&
"Function template is not a conversion function template");
+ assert(ConvDecl->getDeclContext() == this &&
+ "conversion function does not belong to this record");
data().Conversions.addDecl(ConvDecl);
}
@@ -846,28 +859,6 @@ CXXConversionDecl::Create(ASTContext &C, CXXRecordDecl *RD,
return new (C) CXXConversionDecl(RD, L, N, T, TInfo, isInline, isExplicit);
}
-FriendDecl *FriendDecl::Create(ASTContext &C, DeclContext *DC,
- SourceLocation L,
- FriendUnion Friend,
- SourceLocation FriendL) {
-#ifndef NDEBUG
- if (Friend.is<NamedDecl*>()) {
- NamedDecl *D = Friend.get<NamedDecl*>();
- assert(isa<FunctionDecl>(D) ||
- isa<CXXRecordDecl>(D) ||
- isa<FunctionTemplateDecl>(D) ||
- isa<ClassTemplateDecl>(D));
-
- // As a temporary hack, we permit template instantiation to point
- // to the original declaration when instantiating members.
- assert(D->getFriendObjectKind() ||
- (cast<CXXRecordDecl>(DC)->getTemplateSpecializationKind()));
- }
-#endif
-
- return new (C) FriendDecl(DC, L, Friend, FriendL);
-}
-
LinkageSpecDecl *LinkageSpecDecl::Create(ASTContext &C,
DeclContext *DC,
SourceLocation L,
@@ -952,8 +943,7 @@ StaticAssertDecl *StaticAssertDecl::Create(ASTContext &C, DeclContext *DC,
void StaticAssertDecl::Destroy(ASTContext& C) {
AssertExpr->Destroy(C);
Message->Destroy(C);
- this->~StaticAssertDecl();
- C.Deallocate((void *)this);
+ Decl::Destroy(C);
}
StaticAssertDecl::~StaticAssertDecl() {
diff --git a/lib/AST/DeclFriend.cpp b/lib/AST/DeclFriend.cpp
new file mode 100644
index 0000000..ab3552d
--- /dev/null
+++ b/lib/AST/DeclFriend.cpp
@@ -0,0 +1,41 @@
+//===--- DeclFriend.cpp - C++ Friend Declaration AST Node Implementation --===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the AST classes related to C++ friend
+// declarations.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/DeclFriend.h"
+#include "clang/AST/DeclTemplate.h"
+using namespace clang;
+
+FriendDecl *FriendDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L,
+ FriendUnion Friend,
+ SourceLocation FriendL) {
+#ifndef NDEBUG
+ if (Friend.is<NamedDecl*>()) {
+ NamedDecl *D = Friend.get<NamedDecl*>();
+ assert(isa<FunctionDecl>(D) ||
+ isa<CXXRecordDecl>(D) ||
+ isa<FunctionTemplateDecl>(D) ||
+ isa<ClassTemplateDecl>(D));
+
+ // As a temporary hack, we permit template instantiation to point
+ // to the original declaration when instantiating members.
+ assert(D->getFriendObjectKind() ||
+ (cast<CXXRecordDecl>(DC)->getTemplateSpecializationKind()));
+ }
+#endif
+
+ FriendDecl *FD = new (C) FriendDecl(DC, L, Friend, FriendL);
+ cast<CXXRecordDecl>(DC)->pushFriendDecl(FD);
+ return FD;
+}
diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp
index 67b71a0..7d1033d 100644
--- a/lib/AST/DeclObjC.cpp
+++ b/lib/AST/DeclObjC.cpp
@@ -89,47 +89,69 @@ ObjCContainerDecl::getMethod(Selector Sel, bool isInstance) const {
return 0;
}
+ObjCPropertyDecl *
+ObjCPropertyDecl::findPropertyDecl(const DeclContext *DC,
+ IdentifierInfo *propertyID) {
+
+ DeclContext::lookup_const_iterator I, E;
+ llvm::tie(I, E) = DC->lookup(propertyID);
+ for ( ; I != E; ++I)
+ if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(*I))
+ return PD;
+
+ return 0;
+}
+
/// FindPropertyDeclaration - Finds declaration of the property given its name
/// in 'PropertyId' and returns it. It returns 0, if not found.
-/// FIXME: Convert to DeclContext lookup...
-///
ObjCPropertyDecl *
ObjCContainerDecl::FindPropertyDeclaration(IdentifierInfo *PropertyId) const {
- for (prop_iterator I = prop_begin(), E = prop_end(); I != E; ++I)
- if ((*I)->getIdentifier() == PropertyId)
- return *I;
-
- const ObjCProtocolDecl *PID = dyn_cast<ObjCProtocolDecl>(this);
- if (PID) {
- for (ObjCProtocolDecl::protocol_iterator I = PID->protocol_begin(),
- E = PID->protocol_end(); I != E; ++I)
- if (ObjCPropertyDecl *P = (*I)->FindPropertyDeclaration(PropertyId))
- return P;
- }
- if (const ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(this)) {
- // Look through categories.
- for (ObjCCategoryDecl *Category = OID->getCategoryList();
- Category; Category = Category->getNextClassCategory()) {
- if (!Category->IsClassExtension())
- if (ObjCPropertyDecl *P = Category->FindPropertyDeclaration(PropertyId))
+ if (ObjCPropertyDecl *PD =
+ ObjCPropertyDecl::findPropertyDecl(cast<DeclContext>(this), PropertyId))
+ return PD;
+
+ switch (getKind()) {
+ default:
+ break;
+ case Decl::ObjCProtocol: {
+ const ObjCProtocolDecl *PID = cast<ObjCProtocolDecl>(this);
+ for (ObjCProtocolDecl::protocol_iterator I = PID->protocol_begin(),
+ E = PID->protocol_end(); I != E; ++I)
+ if (ObjCPropertyDecl *P = (*I)->FindPropertyDeclaration(PropertyId))
return P;
+ break;
}
- // Look through protocols.
- for (ObjCInterfaceDecl::protocol_iterator I = OID->protocol_begin(),
- E = OID->protocol_end(); I != E; ++I) {
- if (ObjCPropertyDecl *P = (*I)->FindPropertyDeclaration(PropertyId))
- return P;
+ case Decl::ObjCInterface: {
+ const ObjCInterfaceDecl *OID = cast<ObjCInterfaceDecl>(this);
+ // Look through categories.
+ for (ObjCCategoryDecl *Cat = OID->getCategoryList();
+ Cat; Cat = Cat->getNextClassCategory())
+ if (!Cat->IsClassExtension())
+ if (ObjCPropertyDecl *P = Cat->FindPropertyDeclaration(PropertyId))
+ return P;
+
+ // Look through protocols.
+ for (ObjCInterfaceDecl::protocol_iterator
+ I = OID->protocol_begin(), E = OID->protocol_end(); I != E; ++I)
+ if (ObjCPropertyDecl *P = (*I)->FindPropertyDeclaration(PropertyId))
+ return P;
+
+ // Finally, check the super class.
+ if (const ObjCInterfaceDecl *superClass = OID->getSuperClass())
+ return superClass->FindPropertyDeclaration(PropertyId);
+ break;
}
- if (OID->getSuperClass())
- return OID->getSuperClass()->FindPropertyDeclaration(PropertyId);
- } else if (const ObjCCategoryDecl *OCD = dyn_cast<ObjCCategoryDecl>(this)) {
- // Look through protocols.
- if (!OCD->IsClassExtension())
- for (ObjCInterfaceDecl::protocol_iterator I = OCD->protocol_begin(),
- E = OCD->protocol_end(); I != E; ++I) {
+ case Decl::ObjCCategory: {
+ const ObjCCategoryDecl *OCD = cast<ObjCCategoryDecl>(this);
+ // Look through protocols.
+ if (!OCD->IsClassExtension())
+ for (ObjCCategoryDecl::protocol_iterator
+ I = OCD->protocol_begin(), E = OCD->protocol_end(); I != E; ++I)
if (ObjCPropertyDecl *P = (*I)->FindPropertyDeclaration(PropertyId))
return P;
+
+ break;
}
}
return 0;
@@ -137,22 +159,21 @@ ObjCContainerDecl::FindPropertyDeclaration(IdentifierInfo *PropertyId) const {
/// FindPropertyVisibleInPrimaryClass - Finds declaration of the property
/// with name 'PropertyId' in the primary class; including those in protocols
-/// (direct or indirect) used by the promary class.
-/// FIXME: Convert to DeclContext lookup...
+/// (direct or indirect) used by the primary class.
///
ObjCPropertyDecl *
-ObjCContainerDecl::FindPropertyVisibleInPrimaryClass(
+ObjCInterfaceDecl::FindPropertyVisibleInPrimaryClass(
IdentifierInfo *PropertyId) const {
- assert(isa<ObjCInterfaceDecl>(this) && "FindPropertyVisibleInPrimaryClass");
- for (prop_iterator I = prop_begin(), E = prop_end(); I != E; ++I)
- if ((*I)->getIdentifier() == PropertyId)
- return *I;
- const ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(this);
+ if (ObjCPropertyDecl *PD =
+ ObjCPropertyDecl::findPropertyDecl(cast<DeclContext>(this), PropertyId))
+ return PD;
+
// Look through protocols.
- for (ObjCInterfaceDecl::protocol_iterator I = OID->protocol_begin(),
- E = OID->protocol_end(); I != E; ++I)
+ for (ObjCInterfaceDecl::protocol_iterator
+ I = protocol_begin(), E = protocol_end(); I != E; ++I)
if (ObjCPropertyDecl *P = (*I)->FindPropertyDeclaration(PropertyId))
return P;
+
return 0;
}
@@ -441,7 +462,6 @@ void ObjCInterfaceDecl::Destroy(ASTContext &C) {
for (ivar_iterator I = ivar_begin(), E = ivar_end(); I != E; ++I)
if (*I) (*I)->Destroy(C);
- IVars.Destroy(C);
// FIXME: CategoryList?
// FIXME: Because there is no clear ownership
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index efd0fd1..1b3202d 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -788,6 +788,8 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1,
switch (getStmtClass()) {
default:
+ if (getType()->isVoidType())
+ return false;
Loc = getExprLoc();
R1 = getSourceRange();
return true;
@@ -834,8 +836,8 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1,
if (IE->getValue() == 0)
return false;
- return (BO->getRHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx) ||
- BO->getLHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx));
+ return (BO->getLHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx) ||
+ BO->getRHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx));
}
if (BO->isAssignmentOp())
@@ -936,6 +938,8 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1,
if (const Expr *E = dyn_cast<Expr>(CS->body_back()))
return E->isUnusedResultAWarning(Loc, R1, R2, Ctx);
+ if (getType()->isVoidType())
+ return false;
Loc = cast<StmtExpr>(this)->getLParenLoc();
R1 = getSourceRange();
return true;
@@ -949,6 +953,8 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1,
R1 = cast<CStyleCastExpr>(this)->getSubExpr()->getSourceRange();
return true;
case CXXFunctionalCastExprClass: {
+ if (getType()->isVoidType())
+ return false;
const CastExpr *CE = cast<CastExpr>(this);
// If this is a cast to void or a constructor conversion, check the operand.
diff --git a/lib/AST/Makefile b/lib/AST/Makefile
index 8afc629..ede2577 100644
--- a/lib/AST/Makefile
+++ b/lib/AST/Makefile
@@ -15,7 +15,7 @@ LEVEL = ../../../..
LIBRARYNAME := clangAST
BUILD_ARCHIVE = 1
-CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
+CPP.Flags += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
include $(LEVEL)/Makefile.common
diff --git a/lib/AST/RecordLayout.cpp b/lib/AST/RecordLayout.cpp
index 838753a..ade2483 100644
--- a/lib/AST/RecordLayout.cpp
+++ b/lib/AST/RecordLayout.cpp
@@ -38,17 +38,15 @@ ASTRecordLayout::ASTRecordLayout(ASTContext &Ctx, uint64_t size, unsigned alignm
// Constructor for C++ records.
ASTRecordLayout::ASTRecordLayout(ASTContext &Ctx,
- uint64_t size, unsigned alignment,
- uint64_t datasize,
- const uint64_t *fieldoffsets,
- unsigned fieldcount,
- uint64_t nonvirtualsize,
- unsigned nonvirtualalign,
- const PrimaryBaseInfo &PrimaryBase,
- const std::pair<const CXXRecordDecl *, uint64_t> *bases,
- unsigned numbases,
- const std::pair<const CXXRecordDecl *, uint64_t> *vbases,
- unsigned numvbases)
+ uint64_t size, unsigned alignment,
+ uint64_t datasize,
+ const uint64_t *fieldoffsets,
+ unsigned fieldcount,
+ uint64_t nonvirtualsize,
+ unsigned nonvirtualalign,
+ const PrimaryBaseInfo &PrimaryBase,
+ const BaseOffsetsMapTy& BaseOffsets,
+ const BaseOffsetsMapTy& VBaseOffsets)
: Size(size), DataSize(datasize), FieldOffsets(0), Alignment(alignment),
FieldCount(fieldcount), CXXInfo(new (Ctx) CXXRecordLayoutInfo)
{
@@ -60,8 +58,17 @@ ASTRecordLayout::ASTRecordLayout(ASTContext &Ctx,
CXXInfo->PrimaryBase = PrimaryBase;
CXXInfo->NonVirtualSize = nonvirtualsize;
CXXInfo->NonVirtualAlign = nonvirtualalign;
- for (unsigned i = 0; i != numbases; ++i)
- CXXInfo->BaseOffsets[bases[i].first] = bases[i].second;
- for (unsigned i = 0; i != numvbases; ++i)
- CXXInfo->VBaseOffsets[vbases[i].first] = vbases[i].second;
+ CXXInfo->BaseOffsets = BaseOffsets;
+ CXXInfo->VBaseOffsets = VBaseOffsets;
+
+#ifndef NDEBUG
+ if (const CXXRecordDecl *PrimaryBase = getPrimaryBase()) {
+ if (getPrimaryBaseWasVirtual())
+ assert(getVBaseClassOffset(PrimaryBase) == 0 &&
+ "Primary virtual base must be at offset 0!");
+ else
+ assert(getBaseClassOffset(PrimaryBase) == 0 &&
+ "Primary base must be at offset 0!");
+ }
+#endif
}
diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp
index 22285ca..93edb42 100644
--- a/lib/AST/RecordLayoutBuilder.cpp
+++ b/lib/AST/RecordLayoutBuilder.cpp
@@ -23,43 +23,8 @@ using namespace clang;
ASTRecordLayoutBuilder::ASTRecordLayoutBuilder(ASTContext &Ctx)
: Ctx(Ctx), Size(0), Alignment(8), Packed(false), UnfilledBitsInLastByte(0),
MaxFieldAlignment(0), DataSize(0), IsUnion(false), NonVirtualSize(0),
- NonVirtualAlignment(8) { }
+ NonVirtualAlignment(8), FirstNearlyEmptyVBase(0) { }
-/// LayoutVtable - Lay out the vtable and set PrimaryBase.
-void ASTRecordLayoutBuilder::LayoutVtable(const CXXRecordDecl *RD) {
- if (!RD->isDynamicClass()) {
- // There is no primary base in this case.
- return;
- }
-
- SelectPrimaryBase(RD);
- if (!PrimaryBase.getBase()) {
- int AS = 0;
- UpdateAlignment(Ctx.Target.getPointerAlign(AS));
- Size += Ctx.Target.getPointerWidth(AS);
- DataSize = Size;
- }
-}
-
-void
-ASTRecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) {
- for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
- e = RD->bases_end(); i != e; ++i) {
- if (!i->isVirtual()) {
- assert(!i->getType()->isDependentType() &&
- "Cannot layout class with dependent bases.");
- const CXXRecordDecl *Base =
- cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
- // Skip the PrimaryBase here, as it is laid down first.
- if (Base != PrimaryBase.getBase() || PrimaryBase.isVirtual())
- LayoutBaseNonVirtually(Base, false);
- }
- }
-}
-
-// Helper routines related to the abi definition from:
-// http://www.codesourcery.com/public/cxx-abi/abi.html
-//
/// IsNearlyEmpty - Indicates when a class has a vtable pointer, but
/// no other data.
bool ASTRecordLayoutBuilder::IsNearlyEmpty(const CXXRecordDecl *RD) const {
@@ -97,44 +62,48 @@ void ASTRecordLayoutBuilder::IdentifyPrimaryBases(const CXXRecordDecl *RD) {
}
void
-ASTRecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD,
- const CXXRecordDecl *&FirstPrimary) {
- for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
- e = RD->bases_end(); i != e; ++i) {
- assert(!i->getType()->isDependentType() &&
+ASTRecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD) {
+ 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());
- if (!i->isVirtual()) {
- SelectPrimaryVBase(Base, FirstPrimary);
- if (PrimaryBase.getBase())
- return;
- continue;
- }
- if (IsNearlyEmpty(Base)) {
- if (FirstPrimary==0)
- FirstPrimary = Base;
+ cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+
+ // Check if this is a nearly empty virtual base.
+ if (I->isVirtual() && IsNearlyEmpty(Base)) {
+ // If it's not an indirect primary base, then we've found our primary
+ // base.
if (!IndirectPrimaryBases.count(Base)) {
- setPrimaryBase(Base, /*IsVirtual=*/true);
+ PrimaryBase = ASTRecordLayout::PrimaryBaseInfo(Base,
+ /*IsVirtual=*/true);
return;
}
+
+ // Is this the first nearly empty virtual base?
+ if (!FirstNearlyEmptyVBase)
+ FirstNearlyEmptyVBase = Base;
}
- assert(i->isVirtual());
- SelectPrimaryVBase(Base, FirstPrimary);
+
+ SelectPrimaryVBase(Base);
if (PrimaryBase.getBase())
return;
}
}
-/// SelectPrimaryBase - Selects the primary base for the given class and
-/// record that with setPrimaryBase. We also calculate the IndirectPrimaries.
-void ASTRecordLayoutBuilder::SelectPrimaryBase(const CXXRecordDecl *RD) {
+/// DeterminePrimaryBase - Determine the primary base of the given class.
+void ASTRecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) {
+ // If the class isn't dynamic, it won't have a primary base.
+ if (!RD->isDynamicClass())
+ return;
+
// 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 layout class with dependent bases.");
+ "Cannot lay out class with dependent bases.");
const CXXRecordDecl *Base =
cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
IdentifyPrimaryBases(Base);
@@ -161,90 +130,201 @@ void ASTRecordLayoutBuilder::SelectPrimaryBase(const CXXRecordDecl *RD) {
// Otherwise, it is the first nearly empty virtual base that is not an
// indirect primary virtual base class, if one exists.
+ if (RD->getNumVBases() != 0) {
+ SelectPrimaryVBase(RD);
+ if (PrimaryBase.getBase())
+ return;
+ }
- // If we have no virtual bases at this point, bail out as the searching below
- // is expensive.
- if (RD->getNumVBases() == 0)
+ // Otherwise, it is the first nearly empty virtual base that is not an
+ // indirect primary virtual base class, if one exists.
+ if (FirstNearlyEmptyVBase) {
+ PrimaryBase = ASTRecordLayout::PrimaryBaseInfo(FirstNearlyEmptyVBase,
+ /*IsVirtual=*/true);
return;
+ }
- // Then we can search for the first nearly empty virtual base itself.
- const CXXRecordDecl *FirstPrimary = 0;
- SelectPrimaryVBase(RD, FirstPrimary);
-
- // Otherwise if is the first nearly empty virtual base, if one exists,
- // otherwise there is no primary base class.
- if (!PrimaryBase.getBase())
- setPrimaryBase(FirstPrimary, /*IsVirtual=*/true);
-}
+ // Otherwise there is no primary base class.
+ assert(!PrimaryBase.getBase() && "Should not get here with a primary base!");
-void ASTRecordLayoutBuilder::LayoutVirtualBase(const CXXRecordDecl *RD) {
- LayoutBaseNonVirtually(RD, true);
+ // Allocate the virtual table pointer at offset zero.
+ assert(DataSize == 0 && "Vtable pointer must be at offset zero!");
+
+ // Update the size.
+ Size += Ctx.Target.getPointerWidth(0);
+ DataSize = Size;
+
+ // Update the alignment.
+ UpdateAlignment(Ctx.Target.getPointerAlign(0));
}
-uint64_t ASTRecordLayoutBuilder::getBaseOffset(const CXXRecordDecl *Base) {
- for (size_t i = 0; i < Bases.size(); ++i) {
- if (Bases[i].first == Base)
- return Bases[i].second;
+void
+ASTRecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) {
+ // First, determine the primary base class.
+ DeterminePrimaryBase(RD);
+
+ // If we have a primary base class, lay it out.
+ if (const CXXRecordDecl *Base = PrimaryBase.getBase()) {
+ if (PrimaryBase.isVirtual()) {
+ // We have a virtual primary base, insert it as an indirect primary base.
+ IndirectPrimaryBases.insert(Base);
+
+ LayoutVirtualBase(Base);
+ } else
+ LayoutNonVirtualBase(Base);
}
- for (size_t i = 0; i < VBases.size(); ++i) {
- if (VBases[i].first == Base)
- return VBases[i].second;
+
+ // Now lay out the non-virtual bases.
+ for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+ E = RD->bases_end(); I != E; ++I) {
+
+ // Ignore virtual bases.
+ if (I->isVirtual())
+ continue;
+
+ const CXXRecordDecl *Base =
+ cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+
+ // Skip the primary base.
+ if (Base == PrimaryBase.getBase() && !PrimaryBase.isVirtual())
+ continue;
+
+ // Lay out the base.
+ LayoutNonVirtualBase(Base);
}
- assert(0 && "missing base");
- return 0;
}
+void ASTRecordLayoutBuilder::LayoutNonVirtualBase(const CXXRecordDecl *RD) {
+ // Layout the base.
+ uint64_t Offset = LayoutBase(RD);
+
+ // Add its base class offset.
+ if (!Bases.insert(std::make_pair(RD, Offset)).second)
+ assert(false && "Added same base offset more than once!");
+}
-void ASTRecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *Class,
- const CXXRecordDecl *RD,
- const CXXRecordDecl *PB,
- uint64_t Offset,
- llvm::SmallSet<const CXXRecordDecl*, 32> &mark,
- llvm::SmallSet<const CXXRecordDecl*, 32> &IndirectPrimary) {
- for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
- e = RD->bases_end(); i != e; ++i) {
- assert(!i->getType()->isDependentType() &&
+void
+ASTRecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD,
+ uint64_t Offset,
+ const CXXRecordDecl *MostDerivedClass) {
+ const CXXRecordDecl *PrimaryBase;
+
+ if (MostDerivedClass == RD)
+ PrimaryBase = this->PrimaryBase.getBase();
+ else {
+ const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD);
+ PrimaryBase = Layout.getPrimaryBase();
+ }
+
+ 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());
- uint64_t BaseOffset = Offset;
- if (i->isVirtual()) {
- if (Base == PB) {
- // Only lay things out once.
- if (mark.count(Base))
- continue;
- // Mark it so we don't lay it out twice.
- mark.insert(Base);
- assert (IndirectPrimary.count(Base) && "IndirectPrimary was wrong");
- VBases.push_back(std::make_pair(Base, Offset));
- } else if (IndirectPrimary.count(Base)) {
- // Someone else will eventually lay this out.
- ;
- } else {
+ cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+
+ if (I->isVirtual()) {
+ bool IndirectPrimaryBase = IndirectPrimaryBases.count(Base);
+
+ // We only want to visit this virtual base if it's either a primary base,
+ // or not an indirect primary base.
+ if (Base == PrimaryBase || !IndirectPrimaryBase) {
// Only lay things out once.
- if (mark.count(Base))
+ if (!VisitedVirtualBases.insert(Base))
continue;
- // Mark it so we don't lay it out twice.
- mark.insert(Base);
- LayoutVirtualBase(Base);
- BaseOffset = VBases.back().second;
- }
- } else {
- if (RD == Class)
- BaseOffset = getBaseOffset(Base);
- else {
- const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD);
- BaseOffset = Offset + Layout.getBaseClassOffset(Base);
+
+ if (Base == PrimaryBase) {
+ assert(IndirectPrimaryBase &&
+ "Base is supposed to be an indirect primary base!");
+
+ // We only want to add a vbase offset if this primary base is not the
+ // primary base of the most derived class.
+ if (PrimaryBase != this->PrimaryBase.getBase() ||
+ !this->PrimaryBase.isVirtual()) {
+ if (!VBases.insert(std::make_pair(Base, Offset)).second)
+ assert(false && "Added same vbase offset more than once!");
+ }
+ } else {
+ // We actually do want to lay out this base.
+ LayoutVirtualBase(Base);
+ }
}
}
- if (Base->getNumVBases()) {
- const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(Base);
- const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBaseInfo().getBase();
- LayoutVirtualBases(Class, Base, PrimaryBase, BaseOffset, mark,
- IndirectPrimary);
+ if (!Base->getNumVBases()) {
+ // This base isn't interesting since it doesn't have any virtual bases.
+ continue;
+ }
+
+ // Compute the offset of this base.
+ uint64_t BaseOffset;
+
+ if (I->isVirtual()) {
+ // We want the vbase offset from the class we're currently laying out.
+ assert(VBases.count(Base) && "Did not find virtual base!");
+ BaseOffset = VBases[Base];
+ } else if (RD == MostDerivedClass) {
+ // We want the base offset from the class we're currently laying out.
+ assert(Bases.count(Base) && "Did not find base!");
+ BaseOffset = Bases[Base];
+ } else {
+ const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD);
+ BaseOffset = Offset + Layout.getBaseClassOffset(Base);
}
+
+ LayoutVirtualBases(Base, BaseOffset, MostDerivedClass);
+ }
+}
+
+void ASTRecordLayoutBuilder::LayoutVirtualBase(const CXXRecordDecl *RD) {
+ // Layout the base.
+ uint64_t Offset = LayoutBase(RD);
+
+ // Add its base class offset.
+ if (!VBases.insert(std::make_pair(RD, Offset)).second)
+ assert(false && "Added same vbase offset more than once!");
+}
+
+uint64_t ASTRecordLayoutBuilder::LayoutBase(const CXXRecordDecl *RD) {
+ const ASTRecordLayout &BaseInfo = Ctx.getASTRecordLayout(RD);
+
+ // If we have an empty base class, try to place it at offset 0.
+ if (RD->isEmpty() && canPlaceRecordAtOffset(RD, 0)) {
+ // We were able to place the class at offset 0.
+ UpdateEmptyClassOffsets(RD, 0);
+
+ Size = std::max(Size, BaseInfo.getSize());
+
+ return 0;
+ }
+
+ unsigned BaseAlign = BaseInfo.getNonVirtualAlign();
+
+ // Round up the current record size to the base's alignment boundary.
+ uint64_t Offset = llvm::RoundUpToAlignment(DataSize, BaseAlign);
+
+ // Try to place the base.
+ while (true) {
+ if (canPlaceRecordAtOffset(RD, Offset))
+ break;
+
+ Offset += BaseAlign;
}
+
+ if (!RD->isEmpty()) {
+ // Update the data size.
+ DataSize = Offset + BaseInfo.getNonVirtualSize();
+
+ Size = std::max(Size, DataSize);
+ } else
+ Size = std::max(Size, Offset + BaseInfo.getSize());
+
+ // Remember max struct/class alignment.
+ UpdateAlignment(BaseAlign);
+
+ UpdateEmptyClassOffsets(RD, Offset);
+ return Offset;
}
bool ASTRecordLayoutBuilder::canPlaceRecordAtOffset(const CXXRecordDecl *RD,
@@ -393,59 +473,6 @@ ASTRecordLayoutBuilder::UpdateEmptyClassOffsets(const FieldDecl *FD,
}
}
-uint64_t ASTRecordLayoutBuilder::LayoutBase(const CXXRecordDecl *RD) {
- const ASTRecordLayout &BaseInfo = Ctx.getASTRecordLayout(RD);
-
- // If we have an empty base class, try to place it at offset 0.
- if (RD->isEmpty() && canPlaceRecordAtOffset(RD, 0)) {
- // We were able to place the class at offset 0.
- UpdateEmptyClassOffsets(RD, 0);
-
- Size = std::max(Size, BaseInfo.getSize());
-
- return 0;
- }
-
- unsigned BaseAlign = BaseInfo.getNonVirtualAlign();
-
- // Round up the current record size to the base's alignment boundary.
- uint64_t Offset = llvm::RoundUpToAlignment(DataSize, BaseAlign);
-
- // Try to place the base.
- while (true) {
- if (canPlaceRecordAtOffset(RD, Offset))
- break;
-
- Offset += BaseAlign;
- }
-
- if (!RD->isEmpty()) {
- // Update the data size.
- DataSize = Offset + BaseInfo.getNonVirtualSize();
-
- Size = std::max(Size, DataSize);
- } else
- Size = std::max(Size, Offset + BaseInfo.getSize());
-
- // Remember max struct/class alignment.
- UpdateAlignment(BaseAlign);
-
- UpdateEmptyClassOffsets(RD, Offset);
- return Offset;
-}
-
-void ASTRecordLayoutBuilder::LayoutBaseNonVirtually(const CXXRecordDecl *RD,
- bool IsVirtualBase) {
- // Layout the base.
- uint64_t Offset = LayoutBase(RD);
-
- // Add base class offsets.
- if (IsVirtualBase)
- VBases.push_back(std::make_pair(RD, Offset));
- else
- Bases.push_back(std::make_pair(RD, Offset));
-}
-
void ASTRecordLayoutBuilder::Layout(const RecordDecl *D) {
IsUnion = D->isUnion();
@@ -460,27 +487,17 @@ void ASTRecordLayoutBuilder::Layout(const RecordDecl *D) {
// If this is a C++ class, lay out the vtable and the non-virtual bases.
const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D);
- if (RD) {
- LayoutVtable(RD);
- // PrimaryBase goes first.
- if (PrimaryBase.getBase()) {
- if (PrimaryBase.isVirtual())
- IndirectPrimaryBases.insert(PrimaryBase.getBase());
- LayoutBaseNonVirtually(PrimaryBase.getBase(), PrimaryBase.isVirtual());
- }
+ if (RD)
LayoutNonVirtualBases(RD);
- }
LayoutFields(D);
NonVirtualSize = Size;
NonVirtualAlignment = Alignment;
- if (RD) {
- llvm::SmallSet<const CXXRecordDecl*, 32> mark;
- LayoutVirtualBases(RD, RD, PrimaryBase.getBase(),
- 0, mark, IndirectPrimaryBases);
- }
+ // If this is a C++ class, lay out its virtual bases.
+ if (RD)
+ LayoutVirtualBases(RD, 0, RD);
// Finally, round the size of the total struct up to the alignment of the
// struct itself.
@@ -697,10 +714,7 @@ ASTRecordLayoutBuilder::ComputeLayout(ASTContext &Ctx,
NonVirtualSize,
Builder.NonVirtualAlignment,
Builder.PrimaryBase,
- Builder.Bases.data(),
- Builder.Bases.size(),
- Builder.VBases.data(),
- Builder.VBases.size());
+ Builder.Bases, Builder.VBases);
}
const ASTRecordLayout *
diff --git a/lib/AST/RecordLayoutBuilder.h b/lib/AST/RecordLayoutBuilder.h
index d4171d3..a4bce75 100644
--- a/lib/AST/RecordLayoutBuilder.h
+++ b/lib/AST/RecordLayoutBuilder.h
@@ -56,21 +56,28 @@ class ASTRecordLayoutBuilder {
uint64_t NonVirtualSize;
unsigned NonVirtualAlignment;
+ /// PrimaryBase - the primary base class (if one exists) of the class
+ /// we're laying out.
ASTRecordLayout::PrimaryBaseInfo PrimaryBase;
- typedef llvm::SmallVector<std::pair<const CXXRecordDecl *,
- uint64_t>, 4> BaseOffsetsTy;
+ /// Bases - base classes and their offsets in the record.
+ ASTRecordLayout::BaseOffsetsMapTy Bases;
- /// Bases - base classes and their offsets from the record.
- BaseOffsetsTy Bases;
-
- // VBases - virtual base classes and their offsets from the record.
- BaseOffsetsTy VBases;
+ // VBases - virtual base classes and their offsets in the record.
+ ASTRecordLayout::BaseOffsetsMapTy VBases;
/// 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;
+ /// FirstNearlyEmptyVBase - The first nearly empty virtual base class in
+ /// inheritance graph order. Used for determining the primary base class.
+ const CXXRecordDecl *FirstNearlyEmptyVBase;
+
+ /// VisitedVirtualBases - A set of all the visited virtual bases, used to
+ /// avoid visiting virtual bases more than once.
+ llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBases;
+
/// EmptyClassOffsets - A map from offsets to empty record decls.
typedef std::multimap<uint64_t, const CXXRecordDecl *> EmptyClassOffsetsTy;
EmptyClassOffsetsTy EmptyClassOffsets;
@@ -86,33 +93,35 @@ class ASTRecordLayoutBuilder {
void LayoutField(const FieldDecl *D);
void LayoutBitField(const FieldDecl *D);
- void SelectPrimaryBase(const CXXRecordDecl *RD);
- void SelectPrimaryVBase(const CXXRecordDecl *RD,
- const CXXRecordDecl *&FirstPrimary);
+ /// DeterminePrimaryBase - Determine the primary base of the given class.
+ void DeterminePrimaryBase(const CXXRecordDecl *RD);
+
+ void SelectPrimaryVBase(const CXXRecordDecl *RD);
/// 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);
- void setPrimaryBase(const CXXRecordDecl *Base, bool IsVirtual) {
- PrimaryBase = ASTRecordLayout::PrimaryBaseInfo(Base, IsVirtual);
- }
-
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);
+
+ /// LayoutNonVirtualBase - Lays out a single non-virtual base.
+ void LayoutNonVirtualBase(const CXXRecordDecl *RD);
+
+ /// LayoutVirtualBases - Lays out all the virtual bases.
+ void LayoutVirtualBases(const CXXRecordDecl *RD, uint64_t Offset,
+ const CXXRecordDecl *MostDerivedClass);
+
+ /// LayoutVirtualBase - Lays out a single virtual base.
+ void LayoutVirtualBase(const CXXRecordDecl *RD);
+
/// LayoutBase - Will lay out a base and return the offset where it was
/// placed, in bits.
uint64_t LayoutBase(const CXXRecordDecl *RD);
-
- void LayoutVtable(const CXXRecordDecl *RD);
- void LayoutNonVirtualBases(const CXXRecordDecl *RD);
- void LayoutBaseNonVirtually(const CXXRecordDecl *RD, bool IsVBase);
- void LayoutVirtualBase(const CXXRecordDecl *RD);
- void LayoutVirtualBases(const CXXRecordDecl *Class, const CXXRecordDecl *RD,
- const CXXRecordDecl *PB, uint64_t Offset,
- llvm::SmallSet<const CXXRecordDecl*, 32> &mark,
- llvm::SmallSet<const CXXRecordDecl*, 32> &IndirectPrimary);
/// canPlaceRecordAtOffset - Return whether a record (either a base class
/// or a field) can be placed at the given offset.
@@ -134,9 +143,6 @@ class ASTRecordLayoutBuilder {
/// given offset.
void UpdateEmptyClassOffsets(const FieldDecl *FD, uint64_t Offset);
- /// getBaseOffset - Get the offset of a direct base class.
- uint64_t getBaseOffset(const CXXRecordDecl *Base);
-
/// FinishLayout - Finalize record layout. Adjust record size based on the
/// alignment.
void FinishLayout();
diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp
index 037bc14..09a6173 100644
--- a/lib/AST/TypePrinter.cpp
+++ b/lib/AST/TypePrinter.cpp
@@ -474,7 +474,12 @@ void TypePrinter::PrintEnum(const EnumType *T, std::string &S) {
void TypePrinter::PrintElaborated(const ElaboratedType *T, std::string &S) {
Print(T->getUnderlyingType(), S);
- S = std::string(T->getNameForTagKind(T->getTagKind())) + ' ' + S;
+
+ // We don't actually make these in C, but the language options
+ // sometimes lie to us -- for example, if someone calls
+ // QualType::getAsString(). Just suppress the redundant tag if so.
+ if (Policy.LangOpts.CPlusPlus)
+ S = std::string(T->getNameForTagKind(T->getTagKind())) + ' ' + S;
}
void TypePrinter::PrintTemplateTypeParm(const TemplateTypeParmType *T,
OpenPOWER on IntegriCloud