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.
/// \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;
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");
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()) {
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) {
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);
/// 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(),
// 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 {
S3<int> s3;
s3.m();
}
+
+template struct S4<int>;
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();
+}