Index: clang/include/clang/AST/ExternalASTSource.h =================================================================== --- clang/include/clang/AST/ExternalASTSource.h +++ clang/include/clang/AST/ExternalASTSource.h @@ -166,6 +166,10 @@ /// object file. virtual bool DeclIsFromPCHWithObjectFile(const Decl *D) { return false; } + /// Determine whether D is a pending instantiation that comes from a PCH + /// which was built with a corresponding object file. + virtual bool DeclIsPendingInstantiationFromPCHWithObjectFile(const Decl *D) { return false; } + /// Abstracts clang modules and precompiled header files and holds /// everything needed to generate debug info for an imported module /// or PCH. Index: clang/include/clang/Sema/MultiplexExternalSemaSource.h =================================================================== --- clang/include/clang/Sema/MultiplexExternalSemaSource.h +++ clang/include/clang/Sema/MultiplexExternalSemaSource.h @@ -153,6 +153,8 @@ bool DeclIsFromPCHWithObjectFile(const Decl *D) override; + bool DeclIsPendingInstantiationFromPCHWithObjectFile(const Decl *D) override; + /// Perform layout on the given record. /// /// This routine allows the external AST source to provide an specific Index: clang/include/clang/Serialization/ASTReader.h =================================================================== --- clang/include/clang/Serialization/ASTReader.h +++ clang/include/clang/Serialization/ASTReader.h @@ -792,6 +792,11 @@ /// is the instantiation location. SmallVector PendingInstantiations; + /// The position in PendingInstantiations for ReadPendingInstantiations(). + /// + /// To make sure ReadPendingInstantiations() does not return the same item twice. + unsigned PendingInstantiationsReadCount = 0; + //@} /// \name DiagnosticsEngine-relevant special data @@ -2089,6 +2094,8 @@ bool DeclIsFromPCHWithObjectFile(const Decl *D) override; + bool DeclIsPendingInstantiationFromPCHWithObjectFile(const Decl *D) override; + /// Retrieve the module file with a given local ID within the specified /// ModuleFile. ModuleFile *getLocalModuleFile(ModuleFile &M, unsigned ID); Index: clang/lib/AST/ASTContext.cpp =================================================================== --- clang/lib/AST/ASTContext.cpp +++ clang/lib/AST/ASTContext.cpp @@ -9862,6 +9862,11 @@ // We never need to emit an uninstantiated function template. if (FD->getTemplatedKind() == FunctionDecl::TK_FunctionTemplate) return false; + // Force emitting shared template instantiations in the PCH's object file. + if (LangOpts.BuildingPCHWithObjectFile && FD->isFromASTFile() + && getExternalSource()->DeclIsPendingInstantiationFromPCHWithObjectFile(FD)) { + return true; + } } else if (isa(D)) return true; else if (isa(D)) Index: clang/lib/Sema/MultiplexExternalSemaSource.cpp =================================================================== --- clang/lib/Sema/MultiplexExternalSemaSource.cpp +++ clang/lib/Sema/MultiplexExternalSemaSource.cpp @@ -177,6 +177,13 @@ return false; } +bool MultiplexExternalSemaSource::DeclIsPendingInstantiationFromPCHWithObjectFile(const Decl *D) { + for (auto *S : Sources) + if (S->DeclIsPendingInstantiationFromPCHWithObjectFile(D)) + return true; + return false; +} + bool MultiplexExternalSemaSource::layoutRecordType(const RecordDecl *Record, uint64_t &Size, uint64_t &Alignment, Index: clang/lib/Sema/Sema.cpp =================================================================== --- clang/lib/Sema/Sema.cpp +++ clang/lib/Sema/Sema.cpp @@ -724,8 +724,12 @@ (void)FD; assert(FD->getMostRecentDecl()->isInlined() && "used object requires definition but isn't inline or internal?"); - // FIXME: This is ill-formed; we should reject. - S.Diag(VD->getLocation(), diag::warn_undefined_inline) << VD; + // TODO check will-never-get-inlined + bool ignoreSkippedPCHTemplate = FD->isFromASTFile() && S.getExternalSource()->DeclIsPendingInstantiationFromPCHWithObjectFile(FD); + if( !ignoreSkippedPCHTemplate ) { + // FIXME: This is ill-formed; we should reject. + S.Diag(VD->getLocation(), diag::warn_undefined_inline) << VD; + } } else { assert(cast(VD)->getMostRecentDecl()->isInline() && "used var requires definition but isn't inline or internal?"); Index: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp =================================================================== --- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1,3 +1,4 @@ +#include //===--- SemaTemplateInstantiateDecl.cpp - C++ Template Decl Instantiation ===/ // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. @@ -4213,6 +4214,31 @@ !PatternDecl->getReturnType()->getContainedAutoType()) return; + if (Function->isFromASTFile() && getExternalSource()->DeclIsPendingInstantiationFromPCHWithObjectFile(Function)) { + assert(getSourceManager().isLoadedSourceLocation(PointOfInstantiation)); + + // Instantiation of this function may be possibly skipped, other translation units + // using the same PCH will instantiate it as well. Do not skip if the function + // may get inlined or evaluated. + + // TODO is restricting to TSK_ImplicitInstantiation needed? + if(TSK == TSK_ImplicitInstantiation) { + // TODO !PatternDecl->getReturnType()->getContainedAutoType()) + + // TODO ctors/dtors are currently broken + bool Ignore = false; + if (dyn_cast(Function) || dyn_cast(Function)) + Ignore = true; + + // TODO check will-never-get-inlined + if(!Function->isConstexpr() && !Function->hasAttr() && !Ignore) { + if(!getLangOpts().BuildingPCHWithObjectFile) { + return; + } + } + } + } + if (PatternDecl->isInlined()) { // Function, and all later redeclarations of it (from imported modules, // for instance), are now implicitly inline. Index: clang/lib/Serialization/ASTReader.cpp =================================================================== --- clang/lib/Serialization/ASTReader.cpp +++ clang/lib/Serialization/ASTReader.cpp @@ -8293,14 +8293,14 @@ void ASTReader::ReadPendingInstantiations( SmallVectorImpl> &Pending) { - for (unsigned Idx = 0, N = PendingInstantiations.size(); Idx < N;) { + for (unsigned Idx = PendingInstantiationsReadCount, N = PendingInstantiations.size(); Idx < N;) { ValueDecl *D = cast(GetDecl(PendingInstantiations[Idx++])); SourceLocation Loc = SourceLocation::getFromRawEncoding(PendingInstantiations[Idx++]); Pending.push_back(std::make_pair(D, Loc)); } - PendingInstantiations.clear(); + PendingInstantiationsReadCount = PendingInstantiations.size(); } void ASTReader::ReadLateParsedTemplates( @@ -8522,6 +8522,17 @@ return MF && MF->PCHHasObjectFile; } +bool ASTReader::DeclIsPendingInstantiationFromPCHWithObjectFile(const Decl *D) { + if( !DeclIsFromPCHWithObjectFile(D)) + return false; + for (unsigned Idx = 0, N = PendingInstantiations.size(); Idx < N;) { + if( D == cast(GetDecl(PendingInstantiations[Idx++]))) + return true; + Idx++; + } + return false; +} + ModuleFile *ASTReader::getLocalModuleFile(ModuleFile &F, unsigned ID) { if (ID & 1) { // It's a module, look it up by submodule ID.