]> granicus.if.org Git - clang/commitdiff
Store the pending implicit instantiations in the PCH and perform them at the end...
authorArgyrios Kyrtzidis <akyrtzi@gmail.com>
Thu, 5 Aug 2010 09:48:16 +0000 (09:48 +0000)
committerArgyrios Kyrtzidis <akyrtzi@gmail.com>
Thu, 5 Aug 2010 09:48:16 +0000 (09:48 +0000)
included the PCH, as God intended.

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

include/clang/Frontend/PCHBitCodes.h
include/clang/Frontend/PCHReader.h
lib/Frontend/PCHReader.cpp
lib/Frontend/PCHWriter.cpp
lib/Sema/Sema.cpp
test/PCH/cxx-templates.cpp
test/PCH/cxx-templates.h

index 37337963a18d36271749d866f3750601f385f106..7605670f0eaf44f3dd7339949995bd72448c6f05 100644 (file)
@@ -253,7 +253,10 @@ namespace clang {
       SEMA_DECL_REFS = 30,
 
       /// \brief Record code for weak undeclared identifiers.
-      WEAK_UNDECLARED_IDENTIFIERS = 31
+      WEAK_UNDECLARED_IDENTIFIERS = 31,
+
+      /// \brief Record code for pending implicit instantiations.
+      PENDING_IMPLICIT_INSTANTIATIONS = 32
     };
 
     /// \brief Record types used within a source manager block.
index 76975a0e01cc81801458b9f52027c6a1ffd5f44d..fc63e82287b8844ba4024e172ae8d388365ec394 100644 (file)
@@ -397,6 +397,9 @@ private:
   /// \brief The set of dynamic CXXRecord declarations stored in the PCH file.
   llvm::SmallVector<uint64_t, 16> DynamicClasses;
 
+  /// \brief The set of pending implicit instantiations stored in the PCH file.
+  llvm::SmallVector<uint64_t, 64> PendingImplicitInstantiations;
+
   /// \brief The set of Sema declaration references, stored in PCH.
   llvm::SmallVector<uint64_t, 4> SemaDeclRefs;
 
