Index: include/clang/AST/ASTContext.h =================================================================== --- include/clang/AST/ASTContext.h +++ include/clang/AST/ASTContext.h @@ -2487,7 +2487,7 @@ /// /// \returns true if the function/var must be CodeGen'ed/deserialized even if /// it is not used. - bool DeclMustBeEmitted(const Decl *D); + bool DeclMustBeEmitted(const Decl *D, bool WritingModule = false); const CXXConstructorDecl * getCopyConstructorForExceptionObject(CXXRecordDecl *RD); Index: include/clang/AST/ExternalASTSource.h =================================================================== --- include/clang/AST/ExternalASTSource.h +++ include/clang/AST/ExternalASTSource.h @@ -16,6 +16,7 @@ #include "clang/AST/CharUnits.h" #include "clang/AST/DeclBase.h" +#include "clang/Basic/Module.h" #include "llvm/ADT/DenseMap.h" namespace clang { @@ -169,6 +170,10 @@ /// Return a descriptor for the corresponding module, if one exists. virtual llvm::Optional getSourceDescriptor(unsigned ID); + enum ExtKind { EK_Always, EK_Never, EK_ReplyHazy }; + + virtual ExtKind hasExternalDefinitions(unsigned ID); + /// \brief Finds all declarations lexically contained within the given /// DeclContext, after applying an optional filter predicate. /// Index: include/clang/Basic/LangOptions.def =================================================================== --- include/clang/Basic/LangOptions.def +++ include/clang/Basic/LangOptions.def @@ -201,6 +201,7 @@ LANGOPT(AlignedAllocation , 1, 0, "aligned allocation") LANGOPT(NewAlignOverride , 32, 0, "maximum alignment guaranteed by '::operator new(size_t)'") LANGOPT(ConceptsTS , 1, 0, "enable C++ Extensions for Concepts") +BENIGN_LANGOPT(ModularCodegen , 1, 1, "Modular codegen") BENIGN_LANGOPT(ElideConstructors , 1, 1, "C++ copy constructor elision") BENIGN_LANGOPT(DumpRecordLayouts , 1, 0, "dumping the layout of IRgen'd records") BENIGN_LANGOPT(DumpRecordLayoutsSimple , 1, 0, "dumping the layout of IRgen'd records in a simple form") Index: include/clang/Basic/Module.h =================================================================== --- include/clang/Basic/Module.h +++ include/clang/Basic/Module.h @@ -205,6 +205,8 @@ /// and headers from used modules. unsigned NoUndeclaredIncludes : 1; + unsigned WithCodegen : 2; + /// \brief Describes the visibility of the various names within a /// particular module. enum NameVisibilityKind { Index: include/clang/Serialization/ASTBitCodes.h =================================================================== --- include/clang/Serialization/ASTBitCodes.h +++ include/clang/Serialization/ASTBitCodes.h @@ -591,6 +591,8 @@ /// \brief Record code for declarations associated with OpenCL extensions. OPENCL_EXTENSION_DECLS = 59, + + MODULAR_CODEGEN_DECLS = 60, }; /// \brief Record types used within a source manager block. Index: include/clang/Serialization/ASTReader.h =================================================================== --- include/clang/Serialization/ASTReader.h +++ include/clang/Serialization/ASTReader.h @@ -715,6 +715,8 @@ /// the consumer eagerly. SmallVector EagerlyDeserializedDecls; + SmallVector ModularCodegenDecls; + /// \brief The IDs of all tentative definitions stored in the chain. /// /// Sema keeps track of all tentative definitions in a TU because it has to @@ -1968,6 +1970,8 @@ /// \brief Return a descriptor for the corresponding module. llvm::Optional getSourceDescriptor(unsigned ID) override; + ExtKind hasExternalDefinitions(unsigned ID) override; + /// \brief Retrieve a selector from the given module with its local ID /// number. Selector getLocalSelector(ModuleFile &M, unsigned LocalID); Index: include/clang/Serialization/ASTWriter.h =================================================================== --- include/clang/Serialization/ASTWriter.h +++ include/clang/Serialization/ASTWriter.h @@ -365,6 +365,7 @@ /// IDs, since they will be written out to an EAGERLY_DESERIALIZED_DECLS /// record. SmallVector EagerlyDeserializedDecls; + SmallVector ModularCodegenDecls; /// \brief DeclContexts that have received extensions since their serialized /// form. Index: lib/AST/ASTContext.cpp =================================================================== --- lib/AST/ASTContext.cpp +++ lib/AST/ASTContext.cpp @@ -8856,8 +8856,22 @@ } GVALinkage ASTContext::GetGVALinkageForFunction(const FunctionDecl *FD) const { - return adjustGVALinkageForAttributes( - *this, basicGVALinkageForFunction(*this, FD), FD); + auto L = adjustGVALinkageForAttributes( + *this, basicGVALinkageForFunction(*this, FD), FD); + auto EK = ExternalASTSource::EK_ReplyHazy; + if (auto *Ext = getExternalSource()) + EK = Ext->hasExternalDefinitions(FD->getOwningModuleID()); + switch (EK) { + case ExternalASTSource::EK_Never: + if (L == GVA_DiscardableODR) + return GVA_StrongODR; + break; + case ExternalASTSource::EK_Always: + return GVA_AvailableExternally; + case ExternalASTSource::EK_ReplyHazy: + break; + } + return L; } static GVALinkage basicGVALinkageForVariable(const ASTContext &Context, @@ -8934,7 +8948,7 @@ *this, basicGVALinkageForVariable(*this, VD), VD); } -bool ASTContext::DeclMustBeEmitted(const Decl *D) { +bool ASTContext::DeclMustBeEmitted(const Decl *D, bool WritingModule) { if (const VarDecl *VD = dyn_cast(D)) { if (!VD->isFileVarDecl()) return false; @@ -8998,6 +9012,17 @@ } } + GVALinkage Linkage = GetGVALinkageForFunction(FD); + + if (Linkage == GVA_DiscardableODR) { + if (WritingModule) + return true; + if (auto *Ext = getExternalSource()) + if (Ext->hasExternalDefinitions(FD->getOwningModuleID()) == + ExternalASTSource::EK_Never) + return true; + } + // static, static inline, always_inline, and extern inline functions can // always be deferred. Normal inline functions can be deferred in C99/C++. // Implicit template instantiations can also be deferred in C++. Index: lib/AST/ExternalASTSource.cpp =================================================================== --- lib/AST/ExternalASTSource.cpp +++ lib/AST/ExternalASTSource.cpp @@ -28,6 +28,11 @@ return None; } +ExternalASTSource::ExtKind +ExternalASTSource::hasExternalDefinitions(unsigned ID) { + return EK_ReplyHazy; +} + ExternalASTSource::ASTSourceDescriptor::ASTSourceDescriptor(const Module &M) : Signature(M.Signature), ClangModule(&M) { if (M.Directory) Index: lib/Basic/Module.cpp =================================================================== --- lib/Basic/Module.cpp +++ lib/Basic/Module.cpp @@ -33,7 +33,8 @@ IsExplicit(IsExplicit), IsSystem(false), IsExternC(false), IsInferred(false), InferSubmodules(false), InferExplicitSubmodules(false), InferExportWildcard(false), ConfigMacrosExhaustive(false), - NoUndeclaredIncludes(false), NameVisibility(Hidden) { + NoUndeclaredIncludes(false), WithCodegen(false), + NameVisibility(Hidden) { if (Parent) { if (!Parent->isAvailable()) IsAvailable = false; Index: lib/CodeGen/CodeGenModule.cpp =================================================================== --- lib/CodeGen/CodeGenModule.cpp +++ lib/CodeGen/CodeGenModule.cpp @@ -2796,7 +2796,7 @@ // We are guaranteed to have a strong definition somewhere else, // so we can use available_externally linkage. if (Linkage == GVA_AvailableExternally) - return llvm::Function::AvailableExternallyLinkage; + return llvm::GlobalValue::AvailableExternallyLinkage; // Note that Apple's kernel linker doesn't support symbol // coalescing, so we need to avoid linkonce and weak linkages there. Index: lib/Lex/ModuleMap.cpp =================================================================== --- lib/Lex/ModuleMap.cpp +++ lib/Lex/ModuleMap.cpp @@ -554,16 +554,17 @@ return Context->findSubmodule(Name); } -std::pair -ModuleMap::findOrCreateModule(StringRef Name, Module *Parent, bool IsFramework, - bool IsExplicit) { +std::pair ModuleMap::findOrCreateModule(StringRef Name, + Module *Parent, + bool IsFramework, + bool IsExplicit) { // Try to find an existing module with this name. if (Module *Sub = lookupModuleQualified(Name, Parent)) return std::make_pair(Sub, false); // Create a new module with this name. - Module *Result = new Module(Name, SourceLocation(), Parent, - IsFramework, IsExplicit, NumCreatedModules++); + Module *Result = new Module(Name, SourceLocation(), Parent, IsFramework, + IsExplicit, NumCreatedModules++); if (!Parent) { if (LangOpts.CurrentModule == Name) SourceModule = Result; @@ -1499,6 +1500,7 @@ (!ActiveModule->Parent && ModuleName == "Darwin")) ActiveModule->NoUndeclaredIncludes = true; ActiveModule->Directory = Directory; + ActiveModule->WithCodegen = L.getLangOpts().ModularCodegen; if (!ActiveModule->Parent) { StringRef MapFileName(ModuleMapFile->getName()); Index: lib/Serialization/ASTReader.cpp =================================================================== --- lib/Serialization/ASTReader.cpp +++ lib/Serialization/ASTReader.cpp @@ -2607,7 +2607,8 @@ break; case SUBMODULE_BLOCK_ID: - if (ASTReadResult Result = ReadSubmoduleBlock(F, ClientLoadCapabilities)) + if (ASTReadResult Result = + ReadSubmoduleBlock(F, ClientLoadCapabilities)) return Result; break; @@ -2772,6 +2773,14 @@ EagerlyDeserializedDecls.push_back(getGlobalDeclID(F, Record[I])); break; + case MODULAR_CODEGEN_DECLS: + // FIXME: Skip reading this record if our ASTConsumer doesn't care about + // them (ie: if we're not codegenerating this module). + if (F.Kind == MK_MainFile) + for (unsigned I = 0, N = Record.size(); I != N; ++I) + EagerlyDeserializedDecls.push_back(getGlobalDeclID(F, Record[I])); + break; + case SPECIAL_TYPES: if (SpecialTypes.empty()) { for (unsigned I = 0, N = Record.size(); I != N; ++I) @@ -4630,6 +4639,7 @@ bool InferExplicitSubmodules = Record[Idx++]; bool InferExportWildcard = Record[Idx++]; bool ConfigMacrosExhaustive = Record[Idx++]; + bool WithCodegen = Record[Idx++]; Module *ParentModule = nullptr; if (Parent) @@ -4637,8 +4647,9 @@ // Retrieve this (sub)module from the module map, creating it if // necessary. - CurrentModule = ModMap.findOrCreateModule(Name, ParentModule, IsFramework, - IsExplicit).first; + CurrentModule = + ModMap.findOrCreateModule(Name, ParentModule, IsFramework, IsExplicit) + .first; // FIXME: set the definition loc for CurrentModule, or call // ModMap.setInferredModuleAllowedBy() @@ -4674,6 +4685,7 @@ CurrentModule->InferExplicitSubmodules = InferExplicitSubmodules; CurrentModule->InferExportWildcard = InferExportWildcard; CurrentModule->ConfigMacrosExhaustive = ConfigMacrosExhaustive; + CurrentModule->WithCodegen = WithCodegen; if (DeserializationListener) DeserializationListener->ModuleRead(GlobalID, CurrentModule); @@ -7852,6 +7864,18 @@ return None; } +ExternalASTSource::ExtKind ASTReader::hasExternalDefinitions(unsigned ID) { + const Module *M = getSubmodule(ID); + if (!M || !M->WithCodegen) + return EK_ReplyHazy; + + ModuleFile *MF = ModuleMgr.lookup(M->getASTFile()); + assert(MF); // ? + if (MF->Kind == ModuleKind::MK_MainFile) + return EK_Never; + return EK_Always; +} + Selector ASTReader::getLocalSelector(ModuleFile &M, unsigned LocalID) { return DecodeSelector(getGlobalSelectorID(M, LocalID)); } Index: lib/Serialization/ASTWriter.cpp =================================================================== --- lib/Serialization/ASTWriter.cpp +++ lib/Serialization/ASTWriter.cpp @@ -1030,6 +1030,7 @@ RECORD(IDENTIFIER_OFFSET); RECORD(IDENTIFIER_TABLE); RECORD(EAGERLY_DESERIALIZED_DECLS); + RECORD(MODULAR_CODEGEN_DECLS); RECORD(SPECIAL_TYPES); RECORD(STATISTICS); RECORD(TENTATIVE_DEFINITIONS); @@ -2575,6 +2576,7 @@ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // InferExplicit... Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // InferExportWild... Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // ConfigMacrosExh... + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // WithCodegen Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name unsigned DefinitionAbbrev = Stream.EmitAbbrev(std::move(Abbrev)); @@ -2667,7 +2669,7 @@ SUBMODULE_DEFINITION, ID, ParentID, Mod->IsFramework, Mod->IsExplicit, Mod->IsSystem, Mod->IsExternC, Mod->InferSubmodules, Mod->InferExplicitSubmodules, Mod->InferExportWildcard, - Mod->ConfigMacrosExhaustive}; + Mod->ConfigMacrosExhaustive, Mod->WithCodegen}; Stream.EmitRecordWithBlob(DefinitionAbbrev, Record, Mod->Name); } @@ -4675,6 +4677,9 @@ if (!EagerlyDeserializedDecls.empty()) Stream.EmitRecord(EAGERLY_DESERIALIZED_DECLS, EagerlyDeserializedDecls); + if (Context.getLangOpts().ModularCodegen) + Stream.EmitRecord(MODULAR_CODEGEN_DECLS, ModularCodegenDecls); + // Write the record containing tentative definitions. if (!TentativeDefinitions.empty()) Stream.EmitRecord(TENTATIVE_DEFINITIONS, TentativeDefinitions); Index: lib/Serialization/ASTWriterDecl.cpp =================================================================== --- lib/Serialization/ASTWriterDecl.cpp +++ lib/Serialization/ASTWriterDecl.cpp @@ -2152,7 +2152,7 @@ /// relatively painless since they would presumably only do it for top-level /// decls. static bool isRequiredDecl(const Decl *D, ASTContext &Context, - bool WritingModule) { + bool WritingModule, bool ModularCode) { // An ObjCMethodDecl is never considered as "required" because its // implementation container always is. @@ -2168,7 +2168,7 @@ return false; } - return Context.DeclMustBeEmitted(D); + return Context.DeclMustBeEmitted(D, ModularCode); } void ASTWriter::WriteDecl(ASTContext &Context, Decl *D) { @@ -2212,8 +2212,11 @@ // Note declarations that should be deserialized eagerly so that we can add // them to a record in the AST file later. - if (isRequiredDecl(D, Context, WritingModule)) + if (isRequiredDecl(D, Context, WritingModule, false)) EagerlyDeserializedDecls.push_back(ID); + else if (Context.getLangOpts().ModularCodegen && WritingModule && + isRequiredDecl(D, Context, true, true)) + ModularCodegenDecls.push_back(ID); } void ASTRecordWriter::AddFunctionDefinition(const FunctionDecl *FD) {