]> granicus.if.org Git - clang/commitdiff
Apart from storing/retrieving the previous redeclaration from PCH, also store/retriev...
authorArgyrios Kyrtzidis <akyrtzi@gmail.com>
Tue, 3 Aug 2010 17:30:10 +0000 (17:30 +0000)
committerArgyrios Kyrtzidis <akyrtzi@gmail.com>
Tue, 3 Aug 2010 17:30:10 +0000 (17:30 +0000)
redeclaration. That way we are sure that the full redeclarations chain is loaded.

When using chained PCHs, first declarations point to the most recent redeclarations in the same PCH.
To address this use a REDECLS_UPDATE_LATEST record block to keep track of which first declarations need
to point to a most recent redeclaration in another PCH.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@110125 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/Redeclarable.h
include/clang/Frontend/PCHBitCodes.h
include/clang/Frontend/PCHReader.h
include/clang/Frontend/PCHWriter.h
lib/Frontend/PCHReader.cpp
lib/Frontend/PCHReaderDecl.cpp
lib/Frontend/PCHWriter.cpp
lib/Frontend/PCHWriterDecl.cpp
test/PCH/cxx-templates.cpp
test/PCH/cxx-templates.h

index 55e1f8477992c5194be8abbea70451dbc8cd50cd..85c75b771b65d5d07e5429242c912342e531a755 100644 (file)
@@ -177,6 +177,9 @@ public:
                                           static_cast<const decl_type*>(this)));
   }
   redecl_iterator redecls_end() const { return redecl_iterator(); }
+
+  friend class PCHDeclReader;
+  friend class PCHDeclWriter;
 };
 
 }
index 109a78bd8849e822117b5e5fc2ac0713dceee0f8..a07060f8001fd19f7510b3287fc87a72e5ed5dff 100644 (file)
@@ -245,8 +245,12 @@ namespace clang {
       /// declarations.
       TU_UPDATE_LEXICAL = 28,
 
+      /// \brief Record code for an update to first decls pointing to the
+      /// latest redeclarations.
+      REDECLS_UPDATE_LATEST = 29,
+
       /// \brief Record code for declarations that Sema keeps references of.
-      SEMA_DECL_REFS = 29
+      SEMA_DECL_REFS = 30
     };
 
     /// \brief Record types used within a source manager block.
index dda15670b5e95545ab4a886124ec9d99653cd81f..e19669ec7f40fd68114a2771e97aec8426ca2fab 100644 (file)
@@ -319,6 +319,11 @@ private:
   /// DeclContext.
   DeclContextOffsetsMap DeclContextOffsets;
 