index 7229775070e72ad5359d54c22678e7ccd683de70..98b274d17517368c6504b373c517291eb79543dc 100644 (file)
@@ -1739,6 +1739,15 @@ PCHReader::ReadPCHBlock(PerFileData &F) {
       DynamicClasses.swap(Record);
       break;
 
+    case pch::PENDING_IMPLICIT_INSTANTIATIONS:
+      // Optimization for the first block.
+      if (PendingImplicitInstantiations.empty())
+        PendingImplicitInstantiations.swap(Record);
+      else
+        PendingImplicitInstantiations.insert(
+             PendingImplicitInstantiations.end(), Record.begin(), Record.end());
+      break;
+
     case pch::SEMA_DECL_REFS:
       if (!SemaDeclRefs.empty()) {
         Error("duplicate SEMA_DECL_REFS record in PCH file");
@@ -3191,6 +3200,16 @@ void PCHReader::InitializeSema(Sema &S) {
     SemaObj->DynamicClasses.push_back(
                                cast<CXXRecordDecl>(GetDecl(DynamicClasses[I])));
 
+  // If there were any pending implicit instantiations, deserialize them
+  // and add them to Sema's queue of such instantiations.
+  assert(PendingImplicitInstantiations.size() % 2 == 0 &&
+         "Expected pairs of entries");
+  for (unsigned Idx = 0, N = PendingImplicitInstantiations.size(); Idx < N;) {
+    ValueDecl *D=cast<ValueDecl>(GetDecl(PendingImplicitInstantiations[Idx++]));
+    SourceLocation Loc = ReadSourceLocation(PendingImplicitInstantiations, Idx);
+    SemaObj->PendingImplicitInstantiations.push_back(std::make_pair(D, Loc));
+  }
+
   // Load the offsets of the declarations that Sema references.
   // They will be lazily deserialized when needed.
   if (!SemaDeclRefs.empty()) {
index d6dc36fd30d2849b29075792c7f49d00ddb2a684..86b2273ea6c068d4f181074d8acda0cdb512d19f 100644 (file)
@@ -2255,6 +2255,17 @@ void PCHWriter::WritePCHCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
   for (unsigned I = 0, N = SemaRef.DynamicClasses.size(); I != N; ++I)
     AddDeclRef(SemaRef.DynamicClasses[I], DynamicClasses);
 
+  // Build a record containing all of pending implicit instantiations.
+  RecordData PendingImplicitInstantiations;
+  for (std::deque<Sema::PendingImplicitInstantiation>::iterator
+         I = SemaRef.PendingImplicitInstantiations.begin(),
+         N = SemaRef.PendingImplicitInstantiations.end(); I != N; ++I) {
+    AddDeclRef(I->first, PendingImplicitInstantiations);
+    AddSourceLocation(I->second, PendingImplicitInstantiations);
+  }
+  assert(SemaRef.PendingLocalImplicitInstantiations.empty() &&
+         "There are local ones at end of translation unit!");
+
   // Build a record containing some declaration references.
   RecordData SemaDeclRefs;
   if (SemaRef.StdNamespace || SemaRef.StdBadAlloc) {
@@ -2347,6 +2358,11 @@ void PCHWriter::WritePCHCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
   if (!DynamicClasses.empty())
     Stream.EmitRecord(pch::DYNAMIC_CLASSES, DynamicClasses);
 
+  // Write the record containing pending implicit instantiations.
+  if (!PendingImplicitInstantiations.empty())
+    Stream.EmitRecord(pch::PENDING_IMPLICIT_INSTANTIATIONS,
+                      PendingImplicitInstantiations);
+
   // Write the record containing declaration references of Sema.
   if (!SemaDeclRefs.empty())
     Stream.EmitRecord(pch::SEMA_DECL_REFS, SemaDeclRefs);
index 6de4202bae0314e3574cf0513b5c6baeb8140b6f..244538147e53ddfd4325db9435c05d88a0c21a13 100644 (file)
@@ -215,26 +215,29 @@ void Sema::DeleteStmt(StmtTy *S) {
 /// ActOnEndOfTranslationUnit - This is called at the very end of the
 /// translation unit when EOF is reached and all but the top-level scope is
 /// popped.
-void Sema::ActOnEndOfTranslationUnit() {  
-  while (1) {
-    // C++: Perform implicit template instantiations.
-    //
-    // FIXME: When we perform these implicit instantiations, we do not carefully
-    // keep track of the point of instantiation (C++ [temp.point]). This means
-    // that name lookup that occurs within the template instantiation will
-    // always happen at the end of the translation unit, so it will find
-    // some names that should not be found. Although this is common behavior
-    // for C++ compilers, it is technically wrong. In the future, we either need
-    // to be able to filter the results of name lookup or we need to perform
-    // template instantiations earlier.
-    PerformPendingImplicitInstantiations();
-    
-    /// If DefinedUsedVTables ends up marking any virtual member
-    /// functions it might lead to more pending template
-    /// instantiations, which is why we need to loop here.
-    if (!DefineUsedVTables())
-      break;
-  }
+void Sema::ActOnEndOfTranslationUnit() {
+  // At PCH writing, implicit instantiations and VTable handling info are
+  // stored and performed when the PCH is included.
+  if (CompleteTranslationUnit)
+    while (1) {
+      // C++: Perform implicit template instantiations.
+      //
+      // FIXME: When we perform these implicit instantiations, we do not
+      // carefully keep track of the point of instantiation (C++ [temp.point]).
+      // This means that name lookup that occurs within the template
+      // instantiation will always happen at the end of the translation unit,
+      // so it will find some names that should not be found. Although this is
+      // common behavior for C++ compilers, it is technically wrong. In the
+      // future, we either need to be able to filter the results of name lookup
+      // or we need to perform template instantiations earlier.
+      PerformPendingImplicitInstantiations();
+
+      /// If DefinedUsedVTables ends up marking any virtual member
+      /// functions it might lead to more pending template
+      /// instantiations, which is why we need to loop here.
+      if (!DefineUsedVTables())
+        break;
+    }
   
   // Remove functions that turned out to be used.
   UnusedStaticFuncs.erase(std::remove_if(UnusedStaticFuncs.begin(), 
index 8e89b1da462b9f1b983ab01933e66c35dc260ef0..0749fc31e39b86b715960a0181f8bb692375bb98 100644 (file)
@@ -7,6 +7,7 @@
 // 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 weak_odr void @_ZN2S4IiE1mEv
 // CHECK: define linkonce_odr void @_ZN2S3IiE1mEv
 
 struct A {
@@ -30,3 +31,5 @@ void test() {
   S3<int> s3;
   s3.m();
 }
+
+template struct S4<int>;
index 91d53d3060a0b0e159cdefcd3205a797339303a2..978d768acc9207c68af2eefe62beef30659700c6 100644 (file)
@@ -124,3 +124,14 @@ struct S3 {
 
 template <typename T>
 inline void S3<T>::m() { }
+
+template <typename T>
+struct S4 {
+    void m() { }
+};
+extern template struct S4<int>;
+
+void S4ImplicitInst() {
+    S4<int> s;
+    s.m();
+}