diff options
author | Douglas Gregor <dgregor@apple.com> | 2010-10-29 22:39:52 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2010-10-29 22:39:52 +0000 |
commit | 7c789c1a3f77f24032aa0bed2afacdb9e094e952 (patch) | |
tree | 7891cd4684de4f541f141dad60c9698590ead702 | |
parent | 110e8e56af30363072c140285961592b0107f789 (diff) |
Make the deserialization of C++ base class specifiers lazy, improving
the performance of C++ PCH and reducing stack depth in the reader.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@117732 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/AST/DeclCXX.h | 33 | ||||
-rw-r--r-- | include/clang/AST/ExternalASTSource.h | 10 | ||||
-rw-r--r-- | include/clang/Serialization/ASTBitCodes.h | 14 | ||||
-rw-r--r-- | include/clang/Serialization/ASTReader.h | 16 | ||||
-rw-r--r-- | include/clang/Serialization/ASTWriter.h | 39 | ||||
-rw-r--r-- | lib/AST/DeclCXX.cpp | 10 | ||||
-rw-r--r-- | lib/Serialization/ASTReader.cpp | 79 | ||||
-rw-r--r-- | lib/Serialization/ASTReaderDecl.cpp | 22 | ||||
-rw-r--r-- | lib/Serialization/ASTWriter.cpp | 77 | ||||
-rw-r--r-- | lib/Serialization/ASTWriterDecl.cpp | 6 | ||||
-rw-r--r-- | test/PCH/cxx-templates.cpp | 2 | ||||
-rw-r--r-- | test/PCH/cxx-templates.h | 5 |
12 files changed, 272 insertions, 41 deletions
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index f90d9868fa..8071daadd5 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -342,19 +342,19 @@ class CXXRecordDecl : public RecordDecl { /// \brief Whether we have already declared a destructor within the class. bool DeclaredDestructor : 1; - /// Bases - Base classes of this class. - /// FIXME: This is wasted space for a union. - CXXBaseSpecifier *Bases; - /// NumBases - The number of base class specifiers in Bases. unsigned NumBases; - - /// VBases - direct and indirect virtual base classes of this class. - CXXBaseSpecifier *VBases; - + /// NumVBases - The number of virtual base class specifiers in VBases. unsigned NumVBases; + /// Bases - Base classes of this class. + /// FIXME: This is wasted space for a union. + LazyCXXBaseSpecifiersPtr Bases; + + /// VBases - direct and indirect virtual base classes of this class. + LazyCXXBaseSpecifiersPtr VBases; + /// Conversions - Overload set containing the conversion functions /// of this C++ class (but not its inherited conversion /// functions). Each of the entries in this overload set is a @@ -376,6 +376,15 @@ class CXXRecordDecl : public RecordDecl { /// in reverse order. FriendDecl *FirstFriend; + /// \brief Retrieve the set of direct base classes. + CXXBaseSpecifier *getBases() const { + return Bases.get(Definition->getASTContext().getExternalSource()); + } + + /// \brief Retrieve the set of virtual base classes. + CXXBaseSpecifier *getVBases() const { + return VBases.get(Definition->getASTContext().getExternalSource()); + } } *DefinitionData; struct DefinitionData &data() { @@ -480,8 +489,8 @@ public: /// class. unsigned getNumBases() const { return data().NumBases; } - base_class_iterator bases_begin() { return data().Bases; } - base_class_const_iterator bases_begin() const { return data().Bases; } + base_class_iterator bases_begin() { return data().getBases(); } + base_class_const_iterator bases_begin() const { return data().getBases(); } base_class_iterator bases_end() { return bases_begin() + data().NumBases; } base_class_const_iterator bases_end() const { return bases_begin() + data().NumBases; @@ -503,8 +512,8 @@ public: /// class. unsigned getNumVBases() const { return data().NumVBases; } - base_class_iterator vbases_begin() { return data().VBases; } - base_class_const_iterator vbases_begin() const { return data().VBases; } + base_class_iterator vbases_begin() { return data().getVBases(); } + base_class_const_iterator vbases_begin() const { return data().getVBases(); } base_class_iterator vbases_end() { return vbases_begin() + data().NumVBases; } base_class_const_iterator vbases_end() const { return vbases_begin() + data().NumVBases; diff --git a/include/clang/AST/ExternalASTSource.h b/include/clang/AST/ExternalASTSource.h index b35096e072..39363787b4 100644 --- a/include/clang/AST/ExternalASTSource.h +++ b/include/clang/AST/ExternalASTSource.h @@ -25,6 +25,7 @@ template <class T> class SmallVectorImpl; namespace clang { class ASTConsumer; +class CXXBaseSpecifier; class Decl; class DeclContext; class DeclContextLookupResult; @@ -92,6 +93,10 @@ public: /// FunctionDecl::setLazyBody when building decls. virtual Stmt *GetExternalDeclStmt(uint64_t Offset) = 0; + /// \brief Resolve the offset of a set of C++ base specifiers in the decl + /// stream into an array of specifiers. + virtual CXXBaseSpecifier *GetExternalCXXBaseSpecifiers(uint64_t Offset) = 0; + /// \brief Finds all declarations with the given name in the /// given context. /// @@ -248,6 +253,11 @@ typedef LazyOffsetPtr<Stmt, uint64_t, &ExternalASTSource::GetExternalDeclStmt> typedef LazyOffsetPtr<Decl, uint32_t, &ExternalASTSource::GetExternalDecl> LazyDeclPtr; +/// \brief A lazy pointer to a set of CXXBaseSpecifiers. +typedef LazyOffsetPtr<CXXBaseSpecifier, uint64_t, + &ExternalASTSource::GetExternalCXXBaseSpecifiers> + LazyCXXBaseSpecifiersPtr; + } // end namespace clang #endif // LLVM_CLANG_AST_EXTERNAL_AST_SOURCE_H diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h index d8e04214b6..dbd4fa91e9 100644 --- a/include/clang/Serialization/ASTBitCodes.h +++ b/include/clang/Serialization/ASTBitCodes.h @@ -124,6 +124,10 @@ namespace clang { /// \brief An ID number that refers to an ObjC selctor in an AST file. typedef uint32_t SelectorID; + /// \brief An ID number that refers to a set of CXXBaseSpecifiers in an + /// AST file. + typedef uint32_t CXXBaseSpecifiersID; + /// \brief Describes the various kinds of blocks that occur within /// an AST file. enum BlockIDs { @@ -333,7 +337,11 @@ namespace clang { /// \brief Record of updates for a declaration that was modified after /// being deserialized. - DECL_UPDATES = 36 + DECL_UPDATES = 36, + + /// \brief Record code for the table of offsets to CXXBaseSpecifier + /// sets. + CXX_BASE_SPECIFIER_OFFSETS = 37 }; /// \brief Record types used within a source manager block. @@ -705,7 +713,9 @@ namespace clang { /// \brief A TemplateTemplateParmDecl record. DECL_TEMPLATE_TEMPLATE_PARM, /// \brief A StaticAssertDecl record. - DECL_STATIC_ASSERT + DECL_STATIC_ASSERT, + /// \brief A record containing CXXBaseSpecifiers. + DECL_CXX_BASE_SPECIFIERS }; /// \brief Record codes for each kind of statement or expression. diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h index 2217cc7eb8..e855cc7948 100644 --- a/include/clang/Serialization/ASTReader.h +++ b/include/clang/Serialization/ASTReader.h @@ -336,6 +336,13 @@ private: /// is the instantiation location. llvm::SmallVector<uint64_t, 64> PendingInstantiations; + /// \brief The number of C++ base specifier sets in this AST file. + unsigned LocalNumCXXBaseSpecifiers; + + /// \brief Offset of each C++ base specifier set within the bitstream, + /// indexed by the C++ base specifier set ID (-1). + const uint32_t *CXXBaseSpecifiersOffsets; + // === Types === /// \brief The number of types in this AST file. @@ -867,6 +874,9 @@ public: return static_cast<unsigned>(MacroDefinitionsLoaded.size()); } + /// \brief Returns the number of C++ base specifiers found in the chain. + unsigned getTotalNumCXXBaseSpecifiers() const; + /// \brief Reads a TemplateArgumentLocInfo appropriate for the /// given TemplateArgument kind. TemplateArgumentLocInfo @@ -904,6 +914,12 @@ public: Decl *GetDecl(serialization::DeclID ID); virtual Decl *GetExternalDecl(uint32_t ID); + /// \brief Resolve a CXXBaseSpecifiers ID into an offset into the chain + /// of loaded AST files. + uint64_t GetCXXBaseSpecifiersOffset(serialization::CXXBaseSpecifiersID ID); + + virtual CXXBaseSpecifier *GetExternalCXXBaseSpecifiers(uint64_t Offset); + /// \brief Resolve the offset of a statement into a statement. /// /// This operation will read a new statement from the external diff --git a/include/clang/Serialization/ASTWriter.h b/include/clang/Serialization/ASTWriter.h index 1d905ddfaa..5a3fd93d49 100644 --- a/include/clang/Serialization/ASTWriter.h +++ b/include/clang/Serialization/ASTWriter.h @@ -264,6 +264,35 @@ private: /// file. unsigned NumVisibleDeclContexts; + /// \brief The offset of each CXXBaseSpecifier set within the AST. + llvm::SmallVector<uint32_t, 4> CXXBaseSpecifiersOffsets; + + /// \brief The first ID number we can use for our own base specifiers. + serialization::CXXBaseSpecifiersID FirstCXXBaseSpecifiersID; + + /// \brief The base specifiers ID that will be assigned to the next new + /// set of C++ base specifiers. + serialization::CXXBaseSpecifiersID NextCXXBaseSpecifiersID; + + /// \brief A set of C++ base specifiers that is queued to be written into the + /// AST file. + struct QueuedCXXBaseSpecifiers { + QueuedCXXBaseSpecifiers() : ID(), Bases(), BasesEnd() { } + + QueuedCXXBaseSpecifiers(serialization::CXXBaseSpecifiersID ID, + CXXBaseSpecifier const *Bases, + CXXBaseSpecifier const *BasesEnd) + : ID(ID), Bases(Bases), BasesEnd(BasesEnd) { } + + serialization::CXXBaseSpecifiersID ID; + CXXBaseSpecifier const * Bases; + CXXBaseSpecifier const * BasesEnd; + }; + + /// \brief Queue of C++ base specifiers to be written to the AST file, + /// in the order they should be written. + llvm::SmallVector<QueuedCXXBaseSpecifiers, 2> CXXBaseSpecifiersToWrite; + /// \brief Write the given subexpression to the bitstream. void WriteSubStmt(Stmt *S); @@ -344,6 +373,11 @@ public: /// \brief Emit a CXXTemporary. void AddCXXTemporary(const CXXTemporary *Temp, RecordDataImpl &Record); + /// \brief Emit a set of C++ base specifiers to the record. + void AddCXXBaseSpecifiersRef(CXXBaseSpecifier const *Bases, + CXXBaseSpecifier const *BasesEnd, + RecordDataImpl &Record); + /// \brief Get the unique number used to refer to the given selector. serialization::SelectorID getSelectorRef(Selector Sel); @@ -394,6 +428,7 @@ public: /// \brief Emit a reference to a declaration. void AddDeclRef(const Decl *D, RecordDataImpl &Record); + /// \brief Force a declaration to be emitted and get its ID. serialization::DeclID GetDeclRef(const Decl *D); @@ -478,6 +513,10 @@ public: /// been added to the queue via AddStmt(). void FlushStmts(); + /// \brief Flush all of the C++ base specifier sets that have been added + /// via \c AddCXXBaseSpecifiersRef(). + void FlushCXXBaseSpecifiers(); + /// \brief Record an ID for the given switch-case statement. unsigned RecordSwitchCaseID(SwitchCase *S); diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 0e70053866..88ede82d92 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -36,7 +36,7 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D) HasTrivialDestructor(true), ComputedVisibleConversions(false), DeclaredDefaultConstructor(false), DeclaredCopyConstructor(false), DeclaredCopyAssignment(false), DeclaredDestructor(false), - Bases(0), NumBases(0), VBases(0), NumVBases(0), + NumBases(0), NumVBases(0), Bases(), VBases(), Definition(D), FirstFriend(0) { } @@ -77,8 +77,8 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, // no base classes [...]. data().Aggregate = false; - if (data().Bases) - C.Deallocate(data().Bases); + if (!data().Bases.isOffset() && data().NumBases > 0) + C.Deallocate(data().getBases()); // The set of seen virtual base types. llvm::SmallPtrSet<CanQualType, 8> SeenVBaseTypes; @@ -89,7 +89,7 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, data().Bases = new(C) CXXBaseSpecifier [NumBases]; data().NumBases = NumBases; for (unsigned i = 0; i < NumBases; ++i) { - data().Bases[i] = *Bases[i]; + data().getBases()[i] = *Bases[i]; // Keep track of inherited vbases for this base class. const CXXBaseSpecifier *Base = Bases[i]; QualType BaseType = Base->getType(); @@ -193,7 +193,7 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, CXXRecordDecl *VBaseClassDecl = cast<CXXRecordDecl>( VBaseTypeInfo->getType()->getAs<RecordType>()->getDecl()); - data().VBases[I] = + data().getVBases()[I] = CXXBaseSpecifier(VBaseClassDecl->getSourceRange(), true, VBaseClassDecl->getTagKind() == TTK_Class, VBases[I]->getAccessSpecifier(), VBaseTypeInfo); diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index 6497b78772..aa76765dc9 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -2069,6 +2069,17 @@ ASTReader::ReadASTBlock(PerFileData &F) { std::make_pair(&F, Record[I+1]); break; } + + case CXX_BASE_SPECIFIER_OFFSETS: { + if (F.LocalNumCXXBaseSpecifiers != 0) { + Error("duplicate CXX_BASE_SPECIFIER_OFFSETS record in AST file"); + return Failure; + } + + F.LocalNumCXXBaseSpecifiers = Record[0]; + F.CXXBaseSpecifiersOffsets = (const uint32_t *)BlobStart; + break; + } } First = false; } @@ -3207,6 +3218,14 @@ TypeIdx ASTReader::GetTypeIdx(QualType T) const { return I->second; } +unsigned ASTReader::getTotalNumCXXBaseSpecifiers() const { + unsigned Result = 0; + for (unsigned I = 0, N = Chain.size(); I != N; ++I) + Result += Chain[I]->LocalNumCXXBaseSpecifiers; + + return Result; +} + TemplateArgumentLocInfo ASTReader::GetTemplateArgumentLocInfo(PerFileData &F, TemplateArgument::ArgKind Kind, @@ -3249,6 +3268,63 @@ Decl *ASTReader::GetExternalDecl(uint32_t ID) { return GetDecl(ID); } +uint64_t +ASTReader::GetCXXBaseSpecifiersOffset(serialization::CXXBaseSpecifiersID ID) { + if (ID == 0) + return 0; + + --ID; + uint64_t Offset = 0; + for (unsigned I = 0, N = Chain.size(); I != N; ++I) { + if (ID < Chain[I]->LocalNumCXXBaseSpecifiers) + return Offset + Chain[I]->CXXBaseSpecifiersOffsets[ID]; + + ID -= Chain[I]->LocalNumCXXBaseSpecifiers; + Offset += Chain[I]->SizeInBits; + } + + assert(false && "CXXBaseSpecifiers not found"); + return 0; +} + +CXXBaseSpecifier *ASTReader::GetExternalCXXBaseSpecifiers(uint64_t Offset) { + // Figure out which AST file contains this offset. + PerFileData *F = 0; + for (unsigned I = 0, N = Chain.size(); I != N; ++I) { + if (Offset < Chain[I]->SizeInBits) { + F = Chain[I]; + break; + } + + Offset -= Chain[I]->SizeInBits; + } + + if (!F) { + Error("Malformed AST file: C++ base specifiers at impossible offset"); + return 0; + } + + llvm::BitstreamCursor &Cursor = F->DeclsCursor; + SavedStreamPosition SavedPosition(Cursor); + Cursor.JumpToBit(Offset); + ReadingKindTracker ReadingKind(Read_Decl, *this); + RecordData Record; + unsigned Code = Cursor.ReadCode(); + unsigned RecCode = Cursor.ReadRecord(Code, Record); + if (RecCode != DECL_CXX_BASE_SPECIFIERS) { + Error("Malformed AST file: missing C++ base specifiers"); + return 0; + } + + unsigned Idx = 0; + unsigned NumBases = Record[Idx++]; + void *Mem = Context->Allocate(sizeof(CXXBaseSpecifier) * NumBases); + CXXBaseSpecifier *Bases = new (Mem) CXXBaseSpecifier [NumBases]; + for (unsigned I = 0; I != NumBases; ++I) + Bases[I] = ReadCXXBaseSpecifier(*F, Record, Idx); + return Bases; +} + TranslationUnitDecl *ASTReader::GetTranslationUnitDecl() { if (!DeclsLoaded[0]) { ReadDeclRecord(0, 1); @@ -4411,7 +4487,8 @@ ASTReader::PerFileData::PerFileData(ASTFileType Ty) IdentifierLookupTable(0), LocalNumMacroDefinitions(0), MacroDefinitionOffsets(0), LocalNumSelectors(0), SelectorOffsets(0), SelectorLookupTableData(0), SelectorLookupTable(0), LocalNumDecls(0), - DeclOffsets(0), LocalNumTypes(0), TypeOffsets(0), StatCache(0), + DeclOffsets(0), LocalNumCXXBaseSpecifiers(0), CXXBaseSpecifiersOffsets(0), + LocalNumTypes(0), TypeOffsets(0), StatCache(0), NumPreallocatedPreprocessingEntities(0), NextInSource(0) {} diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index d63dce9f2b..c6cb8db439 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -773,8 +773,6 @@ void ASTDeclReader::VisitUnresolvedUsingTypenameDecl( void ASTDeclReader::ReadCXXDefinitionData( struct CXXRecordDecl::DefinitionData &Data, const RecordData &Record, unsigned &Idx) { - ASTContext &C = *Reader.getContext(); - Data.UserDeclaredConstructor = Record[Idx++]; Data.UserDeclaredCopyConstructor = Record[Idx++]; Data.UserDeclaredCopyAssignment = Record[Idx++]; @@ -793,20 +791,13 @@ void ASTDeclReader::ReadCXXDefinitionData( Data.DeclaredCopyConstructor = Record[Idx++]; Data.DeclaredCopyAssignment = Record[Idx++]; Data.DeclaredDestructor = Record[Idx++]; - - // setBases() is unsuitable since it may try to iterate the bases of an - // uninitialized base. Data.NumBases = Record[Idx++]; - Data.Bases = new(C) CXXBaseSpecifier [Data.NumBases]; - for (unsigned i = 0; i != Data.NumBases; ++i) - Data.Bases[i] = Reader.ReadCXXBaseSpecifier(F, Record, Idx); - - // FIXME: Make VBases lazily computed when needed to avoid storing them. + if (Data.NumBases) + Data.Bases = Reader.GetCXXBaseSpecifiersOffset(Record[Idx++]); Data.NumVBases = Record[Idx++]; - Data.VBases = new(C) CXXBaseSpecifier [Data.NumVBases]; - for (unsigned i = 0; i != Data.NumVBases; ++i) - Data.VBases[i] = Reader.ReadCXXBaseSpecifier(F, Record, Idx); - + if (Data.NumVBases) + Data.VBases = Reader.GetCXXBaseSpecifiersOffset(Record[Idx++]); + Reader.ReadUnresolvedSet(Data.Conversions, Record, Idx); Reader.ReadUnresolvedSet(Data.VisibleConversions, Record, Idx); assert(Data.Definition && "Data.Definition should be already set!"); @@ -1508,6 +1499,9 @@ Decl *ASTReader::ReadDeclRecord(unsigned Index, DeclID ID) { case DECL_BLOCK: D = BlockDecl::Create(*Context, 0, SourceLocation()); break; + case DECL_CXX_BASE_SPECIFIERS: + Error("attempt to read a C++ base-specifier record as a declaration"); + return 0; } assert(D && "Unknown declaration reading AST file"); diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index 114f9205d4..1fec22be4e 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -1725,7 +1725,7 @@ void ASTWriter::WriteSelectors(Sema &SemaRef) { // Create a blob abbreviation for the selector table offsets. Abbrev = new BitCodeAbbrev(); Abbrev->Add(BitCodeAbbrevOp(SELECTOR_OFFSETS)); - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // index + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // size Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); unsigned SelectorOffsetAbbrev = Stream.EmitAbbrev(Abbrev); @@ -2230,7 +2230,9 @@ ASTWriter::ASTWriter(llvm::BitstreamWriter &Stream) NextSelectorID(FirstSelectorID), FirstMacroID(1), NextMacroID(FirstMacroID), CollectedStmts(&StmtsToEmit), NumStatements(0), NumMacros(0), NumLexicalDeclContexts(0), - NumVisibleDeclContexts(0) { + NumVisibleDeclContexts(0), FirstCXXBaseSpecifiersID(1), + NextCXXBaseSpecifiersID(1) +{ } void ASTWriter::WriteAST(Sema &SemaRef, MemorizeStatCalls *StatCalls, @@ -2401,6 +2403,26 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls, WriteTypeDeclOffsets(); + // Write the C++ base-specifier set offsets. + if (!CXXBaseSpecifiersOffsets.empty()) { + // Create a blob abbreviation for the C++ base specifiers offsets. + using namespace llvm; + + BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); + Abbrev->Add(BitCodeAbbrevOp(CXX_BASE_SPECIFIER_OFFSETS)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // size + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); + unsigned BaseSpecifierOffsetAbbrev = Stream.EmitAbbrev(Abbrev); + + // Write the selector offsets table. + Record.clear(); + Record.push_back(CXX_BASE_SPECIFIER_OFFSETS); + Record.push_back(CXXBaseSpecifiersOffsets.size()); + Stream.EmitRecordWithBlob(BaseSpecifierOffsetAbbrev, Record, + (const char *)CXXBaseSpecifiersOffsets.data(), + CXXBaseSpecifiersOffsets.size() * sizeof(uint32_t)); + } + // Write the record containing external, unnamed definitions. if (!ExternalDefinitions.empty()) Stream.EmitRecord(EXTERNAL_DEFINITIONS, ExternalDefinitions); @@ -2798,6 +2820,16 @@ void ASTWriter::AddCXXTemporary(const CXXTemporary *Temp, RecordDataImpl &Record AddDeclRef(Temp->getDestructor(), Record); } +void ASTWriter::AddCXXBaseSpecifiersRef(CXXBaseSpecifier const *Bases, + CXXBaseSpecifier const *BasesEnd, + RecordDataImpl &Record) { + assert(Bases != BasesEnd && "Empty base-specifier sets are not recorded"); + CXXBaseSpecifiersToWrite.push_back( + QueuedCXXBaseSpecifiers(NextCXXBaseSpecifiersID, + Bases, BasesEnd)); + Record.push_back(NextCXXBaseSpecifiersID++); +} + void ASTWriter::AddTemplateArgumentLocInfo(TemplateArgument::ArgKind Kind, const TemplateArgumentLocInfo &Arg, RecordDataImpl &Record) { @@ -3155,6 +3187,32 @@ void ASTWriter::AddCXXBaseSpecifier(const CXXBaseSpecifier &Base, AddSourceRange(Base.getSourceRange(), Record); } +void ASTWriter::FlushCXXBaseSpecifiers() { + RecordData Record; + for (unsigned I = 0, N = CXXBaseSpecifiersToWrite.size(); I != N; ++I) { + Record.clear(); + + // Record the offset of this base-specifier set. + unsigned Index = CXXBaseSpecifiersToWrite[I].ID - FirstCXXBaseSpecifiersID; + if (Index == CXXBaseSpecifiersOffsets.size()) + CXXBaseSpecifiersOffsets.push_back(Stream.GetCurrentBitNo()); + else { + if (Index > CXXBaseSpecifiersOffsets.size()) + CXXBaseSpecifiersOffsets.resize(Index + 1); + CXXBaseSpecifiersOffsets[Index] = Stream.GetCurrentBitNo(); + } + + const CXXBaseSpecifier *B = CXXBaseSpecifiersToWrite[I].Bases, + *BEnd = CXXBaseSpecifiersToWrite[I].BasesEnd; + Record.push_back(BEnd - B); + for (; B != BEnd; ++B) + AddCXXBaseSpecifier(*B, Record); + Stream.EmitRecord(serialization::DECL_CXX_BASE_SPECIFIERS, Record); + } + + CXXBaseSpecifiersToWrite.clear(); +} + void ASTWriter::AddCXXBaseOrMemberInitializers( const CXXBaseOrMemberInitializer * const *BaseOrMembers, unsigned NumBaseOrMembers, RecordDataImpl &Record) { @@ -3208,13 +3266,15 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec Record.push_back(Data.DeclaredDestructor); Record.push_back(Data.NumBases); - for (unsigned i = 0; i != Data.NumBases; ++i) - AddCXXBaseSpecifier(Data.Bases[i], Record); - + if (Data.NumBases > 0) + AddCXXBaseSpecifiersRef(Data.getBases(), Data.getBases() + Data.NumBases, + Record); + // FIXME: Make VBases lazily computed when needed to avoid storing them. Record.push_back(Data.NumVBases); - for (unsigned i = 0; i != Data.NumVBases; ++i) - AddCXXBaseSpecifier(Data.VBases[i], Record); + if (Data.NumVBases > 0) + AddCXXBaseSpecifiersRef(Data.getVBases(), Data.getVBases() + Data.NumVBases, + Record); AddUnresolvedSet(Data.Conversions, Record); AddUnresolvedSet(Data.VisibleConversions, Record); @@ -3230,6 +3290,7 @@ void ASTWriter::ReaderInitialized(ASTReader *Reader) { FirstIdentID == NextIdentID && FirstSelectorID == NextSelectorID && FirstMacroID == NextMacroID && + FirstCXXBaseSpecifiersID == NextCXXBaseSpecifiersID && "Setting chain after writing has started."); Chain = Reader; @@ -3238,11 +3299,13 @@ void ASTWriter::ReaderInitialized(ASTReader *Reader) { FirstIdentID += Chain->getTotalNumIdentifiers(); FirstSelectorID += Chain->getTotalNumSelectors(); FirstMacroID += Chain->getTotalNumMacroDefinitions(); + FirstCXXBaseSpecifiersID += Chain->getTotalNumCXXBaseSpecifiers(); NextDeclID = FirstDeclID; NextTypeID = FirstTypeID; NextIdentID = FirstIdentID; NextSelectorID = FirstSelectorID; NextMacroID = FirstMacroID; + NextCXXBaseSpecifiersID = FirstCXXBaseSpecifiersID; } void ASTWriter::IdentifierRead(IdentID ID, IdentifierInfo *II) { diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp index 37c7765dc8..7d80f31856 100644 --- a/lib/Serialization/ASTWriterDecl.cpp +++ b/lib/Serialization/ASTWriterDecl.cpp @@ -1182,6 +1182,12 @@ void ASTWriter::WriteDecl(ASTContext &Context, Decl *D) { // Flush any expressions that were written as part of this declaration. FlushStmts(); + + // Flush C++ base specifiers, if there are any. + FlushCXXBaseSpecifiers(); + + // Flush any expressions that were written as part of the base specifiers. + FlushStmts(); // Note "external" declarations so that we can add them to a record in the // AST file later. diff --git a/test/PCH/cxx-templates.cpp b/test/PCH/cxx-templates.cpp index 95477992e6..56b8ab7399 100644 --- a/test/PCH/cxx-templates.cpp +++ b/test/PCH/cxx-templates.cpp @@ -37,3 +37,5 @@ void test(const int (&a6)[17]) { } template struct S4<int>; + +S7<int[5]> s7_5; diff --git a/test/PCH/cxx-templates.h b/test/PCH/cxx-templates.h index 5baa772b5d..ec8becbdc9 100644 --- a/test/PCH/cxx-templates.h +++ b/test/PCH/cxx-templates.h @@ -164,3 +164,8 @@ public: typedef t1& t2; }; +template<typename T> + struct S7; + +template<unsigned N> +struct S7<int[N]> : S6<const int[N]> { }; |