+  typedef llvm::DenseMap<pch::DeclID, pch::DeclID> FirstLatestDeclIDMap;
+  /// \brief Map of first declarations from a chained PCH that point to the
+  /// most recent declarations in another PCH.
+  FirstLatestDeclIDMap FirstLatestDeclIDs;
+
   /// \brief Read the records that describe the contents of declcontexts.
   bool ReadDeclContextStorage(llvm::BitstreamCursor &Cursor,
                               const std::pair<uint64_t, uint64_t> &Offsets,
@@ -561,7 +566,7 @@ private:
   QualType ReadTypeRecord(unsigned Index);
   RecordLocation TypeCursorForIndex(unsigned Index);
   void LoadedDecl(unsigned Index, Decl *D);
-  Decl *ReadDeclRecord(unsigned Index);
+  Decl *ReadDeclRecord(unsigned Index, pch::DeclID ID);
   RecordLocation DeclCursorForIndex(unsigned Index);
 
   void PassInterestingDeclsToConsumer();
index 92c7085bc6fccce237d02a5630fccc74e69f7192..3403c6e2d177ba62b8f5aa0eb005f14b8cad8250 100644 (file)
@@ -79,6 +79,7 @@ class PCHWriter : public PCHDeserializationListener {
 public:
   typedef llvm::SmallVector<uint64_t, 64> RecordData;
 
+  friend class PCHDeclWriter;
 private:
   /// \brief The bitstream writer used to emit this precompiled header.
   llvm::BitstreamWriter &Stream;
@@ -195,6 +196,11 @@ private:
   /// \brief Mapping from the macro definition indices in \c MacroDefinitions
   /// to the corresponding offsets within the preprocessor block.
   std::vector<uint32_t> MacroDefinitionOffsets;
+
+  typedef llvm::DenseMap<Decl *, Decl *> FirstLatestDeclMap;
+  /// \brief Map of first declarations from a chained PCH that point to the
+  /// most recent declarations in another PCH.
+  FirstLatestDeclMap FirstLatestDecls;
   
   /// \brief Declarations encountered that might be external
   /// definitions.
index b415f8dea540febf7ac794c0c740461f30c3e1e8..35909a05556605cd71928a529690bdba9ed0cb79 100644 (file)
@@ -1557,6 +1557,18 @@ PCHReader::ReadPCHBlock(PerFileData &F) {
       break;
     }
 
+    case pch::REDECLS_UPDATE_LATEST: {
+      assert(Record.size() % 2 == 0 && "Expected pairs of DeclIDs");
+      for (unsigned i = 0, e = Record.size(); i < e; i += 2) {
+        pch::DeclID First = Record[i], Latest = Record[i+1];
+        assert((FirstLatestDeclIDs.find(First) == FirstLatestDeclIDs.end() ||
+                Latest > FirstLatestDeclIDs[First]) &&
+               "The new latest is supposed to come after the previous latest");
+        FirstLatestDeclIDs[First] = Latest;
+      }
+      break;
+    }
+
     case pch::LANGUAGE_OPTIONS:
       if (ParseLanguageOptions(Record) && !DisableValidation)
         return IgnorePCH;
@@ -2868,7 +2880,7 @@ Decl *PCHReader::GetExternalDecl(uint32_t ID) {
 
 TranslationUnitDecl *PCHReader::GetTranslationUnitDecl() {
   if (!DeclsLoaded[0]) {
-    ReadDeclRecord(0);
+    ReadDeclRecord(0, 0);
     if (DeserializationListener)
       DeserializationListener->DeclRead(1, DeclsLoaded[0]);
   }
@@ -2887,7 +2899,7 @@ Decl *PCHReader::GetDecl(pch::DeclID ID) {
 
   unsigned Index = ID - 1;
   if (!DeclsLoaded[Index]) {
-    ReadDeclRecord(Index);
+    ReadDeclRecord(Index, ID);
     if (DeserializationListener)
       DeserializationListener->DeclRead(ID, DeclsLoaded[Index]);
   }
index e9428cc0b4bd8d68f8349c371090b39bc0928c27..21beb42e93e5c653b2fe93a5c52f4add92137356 100644 (file)
@@ -31,6 +31,7 @@ namespace clang {
   class PCHDeclReader : public DeclVisitor<PCHDeclReader, void> {
     PCHReader &Reader;
     llvm::BitstreamCursor &Cursor;
+    const pch::DeclID ThisDeclID;
     const PCHReader::RecordData &Record;
     unsigned &Idx;
     pch::TypeID TypeIDForTypeDecl;
@@ -39,9 +40,10 @@ namespace clang {
 
   public:
     PCHDeclReader(PCHReader &Reader, llvm::BitstreamCursor &Cursor,
-                  const PCHReader::RecordData &Record, unsigned &Idx)
-      : Reader(Reader), Cursor(Cursor), Record(Record), Idx(Idx),
-        TypeIDForTypeDecl(0) { }
+                  pch::DeclID thisDeclID, const PCHReader::RecordData &Record,
+                  unsigned &Idx)
+      : Reader(Reader), Cursor(Cursor), ThisDeclID(thisDeclID), Record(Record),
+        Idx(Idx), TypeIDForTypeDecl(0) { }
 
     void Visit(Decl *D);
 
@@ -93,6 +95,7 @@ namespace clang {
     void VisitBlockDecl(BlockDecl *BD);
 
     std::pair<uint64_t, uint64_t> VisitDeclContext(DeclContext *DC);
+    template <typename T> void VisitRedeclarable(Redeclarable<T> *D);
 
     // FIXME: Reorder according to DeclNodes.td?
     void VisitObjCMethodDecl(ObjCMethodDecl *D);
@@ -178,8 +181,7 @@ void PCHDeclReader::VisitTypedefDecl(TypedefDecl *TD) {
 void PCHDeclReader::VisitTagDecl(TagDecl *TD) {
   VisitTypeDecl(TD);
   TD->IdentifierNamespace = Record[Idx++];
-  TD->setPreviousDeclaration(
-                        cast_or_null<TagDecl>(Reader.GetDecl(Record[Idx++])));
+  VisitRedeclarable(TD);
   TD->setTagKind((TagDecl::TagKind)Record[Idx++]);
   TD->setDefinition(Record[Idx++]);
   TD->setEmbeddedInDeclarator(Record[Idx++]);
@@ -305,10 +307,7 @@ void PCHDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
   // FunctionDecl's body is handled last at PCHReaderDecl::Visit,
   // after everything else is read.
 
-  // Avoid side effects and invariant checking of FunctionDecl's
-  // setPreviousDeclaration.
-  FD->redeclarable_base::setPreviousDeclaration(
-                   cast_or_null<FunctionDecl>(Reader.GetDecl(Record[Idx++])));
+  VisitRedeclarable(FD);
   FD->setStorageClass((FunctionDecl::StorageClass)Record[Idx++]);
   FD->setStorageClassAsWritten((FunctionDecl::StorageClass)Record[Idx++]);
   FD->setInlineSpecified(Record[Idx++]);
@@ -550,8 +549,7 @@ void PCHDeclReader::VisitVarDecl(VarDecl *VD) {
   VD->setDeclaredInCondition(Record[Idx++]);
   VD->setExceptionVariable(Record[Idx++]);
   VD->setNRVOVariable(Record[Idx++]);
-  VD->setPreviousDeclaration(
-                         cast_or_null<VarDecl>(Reader.GetDecl(Record[Idx++])));
+  VisitRedeclarable(VD);
   if (Record[Idx++])
     VD->setInit(Reader.ReadExpr(Cursor));
 
@@ -918,6 +916,25 @@ void PCHDeclReader::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {
 
     RedeclarableTemplateDecl *LatestDecl = 
         cast_or_null<RedeclarableTemplateDecl>(Reader.GetDecl(Record[Idx++]));
+  
+    // This decl is a first one and the latest declaration that it points to is
+    // in the same PCH. However, if this actually needs to point to a
+    // redeclaration in another chained PCH, we need to update it by checking
+    // the FirstLatestDeclIDs map which tracks this kind of decls.
+    assert(Reader.GetDecl(ThisDeclID) == D && "Invalid ThisDeclID ?");
+    PCHReader::FirstLatestDeclIDMap::iterator I
+        = Reader.FirstLatestDeclIDs.find(ThisDeclID);
+    if (I != Reader.FirstLatestDeclIDs.end()) {
+      Decl *NewLatest = Reader.GetDecl(I->second);
+      assert((LatestDecl->getLocation().isInvalid() ||
+              NewLatest->getLocation().isInvalid()  ||
+              Reader.SourceMgr.isBeforeInTranslationUnit(
+                                                   LatestDecl->getLocation(),
+                                                   NewLatest->getLocation())) &&
+             "The new latest is supposed to come after the previous latest");
+      LatestDecl = cast<RedeclarableTemplateDecl>(NewLatest);
+    }
+
     assert(LatestDecl->getKind() == D->getKind() && "Latest kind mismatch");
     D->getCommonPtr()->Latest = LatestDecl;
   }
@@ -1072,6 +1089,54 @@ PCHDeclReader::VisitDeclContext(DeclContext *DC) {
   return std::make_pair(LexicalOffset, VisibleOffset);
 }
 
+template <typename T>
+void PCHDeclReader::VisitRedeclarable(Redeclarable<T> *D) {
+  enum RedeclKind { NoRedeclaration = 0, PointsToPrevious, PointsToLatest };
+  RedeclKind Kind = (RedeclKind)Record[Idx++];
+  switch (Kind) {
+  default:
+    assert(0 && "Out of sync with PCHDeclWriter::VisitRedeclarable or messed up"
+                " reading");
+  case NoRedeclaration:
+    break;
+  case PointsToPrevious:
+    D->RedeclLink = typename Redeclarable<T>::PreviousDeclLink(
+                                cast_or_null<T>(Reader.GetDecl(Record[Idx++])));
+    break;
+  case PointsToLatest:
+    D->RedeclLink = typename Redeclarable<T>::LatestDeclLink(
+                                cast_or_null<T>(Reader.GetDecl(Record[Idx++])));
+    break;
+  }
+
+  assert(!(Kind == PointsToPrevious &&
+           Reader.FirstLatestDeclIDs.find(ThisDeclID) !=
+               Reader.FirstLatestDeclIDs.end()) &&
+         "This decl is not first, it should not be in the map");
+  if (Kind == PointsToPrevious)
+    return;
+
+  // This decl is a first one and the latest declaration that it points to is in
+  // the same PCH. However, if this actually needs to point to a redeclaration
+  // in another chained PCH, we need to update it by checking the
+  // FirstLatestDeclIDs map which tracks this kind of decls.
+  assert(Reader.GetDecl(ThisDeclID) == static_cast<T*>(D) &&
+         "Invalid ThisDeclID ?");
+  PCHReader::FirstLatestDeclIDMap::iterator I
+      = Reader.FirstLatestDeclIDs.find(ThisDeclID);
+  if (I != Reader.FirstLatestDeclIDs.end()) {
+    Decl *NewLatest = Reader.GetDecl(I->second);
+    assert((D->getMostRecentDeclaration()->getLocation().isInvalid() ||
+            NewLatest->getLocation().isInvalid() ||
+            Reader.SourceMgr.isBeforeInTranslationUnit(
+                                   D->getMostRecentDeclaration()->getLocation(),
+                                   NewLatest->getLocation())) &&
+           "The new latest is supposed to come after the previous latest");
+    D->RedeclLink
+        = typename Redeclarable<T>::LatestDeclLink(cast_or_null<T>(NewLatest));
+  }
+}
+
 //===----------------------------------------------------------------------===//
 // Attribute Reading
 //===----------------------------------------------------------------------===//
@@ -1304,7 +1369,7 @@ PCHReader::RecordLocation PCHReader::DeclCursorForIndex(unsigned Index) {
 }
 
 /// \brief Read the declaration at the given offset from the PCH file.
-Decl *PCHReader::ReadDeclRecord(unsigned Index) {
+Decl *PCHReader::ReadDeclRecord(unsigned Index, pch::DeclID ID) {
   RecordLocation Loc = DeclCursorForIndex(Index);
   llvm::BitstreamCursor &DeclsCursor = *Loc.first;
   // Keep track of where we are in the stream, then jump back there
@@ -1320,7 +1385,7 @@ Decl *PCHReader::ReadDeclRecord(unsigned Index) {
   RecordData Record;
   unsigned Code = DeclsCursor.ReadCode();
   unsigned Idx = 0;
-  PCHDeclReader Reader(*this, DeclsCursor, Record, Idx);
+  PCHDeclReader Reader(*this, DeclsCursor, ID, Record, Idx);
 
   Decl *D = 0;
   switch ((pch::DeclCode)DeclsCursor.ReadRecord(Code, Record)) {
index 75592a41c858f94d6b57fccc1b5b39c246186cc1..776a40940d7619f729b73b667bdb1ab4be8e5a59 100644 (file)
@@ -2410,6 +2410,19 @@ void PCHWriter::WritePCHChain(Sema &SemaRef, MemorizeStatCalls *StatCalls,
   WriteIdentifierTable(PP);
   WriteTypeDeclOffsets();
 
+  /// Build a record containing first declarations from a chained PCH and the
+  /// most recent declarations in this PCH that they point to.
+  RecordData FirstLatestDeclIDs;
+  for (FirstLatestDeclMap::iterator
+        I = FirstLatestDecls.begin(), E = FirstLatestDecls.end(); I != E; ++I) {
+    assert(I->first->getPCHLevel() > I->second->getPCHLevel() &&
+           "Expected first & second to be in different PCHs");
+    AddDeclRef(I->first, FirstLatestDeclIDs);
+    AddDeclRef(I->second, FirstLatestDeclIDs);
+  }
+  if (!FirstLatestDeclIDs.empty())
+    Stream.EmitRecord(pch::REDECLS_UPDATE_LATEST, FirstLatestDeclIDs);
+
   // Write the record containing external, unnamed definitions.
   if (!ExternalDefinitions.empty())
     Stream.EmitRecord(pch::EXTERNAL_DEFINITIONS, ExternalDefinitions);
index 28a82cd23f5b7a2ec51c8926a9185d85752113bb..9e9835adb424551813b42edcd5d22985a98ceee4 100644 (file)
@@ -92,6 +92,7 @@ namespace clang {
 
     void VisitDeclContext(DeclContext *DC, uint64_t LexicalOffset,
                           uint64_t VisibleOffset);
+    template <typename T> void VisitRedeclarable(Redeclarable<T> *D);
 
 
     // FIXME: Put in the same order is DeclNodes.td?
@@ -163,7 +164,7 @@ void PCHDeclWriter::VisitTypedefDecl(TypedefDecl *D) {
 void PCHDeclWriter::VisitTagDecl(TagDecl *D) {
   VisitTypeDecl(D);
   Record.push_back(D->getIdentifierNamespace());
-  Writer.AddDeclRef(D->getPreviousDeclaration(), Record);
+  VisitRedeclarable(D);
   Record.push_back((unsigned)D->getTagKind()); // FIXME: stable encoding
   Record.push_back(D->isDefinition());
   Record.push_back(D->isEmbeddedInDeclarator());
@@ -279,7 +280,7 @@ void PCHDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
   // FunctionDecl's body is handled last at PCHWriterDecl::Visit,
   // after everything else is written.
 
-  Writer.AddDeclRef(D->getPreviousDeclaration(), Record);
+  VisitRedeclarable(D);
   Record.push_back(D->getStorageClass()); // FIXME: stable encoding
   Record.push_back(D->getStorageClassAsWritten());
   Record.push_back(D->isInlineSpecified());
@@ -500,7 +501,7 @@ void PCHDeclWriter::VisitVarDecl(VarDecl *D) {
   Record.push_back(D->isDeclaredInCondition());
   Record.push_back(D->isExceptionVariable());
   Record.push_back(D->isNRVOVariable());
-  Writer.AddDeclRef(D->getPreviousDeclaration(), Record);
+  VisitRedeclarable(D);
   Record.push_back(D->getInit() ? 1 : 0);
   if (D->getInit())
     Writer.AddStmt(D->getInit());
@@ -854,6 +855,18 @@ void PCHDeclWriter::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {
       Record.push_back(D->isMemberSpecialization());
 
     Writer.AddDeclRef(D->getCommonPtr()->Latest, Record);
+  } else {
+    RedeclarableTemplateDecl *First = D->getFirstDeclaration();
+    assert(First != D);
+    // If this is a most recent redeclaration that is pointed to by a first decl
+    // in a chained PCH, keep track of the association with the map so we can
+    // update the first decl during PCH reading.
+    if (First->getMostRecentDeclaration() == D &&
+        First->getPCHLevel() > D->getPCHLevel()) {
+      assert(Writer.FirstLatestDecls.find(First)==Writer.FirstLatestDecls.end()
+             && "The latest is already set");
+      Writer.FirstLatestDecls[First] = D;
+    }
   }
 }
 
@@ -1016,6 +1029,29 @@ void PCHDeclWriter::VisitDeclContext(DeclContext *DC, uint64_t LexicalOffset,
   Record.push_back(VisibleOffset);
 }
 
+template <typename T>
+void PCHDeclWriter::VisitRedeclarable(Redeclarable<T> *D) {
+  enum { NoRedeclaration = 0, PointsToPrevious, PointsToLatest };
+  if (D->RedeclLink.getNext() == D) {
+    Record.push_back(NoRedeclaration);
+  } else {
+    Record.push_back(D->RedeclLink.NextIsPrevious() ? PointsToPrevious
+                                                    : PointsToLatest);
+    Writer.AddDeclRef(D->RedeclLink.getPointer(), Record);
+  }
+
+  T *First = D->getFirstDeclaration();
+  T *ThisDecl = static_cast<T*>(D);
+  // If this is a most recent redeclaration that is pointed to by a first decl
+  // in a chained PCH, keep track of the association with the map so we can
+  // update the first decl during PCH reading.
+  if (ThisDecl != First && First->getMostRecentDeclaration() == ThisDecl &&
+      First->getPCHLevel() > ThisDecl->getPCHLevel()) {
+    assert(Writer.FirstLatestDecls.find(First) == Writer.FirstLatestDecls.end()
+           && "The latest is already set");
+    Writer.FirstLatestDecls[First] = ThisDecl;
+  }
+}
 
 //===----------------------------------------------------------------------===//
 // PCHWriter Implementation
index f12742755a9f7e9320336f8294d99fe42f4a82f8..8e89b1da462b9f1b983ab01933e66c35dc260ef0 100644 (file)
@@ -1,9 +1,13 @@
 // Test this without pch.
-// RUN: %clang_cc1 -include %S/cxx-templates.h -verify %s -ast-dump
+// RUN: %clang_cc1 -include %S/cxx-templates.h -verify %s -ast-dump 1>/dev/null
+// RUN: %clang_cc1 -include %S/cxx-templates.h %s -emit-llvm -o - | FileCheck %s
 
 // Test with pch.
 // RUN: %clang_cc1 -x c++-header -emit-pch -o %t %S/cxx-templates.h
-// RUN: %clang_cc1 -include-pch %t -verify %s -ast-dump 
+// RUN: %clang_cc1 -include-pch %t -verify %s -ast-dump  1>/dev/null
+// RUN: %clang_cc1 -include-pch %t %s -emit-llvm -o - | FileCheck %s
+
+// CHECK: define linkonce_odr void @_ZN2S3IiE1mEv
 
 struct A {
   typedef int type;
@@ -22,4 +26,7 @@ void test() {
   Dep<A>::Ty ty;
   Dep<A> a;
   a.f();
+  
+  S3<int> s3;
+  s3.m();
 }
index 92932199fa825918b2c3712d71cdba90172efe1b..91d53d3060a0b0e159cdefcd3205a797339303a2 100644 (file)
@@ -116,3 +116,11 @@ struct S2 {
 };
 
 extern template class S2<true>;
+
+template <typename T>
+struct S3 {
+    void m();
+};
+
+template <typename T>
+inline void S3<T>::m() { }