From: Douglas Gregor Date: Thu, 28 Jul 2011 19:11:31 +0000 (+0000) Subject: Lazily deserialize Sema::VTableUses. Plus, fix the utterly and X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=dfe6543e12eca5c79421378b7fa6b3e8fc403e63;p=clang Lazily deserialize Sema::VTableUses. Plus, fix the utterly and completely broken deserialization mapping code we had for VTableUses, which would have broken horribly as soon as our local-to-global ID mapping became interesting. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@136371 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Sema/ExternalSemaSource.h b/include/clang/Sema/ExternalSemaSource.h index 41bc4e3536..00494641ba 100644 --- a/include/clang/Sema/ExternalSemaSource.h +++ b/include/clang/Sema/ExternalSemaSource.h @@ -29,6 +29,14 @@ class Sema; class TypedefNameDecl; class VarDecl; +/// \brief A simple structure that captures a vtable use for the purposes of +/// the \c ExternalSemaSource. +struct ExternalVTableUse { + CXXRecordDecl *Record; + SourceLocation Location; + bool DefinitionRequired; +}; + /// \brief An abstract interface that should be implemented by /// external AST sources that also provide information for semantic /// analysis. @@ -147,6 +155,13 @@ public: virtual void ReadWeakUndeclaredIdentifiers( SmallVectorImpl > &WI) {} + /// \brief Read the set of used vtables known to the external Sema source. + /// + /// The external source should append its own used vtables to the given + /// vector. Note that this routine may be invoked multiple times; the external + /// source should take care not to introduce the same vtables repeatedly. + virtual void ReadUsedVTables(SmallVectorImpl &VTables) {} + // isa/cast/dyn_cast support static bool classof(const ExternalASTSource *Source) { return Source->SemaSource; diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index adc6e2ba6d..81d93115e3 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -3365,6 +3365,9 @@ public: /// by code generation). llvm::DenseMap VTablesUsed; + /// \brief Load any externally-stored vtable uses. + void LoadExternalVTableUses(); + typedef LazyVector DynamicClassesType; diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h index 8bb11cc575..f3bdcc8c2f 100644 --- a/include/clang/Serialization/ASTReader.h +++ b/include/clang/Serialization/ASTReader.h @@ -1404,6 +1404,8 @@ public: virtual void ReadWeakUndeclaredIdentifiers( SmallVectorImpl > &WI); + virtual void ReadUsedVTables(SmallVectorImpl &VTables); + /// \brief Load a selector from disk, registering its ID if it exists. void LoadSelector(Selector Sel); diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index ba00944156..5d81205137 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -8935,6 +8935,30 @@ DeclResult Sema::ActOnCXXConditionDeclaration(Scope *S, Declarator &D) { return Dcl; } +void Sema::LoadExternalVTableUses() { + if (!ExternalSource) + return; + + SmallVector VTables; + ExternalSource->ReadUsedVTables(VTables); + SmallVector NewUses; + for (unsigned I = 0, N = VTables.size(); I != N; ++I) { + llvm::DenseMap::iterator Pos + = VTablesUsed.find(VTables[I].Record); + // Even if a definition wasn't required before, it may be required now. + if (Pos != VTablesUsed.end()) { + if (!Pos->second && VTables[I].DefinitionRequired) + Pos->second = true; + continue; + } + + VTablesUsed[VTables[I].Record] = VTables[I].DefinitionRequired; + NewUses.push_back(VTableUse(VTables[I].Record, VTables[I].Location)); + } + + VTableUses.insert(VTableUses.begin(), NewUses.begin(), NewUses.end()); +} + void Sema::MarkVTableUsed(SourceLocation Loc, CXXRecordDecl *Class, bool DefinitionRequired) { // Ignore any vtable uses in unevaluated operands or for classes that do @@ -8945,6 +8969,7 @@ void Sema::MarkVTableUsed(SourceLocation Loc, CXXRecordDecl *Class, return; // Try to insert this class into the map. + LoadExternalVTableUses(); Class = cast(Class->getCanonicalDecl()); std::pair::iterator, bool> Pos = VTablesUsed.insert(std::make_pair(Class, DefinitionRequired)); @@ -8970,6 +8995,7 @@ void Sema::MarkVTableUsed(SourceLocation Loc, CXXRecordDecl *Class, } bool Sema::DefineUsedVTables() { + LoadExternalVTableUses(); if (VTableUses.empty()) return false; diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index ff87c23897..288e50df74 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -2310,11 +2310,22 @@ ASTReader::ReadASTBlock(Module &F) { break; case VTABLE_USES: + if (Record.size() % 3 != 0) { + Error("Invalid VTABLE_USES record"); + return Failure; + } + // Later tables overwrite earlier ones. - // FIXME: Modules will have some trouble with this. + // FIXME: Modules will have some trouble with this. This is clearly not + // the right way to do this. VTableUses.clear(); - for (unsigned I = 0, N = Record.size(); I != N; ++I) - VTableUses.push_back(getGlobalDeclID(F, Record[I])); + + for (unsigned Idx = 0, N = Record.size(); Idx != N; /* In loop */) { + VTableUses.push_back(getGlobalDeclID(F, Record[Idx++])); + VTableUses.push_back( + ReadSourceLocation(F, Record, Idx).getRawEncoding()); + VTableUses.push_back(Record[Idx++]); + } break; case DYNAMIC_CLASSES: @@ -4397,19 +4408,6 @@ void ASTReader::InitializeSema(Sema &S) { SemaObj->PendingInstantiations.push_back(std::make_pair(D, Loc)); } - // If there were any VTable uses, deserialize the information and add it - // to Sema's vector and map of VTable uses. - if (!VTableUses.empty()) { - unsigned Idx = 0; - for (unsigned I = 0, N = VTableUses[Idx++]; I != N; ++I) { - CXXRecordDecl *Class = cast(GetDecl(VTableUses[Idx++])); - SourceLocation Loc = ReadSourceLocation(F, VTableUses, Idx); - bool DefinitionRequired = VTableUses[Idx++]; - SemaObj->VTableUses.push_back(std::make_pair(Class, Loc)); - SemaObj->VTablesUsed[Class] = DefinitionRequired; - } - } - if (!FPPragmaOptions.empty()) { assert(FPPragmaOptions.size() == 1 && "Wrong number of FP_PRAGMA_OPTIONS"); SemaObj->FPFeatures.fp_contract = FPPragmaOptions[0]; @@ -4644,6 +4642,18 @@ void ASTReader::ReadWeakUndeclaredIdentifiers( WeakUndeclaredIdentifiers.clear(); } +void ASTReader::ReadUsedVTables(SmallVectorImpl &VTables) { + for (unsigned Idx = 0, N = VTableUses.size(); Idx < N; /* In loop */) { + ExternalVTableUse VT; + VT.Record = dyn_cast_or_null(GetDecl(VTableUses[Idx++])); + VT.Location = SourceLocation::getFromRawEncoding(VTableUses[Idx++]); + VT.DefinitionRequired = VTableUses[Idx++]; + VTables.push_back(VT); + } + + VTableUses.clear(); +} + void ASTReader::LoadSelector(Selector Sel) { // It would be complicated to avoid reading the methods anyway. So don't. ReadMethodPool(Sel); diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index fb29f6970f..e506bba8a2 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -2886,7 +2886,6 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls, // Build a record containing all of the VTable uses information. RecordData VTableUses; if (!SemaRef.VTableUses.empty()) { - VTableUses.push_back(SemaRef.VTableUses.size()); for (unsigned I = 0, N = SemaRef.VTableUses.size(); I != N; ++I) { AddDeclRef(SemaRef.VTableUses[I].first, VTableUses); AddSourceLocation(SemaRef.VTableUses[I].second, VTableUses); @@ -3153,7 +3152,6 @@ void ASTWriter::WriteASTChain(Sema &SemaRef, MemorizeStatCalls *StatCalls, // a use is new to this part. RecordData VTableUses; if (!SemaRef.VTableUses.empty()) { - VTableUses.push_back(SemaRef.VTableUses.size()); for (unsigned I = 0, N = SemaRef.VTableUses.size(); I != N; ++I) { AddDeclRef(SemaRef.VTableUses[I].first, VTableUses); AddSourceLocation(SemaRef.VTableUses[I].second, VTableUses);