Store the pending implicit instantiations in the PCH and perform them at the end of the translation unit that
included the PCH, as God intended.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@110324 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Frontend/PCHBitCodes.h b/include/clang/Frontend/PCHBitCodes.h
index 3733796..7605670 100644
--- a/include/clang/Frontend/PCHBitCodes.h
+++ b/include/clang/Frontend/PCHBitCodes.h
@@ -253,7 +253,10 @@
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.
diff --git a/include/clang/Frontend/PCHReader.h b/include/clang/Frontend/PCHReader.h
index 76975a0..fc63e82 100644
--- a/include/clang/Frontend/PCHReader.h
+++ b/include/clang/Frontend/PCHReader.h
@@ -397,6 +397,9 @@
/// \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;
diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp
index 7229775..98b274d 100644
--- a/lib/Frontend/PCHReader.cpp
+++ b/lib/Frontend/PCHReader.cpp
@@ -1739,6 +1739,15 @@
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 @@
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()) {
diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp
index d6dc36f..86b2273 100644
--- a/lib/Frontend/PCHWriter.cpp
+++ b/lib/Frontend/PCHWriter.cpp
@@ -2255,6 +2255,17 @@
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 @@
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);
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 6de4202..2445381 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -215,26 +215,29 @@
/// 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(),
diff --git a/test/PCH/cxx-templates.cpp b/test/PCH/cxx-templates.cpp
index 8e89b1d..0749fc3 100644
--- a/test/PCH/cxx-templates.cpp
+++ b/test/PCH/cxx-templates.cpp
@@ -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 @@
S3<int> s3;
s3.m();
}
+
+template struct S4<int>;
diff --git a/test/PCH/cxx-templates.h b/test/PCH/cxx-templates.h
index 91d53d3..978d768 100644
--- a/test/PCH/cxx-templates.h
+++ b/test/PCH/cxx-templates.h
@@ -124,3 +124,14 @@
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();
+}