diff options
Diffstat (limited to 'lib/AST')
-rw-r--r-- | lib/AST/ASTContext.cpp | 70 | ||||
-rw-r--r-- | lib/AST/ASTImporter.cpp | 28 | ||||
-rw-r--r-- | lib/AST/CMakeLists.txt | 1 | ||||
-rw-r--r-- | lib/AST/Decl.cpp | 75 | ||||
-rw-r--r-- | lib/AST/DeclBase.cpp | 1 | ||||
-rw-r--r-- | lib/AST/DeclCXX.cpp | 256 | ||||
-rw-r--r-- | lib/AST/DeclFriend.cpp | 41 | ||||
-rw-r--r-- | lib/AST/DeclObjC.cpp | 104 | ||||
-rw-r--r-- | lib/AST/Expr.cpp | 10 | ||||
-rw-r--r-- | lib/AST/Makefile | 2 | ||||
-rw-r--r-- | lib/AST/RecordLayout.cpp | 37 | ||||
-rw-r--r-- | lib/AST/RecordLayoutBuilder.cpp | 400 | ||||
-rw-r--r-- | lib/AST/RecordLayoutBuilder.h | 58 | ||||
-rw-r--r-- | lib/AST/TypePrinter.cpp | 7 |
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, |