Index: cfe/trunk/include/clang/AST/ASTContext.h =================================================================== --- cfe/trunk/include/clang/AST/ASTContext.h +++ cfe/trunk/include/clang/AST/ASTContext.h @@ -2510,7 +2510,7 @@ /// /// \returns true if the function/var must be CodeGen'ed/deserialized even if /// it is not used. - bool DeclMustBeEmitted(const Decl *D, bool ForModularCodegen = false); + bool DeclMustBeEmitted(const Decl *D); const CXXConstructorDecl * getCopyConstructorForExceptionObject(CXXRecordDecl *RD); Index: cfe/trunk/include/clang/AST/ExternalASTSource.h =================================================================== --- cfe/trunk/include/clang/AST/ExternalASTSource.h +++ cfe/trunk/include/clang/AST/ExternalASTSource.h @@ -172,7 +172,7 @@ enum ExtKind { EK_Always, EK_Never, EK_ReplyHazy }; - virtual ExtKind hasExternalDefinitions(unsigned ID); + virtual ExtKind hasExternalDefinitions(const FunctionDecl *FD); /// \brief Finds all declarations lexically contained within the given /// DeclContext, after applying an optional filter predicate. Index: cfe/trunk/include/clang/Basic/Module.h =================================================================== --- cfe/trunk/include/clang/Basic/Module.h +++ cfe/trunk/include/clang/Basic/Module.h @@ -215,8 +215,6 @@ /// and headers from used modules. unsigned NoUndeclaredIncludes : 1; - unsigned WithCodegen : 1; - /// \brief Describes the visibility of the various names within a /// particular module. enum NameVisibilityKind { Index: cfe/trunk/include/clang/Sema/MultiplexExternalSemaSource.h =================================================================== --- cfe/trunk/include/clang/Sema/MultiplexExternalSemaSource.h +++ cfe/trunk/include/clang/Sema/MultiplexExternalSemaSource.h @@ -90,7 +90,7 @@ /// initializers themselves. CXXCtorInitializer **GetExternalCXXCtorInitializers(uint64_t Offset) override; - ExtKind hasExternalDefinitions(unsigned ID) override; + ExtKind hasExternalDefinitions(const FunctionDecl *FD) override; /// \brief Find all declarations with the given name in the /// given context. Index: cfe/trunk/include/clang/Serialization/ASTReader.h =================================================================== --- cfe/trunk/include/clang/Serialization/ASTReader.h +++ cfe/trunk/include/clang/Serialization/ASTReader.h @@ -1115,6 +1115,8 @@ /// predefines buffer may contain additional definitions. std::string SuggestedPredefines; + llvm::DenseMap BodySource; + /// \brief Reads a statement from the specified cursor. Stmt *ReadStmtFromStream(ModuleFile &F); @@ -1997,7 +1999,7 @@ /// \brief Return a descriptor for the corresponding module. llvm::Optional getSourceDescriptor(unsigned ID) override; - ExtKind hasExternalDefinitions(unsigned ID) override; + ExtKind hasExternalDefinitions(const FunctionDecl *FD) override; /// \brief Retrieve a selector from the given module with its local ID /// number. Index: cfe/trunk/lib/AST/ASTContext.cpp =================================================================== --- cfe/trunk/lib/AST/ASTContext.cpp +++ cfe/trunk/lib/AST/ASTContext.cpp @@ -8897,7 +8897,7 @@ *this, basicGVALinkageForFunction(*this, FD), FD); auto EK = ExternalASTSource::EK_ReplyHazy; if (auto *Ext = getExternalSource()) - EK = Ext->hasExternalDefinitions(FD->getOwningModuleID()); + EK = Ext->hasExternalDefinitions(FD); switch (EK) { case ExternalASTSource::EK_Never: if (L == GVA_DiscardableODR) @@ -8993,7 +8993,7 @@ *this, basicGVALinkageForVariable(*this, VD), VD); } -bool ASTContext::DeclMustBeEmitted(const Decl *D, bool ForModularCodegen) { +bool ASTContext::DeclMustBeEmitted(const Decl *D) { if (const VarDecl *VD = dyn_cast(D)) { if (!VD->isFileVarDecl()) return false; @@ -9059,9 +9059,6 @@ GVALinkage Linkage = GetGVALinkageForFunction(FD); - if (Linkage == GVA_DiscardableODR && ForModularCodegen) - 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: cfe/trunk/lib/AST/ExternalASTSource.cpp =================================================================== --- cfe/trunk/lib/AST/ExternalASTSource.cpp +++ cfe/trunk/lib/AST/ExternalASTSource.cpp @@ -29,7 +29,7 @@ } ExternalASTSource::ExtKind -ExternalASTSource::hasExternalDefinitions(unsigned ID) { +ExternalASTSource::hasExternalDefinitions(const FunctionDecl *FD) { return EK_ReplyHazy; } Index: cfe/trunk/lib/Basic/Module.cpp =================================================================== --- cfe/trunk/lib/Basic/Module.cpp +++ cfe/trunk/lib/Basic/Module.cpp @@ -33,7 +33,7 @@ IsExplicit(IsExplicit), IsSystem(false), IsExternC(false), IsInferred(false), InferSubmodules(false), InferExplicitSubmodules(false), InferExportWildcard(false), ConfigMacrosExhaustive(false), - NoUndeclaredIncludes(false), WithCodegen(false), NameVisibility(Hidden) { + NoUndeclaredIncludes(false), NameVisibility(Hidden) { if (Parent) { if (!Parent->isAvailable()) IsAvailable = false; Index: cfe/trunk/lib/Sema/MultiplexExternalSemaSource.cpp =================================================================== --- cfe/trunk/lib/Sema/MultiplexExternalSemaSource.cpp +++ cfe/trunk/lib/Sema/MultiplexExternalSemaSource.cpp @@ -95,9 +95,9 @@ } ExternalASTSource::ExtKind -MultiplexExternalSemaSource::hasExternalDefinitions(unsigned int ID) { +MultiplexExternalSemaSource::hasExternalDefinitions(const FunctionDecl *FD) { for (const auto &S : Sources) - if (auto EK = S->hasExternalDefinitions(ID)) + if (auto EK = S->hasExternalDefinitions(FD)) if (EK != EK_ReplyHazy) return EK; return EK_ReplyHazy; Index: cfe/trunk/lib/Serialization/ASTReader.cpp =================================================================== --- cfe/trunk/lib/Serialization/ASTReader.cpp +++ cfe/trunk/lib/Serialization/ASTReader.cpp @@ -4834,7 +4834,6 @@ bool InferExplicitSubmodules = Record[Idx++]; bool InferExportWildcard = Record[Idx++]; bool ConfigMacrosExhaustive = Record[Idx++]; - bool WithCodegen = Record[Idx++]; Module *ParentModule = nullptr; if (Parent) @@ -4880,7 +4879,6 @@ CurrentModule->InferExplicitSubmodules = InferExplicitSubmodules; CurrentModule->InferExportWildcard = InferExportWildcard; CurrentModule->ConfigMacrosExhaustive = ConfigMacrosExhaustive; - CurrentModule->WithCodegen = WithCodegen; if (DeserializationListener) DeserializationListener->ModuleRead(GlobalID, CurrentModule); @@ -8149,16 +8147,12 @@ return None; } -ExternalASTSource::ExtKind ASTReader::hasExternalDefinitions(unsigned ID) { - const Module *M = getSubmodule(ID); - if (!M || !M->WithCodegen) +ExternalASTSource::ExtKind +ASTReader::hasExternalDefinitions(const FunctionDecl *FD) { + auto I = BodySource.find(FD); + if (I == BodySource.end()) return EK_ReplyHazy; - - ModuleFile *MF = ModuleMgr.lookup(M->getASTFile()); - assert(MF); // ? - if (MF->Kind == ModuleKind::MK_MainFile) - return EK_Never; - return EK_Always; + return I->second ? EK_Never : EK_Always; } Selector ASTReader::getLocalSelector(ModuleFile &M, unsigned LocalID) { @@ -8992,9 +8986,9 @@ // FIXME: Check for =delete/=default? // FIXME: Complain about ODR violations here? const FunctionDecl *Defn = nullptr; - if (!getContext().getLangOpts().Modules || !FD->hasBody(Defn)) + if (!getContext().getLangOpts().Modules || !FD->hasBody(Defn)) { FD->setLazyBody(PB->second); - else + } else mergeDefinitionVisibility(const_cast(Defn), FD); continue; } Index: cfe/trunk/lib/Serialization/ASTReaderDecl.cpp =================================================================== --- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp +++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp @@ -424,6 +424,8 @@ } void ASTDeclReader::ReadFunctionDefinition(FunctionDecl *FD) { + if (Record.readInt()) + Reader.BodySource[FD] = Loc.F->Kind == ModuleKind::MK_MainFile; if (auto *CD = dyn_cast(FD)) { CD->NumCtorInitializers = Record.readInt(); if (CD->NumCtorInitializers) Index: cfe/trunk/lib/Serialization/ASTWriter.cpp =================================================================== --- cfe/trunk/lib/Serialization/ASTWriter.cpp +++ cfe/trunk/lib/Serialization/ASTWriter.cpp @@ -2627,7 +2627,6 @@ 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, 1)); // WithCodegen Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name unsigned DefinitionAbbrev = Stream.EmitAbbrev(std::move(Abbrev)); @@ -2726,8 +2725,7 @@ Mod->InferSubmodules, Mod->InferExplicitSubmodules, Mod->InferExportWildcard, - Mod->ConfigMacrosExhaustive, - Context->getLangOpts().ModularCodegen && WritingModule}; + Mod->ConfigMacrosExhaustive}; Stream.EmitRecordWithBlob(DefinitionAbbrev, Record, Mod->Name); } Index: cfe/trunk/lib/Serialization/ASTWriterDecl.cpp =================================================================== --- cfe/trunk/lib/Serialization/ASTWriterDecl.cpp +++ cfe/trunk/lib/Serialization/ASTWriterDecl.cpp @@ -2159,7 +2159,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 ModularCode) { + bool WritingModule) { // An ObjCMethodDecl is never considered as "required" because its // implementation container always is. @@ -2175,7 +2175,7 @@ return false; } - return Context.DeclMustBeEmitted(D, ModularCode); + return Context.DeclMustBeEmitted(D); } void ASTWriter::WriteDecl(ASTContext &Context, Decl *D) { @@ -2219,11 +2219,8 @@ // 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, false)) + if (isRequiredDecl(D, Context, WritingModule)) 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) { @@ -2231,6 +2228,11 @@ Writer->ClearSwitchCaseIDs(); assert(FD->doesThisDeclarationHaveABody()); + bool ModularCodegen = Writer->Context->getLangOpts().ModularCodegen && + Writer->WritingModule && !FD->isDependentContext(); + Record->push_back(ModularCodegen); + if (ModularCodegen) + Writer->ModularCodegenDecls.push_back(Writer->GetDeclRef(FD)); if (auto *CD = dyn_cast(FD)) { Record->push_back(CD->getNumCtorInitializers()); if (CD->getNumCtorInitializers()) Index: cfe/trunk/test/Modules/Inputs/codegen-nodep/foo.h =================================================================== --- cfe/trunk/test/Modules/Inputs/codegen-nodep/foo.h +++ cfe/trunk/test/Modules/Inputs/codegen-nodep/foo.h @@ -0,0 +1,5 @@ +template +void ftempl() { +} +inline void f() { +} Index: cfe/trunk/test/Modules/Inputs/codegen-nodep/foo.modulemap =================================================================== --- cfe/trunk/test/Modules/Inputs/codegen-nodep/foo.modulemap +++ cfe/trunk/test/Modules/Inputs/codegen-nodep/foo.modulemap @@ -0,0 +1 @@ +module foo { header "foo.h" } Index: cfe/trunk/test/Modules/Inputs/codegen/foo.h =================================================================== --- cfe/trunk/test/Modules/Inputs/codegen/foo.h +++ cfe/trunk/test/Modules/Inputs/codegen/foo.h @@ -2,3 +2,29 @@ __builtin_va_list args; __builtin_va_start(args, fmt); } + +struct non_trivial_dtor { + ~non_trivial_dtor(); +}; + +struct implicit_dtor { + non_trivial_dtor d; +}; + +struct uninst_implicit_dtor { + non_trivial_dtor d; +}; + +inline void use_implicit_dtor() { + implicit_dtor d; +} + +template +void inst() { +} + +inline void inst_decl() { + // cause inst's declaration to be instantiated, without a definition. + (void)sizeof(&inst); + inst(); +} Index: cfe/trunk/test/Modules/Inputs/codegen/use.cpp =================================================================== --- cfe/trunk/test/Modules/Inputs/codegen/use.cpp +++ cfe/trunk/test/Modules/Inputs/codegen/use.cpp @@ -0,0 +1,8 @@ +#include "foo.h" +void non_modular_use_of_implicit_dtor() { + implicit_dtor d1; + uninst_implicit_dtor d2; +} +void use_of_instantiated_declaration_without_definition() { + inst(); +} Index: cfe/trunk/test/Modules/codegen-nodep.test =================================================================== --- cfe/trunk/test/Modules/codegen-nodep.test +++ cfe/trunk/test/Modules/codegen-nodep.test @@ -0,0 +1,13 @@ +RUN: rm -rf %t +REQUIRES: x86-registered-target + +RUN: %clang_cc1 -triple=x86_64-linux-gnu -fmodules-codegen -x c++ -fmodules \ +RUN: -emit-module -fmodule-name=foo \ +RUN: %S/Inputs/codegen-nodep/foo.modulemap -o - \ +RUN: | llvm-bcanalyzer - -dump \ +RUN: | FileCheck %s + +Ensure there's only one modular codegen decl - the sentinel plain inline +function, not any for the function template. + +CHECK: Index: cfe/trunk/test/Modules/codegen.test =================================================================== --- cfe/trunk/test/Modules/codegen.test +++ cfe/trunk/test/Modules/codegen.test @@ -3,8 +3,25 @@ RUN: %clang_cc1 -triple=x86_64-linux-gnu -fmodules-codegen -x c++ -fmodules -emit-module -fmodule-name=foo %S/Inputs/codegen/foo.modulemap -o %t/foo.pcm -RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - %t/foo.pcm | FileCheck %s +RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - %t/foo.pcm | FileCheck --check-prefix=FOO --check-prefix=BOTH %s +RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - -fmodules -fmodule-file=%t/foo.pcm %S/Inputs/codegen/use.cpp | FileCheck --check-prefix=BOTH --check-prefix=USE %s -CHECK: $_Z2f1PKcz = comdat any -CHECK: define weak_odr void @_Z2f1PKcz(i8* %fmt, ...) #{{[0-9]+}} comdat -CHECK: call void @llvm.va_start(i8* %{{[a-zA-Z0-9]*}}) +FOO: $_Z2f1PKcz = comdat any +FOO: $_ZN13implicit_dtorD1Ev = comdat any +USE: $_Z4instIiEvv = comdat any +FOO: $_ZN13implicit_dtorD2Ev = comdat any +FOO: define weak_odr void @_Z2f1PKcz(i8* %fmt, ...) #{{[0-9]+}} comdat +FOO: call void @llvm.va_start(i8* %{{[a-zA-Z0-9]*}}) + +Test that implicit special members are emitted into the FOO module if they're +ODR used there, otherwise emit them linkonce_odr as usual in the use. + +FIXME: Proactively instantiate any valid implicit special members to emit them into the module object. + +FOO: define weak_odr void @_ZN13implicit_dtorD1Ev +FOO: define weak_odr void @_Z4instIfEvv +FOO: define weak_odr void @_ZN13implicit_dtorD2Ev + +USE: define linkonce_odr void @_ZN20uninst_implicit_dtorD1Ev +USE: define linkonce_odr void @_Z4instIiEvv +USE: define linkonce_odr void @_ZN20uninst_implicit_dtorD2Ev