[cfe-commits] r117732 - in /cfe/trunk: include/clang/AST/DeclCXX.h include/clang/AST/ExternalASTSource.h include/clang/Serialization/ASTBitCodes.h include/clang/Serialization/ASTReader.h include/clang/Serialization/ASTWriter.h lib/AST/DeclCXX.cpp lib/Serialization/ASTReader.cpp lib/Serialization/ASTReaderDecl.cpp lib/Serialization/ASTWriter.cpp lib/Serialization/ASTWriterDecl.cpp test/PCH/cxx-templates.cpp test/PCH/cxx-templates.h

Douglas Gregor dgregor at apple.com
Fri Oct 29 15:39:52 PDT 2010


Author: dgregor
Date: Fri Oct 29 17:39:52 2010
New Revision: 117732

URL: http://llvm.org/viewvc/llvm-project?rev=117732&view=rev
Log:
Make the deserialization of C++ base class specifiers lazy, improving
the performance of C++ PCH and reducing stack depth in the reader.


Modified:
    cfe/trunk/include/clang/AST/DeclCXX.h
    cfe/trunk/include/clang/AST/ExternalASTSource.h
    cfe/trunk/include/clang/Serialization/ASTBitCodes.h
    cfe/trunk/include/clang/Serialization/ASTReader.h
    cfe/trunk/include/clang/Serialization/ASTWriter.h
    cfe/trunk/lib/AST/DeclCXX.cpp
    cfe/trunk/lib/Serialization/ASTReader.cpp
    cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
    cfe/trunk/lib/Serialization/ASTWriter.cpp
    cfe/trunk/lib/Serialization/ASTWriterDecl.cpp
    cfe/trunk/test/PCH/cxx-templates.cpp
    cfe/trunk/test/PCH/cxx-templates.h

Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=117732&r1=117731&r2=117732&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Fri Oct 29 17:39:52 2010
@@ -342,19 +342,19 @@
     /// \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 @@
     /// 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 @@
   /// 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 @@
   /// 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;

Modified: cfe/trunk/include/clang/AST/ExternalASTSource.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ExternalASTSource.h?rev=117732&r1=117731&r2=117732&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ExternalASTSource.h (original)
+++ cfe/trunk/include/clang/AST/ExternalASTSource.h Fri Oct 29 17:39:52 2010
@@ -25,6 +25,7 @@
 namespace clang {
 
 class ASTConsumer;
+class CXXBaseSpecifier;
 class Decl;
 class DeclContext;
 class DeclContextLookupResult;
@@ -92,6 +93,10 @@
   /// 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<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

Modified: cfe/trunk/include/clang/Serialization/ASTBitCodes.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTBitCodes.h?rev=117732&r1=117731&r2=117732&view=diff
==============================================================================
--- cfe/trunk/include/clang/Serialization/ASTBitCodes.h (original)
+++ cfe/trunk/include/clang/Serialization/ASTBitCodes.h Fri Oct 29 17:39:52 2010
@@ -124,6 +124,10 @@
     /// \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 @@
 
       /// \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 @@
       /// \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.

Modified: cfe/trunk/include/clang/Serialization/ASTReader.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTReader.h?rev=117732&r1=117731&r2=117732&view=diff
==============================================================================
--- cfe/trunk/include/clang/Serialization/ASTReader.h (original)
+++ cfe/trunk/include/clang/Serialization/ASTReader.h Fri Oct 29 17:39:52 2010
@@ -336,6 +336,13 @@
     /// 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 @@
     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 @@
   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

Modified: cfe/trunk/include/clang/Serialization/ASTWriter.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTWriter.h?rev=117732&r1=117731&r2=117732&view=diff
==============================================================================
--- cfe/trunk/include/clang/Serialization/ASTWriter.h (original)
+++ cfe/trunk/include/clang/Serialization/ASTWriter.h Fri Oct 29 17:39:52 2010
@@ -264,6 +264,35 @@
   /// 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 @@
   /// \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 @@
   /// \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 @@
   /// 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);
 

Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=117732&r1=117731&r2=117732&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Fri Oct 29 17:39:52 2010
@@ -36,7 +36,7 @@
     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 @@
   //   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 @@
   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 *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);

Modified: cfe/trunk/lib/Serialization/ASTReader.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReader.cpp?rev=117732&r1=117731&r2=117732&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReader.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReader.cpp Fri Oct 29 17:39:52 2010
@@ -2069,6 +2069,17 @@
             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 @@
   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 @@
   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 @@
     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)
 {}
 

Modified: cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderDecl.cpp?rev=117732&r1=117731&r2=117732&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp Fri Oct 29 17:39:52 2010
@@ -773,8 +773,6 @@
 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 @@
   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 @@
   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");

Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=117732&r1=117731&r2=117732&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriter.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriter.cpp Fri Oct 29 17:39:52 2010
@@ -1725,7 +1725,7 @@
     // 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 @@
     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 @@
 
   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 @@
   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 @@
   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 @@
   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 @@
          FirstIdentID == NextIdentID &&
          FirstSelectorID == NextSelectorID &&
          FirstMacroID == NextMacroID &&
+         FirstCXXBaseSpecifiersID == NextCXXBaseSpecifiersID &&
          "Setting chain after writing has started.");
   Chain = Reader;
 
@@ -3238,11 +3299,13 @@
   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) {

Modified: cfe/trunk/lib/Serialization/ASTWriterDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterDecl.cpp?rev=117732&r1=117731&r2=117732&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriterDecl.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriterDecl.cpp Fri Oct 29 17:39:52 2010
@@ -1182,6 +1182,12 @@
 
   // 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.

Modified: cfe/trunk/test/PCH/cxx-templates.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/cxx-templates.cpp?rev=117732&r1=117731&r2=117732&view=diff
==============================================================================
--- cfe/trunk/test/PCH/cxx-templates.cpp (original)
+++ cfe/trunk/test/PCH/cxx-templates.cpp Fri Oct 29 17:39:52 2010
@@ -37,3 +37,5 @@
 }
 
 template struct S4<int>;
+
+S7<int[5]> s7_5;

Modified: cfe/trunk/test/PCH/cxx-templates.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/cxx-templates.h?rev=117732&r1=117731&r2=117732&view=diff
==============================================================================
--- cfe/trunk/test/PCH/cxx-templates.h (original)
+++ cfe/trunk/test/PCH/cxx-templates.h Fri Oct 29 17:39:52 2010
@@ -164,3 +164,8 @@
    typedef t1& t2;
 };
 
+template<typename T>
+  struct S7;
+
+template<unsigned N>
+struct S7<int[N]> : S6<const int[N]> { };





More information about the cfe-commits mailing list