Index: include/clang/AST/ASTContext.h =================================================================== --- include/clang/AST/ASTContext.h +++ include/clang/AST/ASTContext.h @@ -2494,7 +2494,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, bool *ForModuleFile = nullptr); const CXXConstructorDecl * getCopyConstructorForExceptionObject(CXXRecordDecl *RD); Index: include/clang/Serialization/ASTReader.h =================================================================== --- include/clang/Serialization/ASTReader.h +++ include/clang/Serialization/ASTReader.h @@ -715,7 +715,7 @@ /// the consumer eagerly. SmallVector EagerlyDeserializedDecls; - SmallVector ModularCodegenDecls; + Optional> ModularCodegenDecls; /// \brief The IDs of all tentative definitions stored in the chain. /// Index: lib/AST/ASTContext.cpp =================================================================== --- lib/AST/ASTContext.cpp +++ lib/AST/ASTContext.cpp @@ -8982,7 +8982,8 @@ *this, basicGVALinkageForVariable(*this, VD), VD); } -bool ASTContext::DeclMustBeEmitted(const Decl *D, bool ForModularCodegen) { +bool ASTContext::DeclMustBeEmitted(const Decl *D, bool *ForModuleFile) { + assert(!ForModuleFile || !*ForModuleFile); if (const VarDecl *VD = dyn_cast(D)) { if (!VD->isFileVarDecl()) return false; @@ -9048,8 +9049,11 @@ GVALinkage Linkage = GetGVALinkageForFunction(FD); - if (Linkage == GVA_DiscardableODR && ForModularCodegen) + if ((Linkage == GVA_DiscardableODR || Linkage == GVA_StrongExternal) && + ForModuleFile) { + *ForModuleFile = true; return true; + } // static, static inline, always_inline, and extern inline functions can // always be deferred. Normal inline functions can be deferred in C99/C++. Index: lib/Serialization/ASTReader.cpp =================================================================== --- lib/Serialization/ASTReader.cpp +++ lib/Serialization/ASTReader.cpp @@ -2777,9 +2777,11 @@ 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) + if (F.Kind == MK_MainFile) { + ModularCodegenDecls.emplace(); for (unsigned I = 0, N = Record.size(); I != N; ++I) - EagerlyDeserializedDecls.push_back(getGlobalDeclID(F, Record[I])); + ModularCodegenDecls->push_back(getGlobalDeclID(F, Record[I])); + } break; case SPECIAL_TYPES: @@ -7001,8 +7003,15 @@ // Ensure that we've loaded all potentially-interesting declarations // that need to be eagerly loaded. - for (auto ID : EagerlyDeserializedDecls) - GetDecl(ID); + auto GetDecls = [&](const SmallVector &V) { + for (auto ID : V) + GetDecl(ID); + }; + if (ModularCodegenDecls) + GetDecls(*ModularCodegenDecls); + else + GetDecls(EagerlyDeserializedDecls); + ModularCodegenDecls = None; EagerlyDeserializedDecls.clear(); while (!InterestingDecls.empty()) { Index: lib/Serialization/ASTWriterDecl.cpp =================================================================== --- lib/Serialization/ASTWriterDecl.cpp +++ lib/Serialization/ASTWriterDecl.cpp @@ -2153,7 +2153,8 @@ /// 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, bool *ForModuleFile) { + assert(!ForModuleFile || !*ForModuleFile); // An ObjCMethodDecl is never considered as "required" because its // implementation container always is. @@ -2169,7 +2170,7 @@ return false; } - return Context.DeclMustBeEmitted(D, ModularCode); + return Context.DeclMustBeEmitted(D, ForModuleFile); } void ASTWriter::WriteDecl(ASTContext &Context, Decl *D) { @@ -2213,11 +2214,13 @@ // 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)) - EagerlyDeserializedDecls.push_back(ID); - else if (Context.getLangOpts().ModularCodegen && WritingModule && - isRequiredDecl(D, Context, true, true)) - ModularCodegenDecls.push_back(ID); + bool ForModuleFile = false; + if (isRequiredDecl(D, Context, WritingModule, + Context.getLangOpts().ModularCodegen && WritingModule + ? &ForModuleFile + : nullptr)) + (ForModuleFile ? ModularCodegenDecls : EagerlyDeserializedDecls) + .push_back(ID); } void ASTRecordWriter::AddFunctionDefinition(const FunctionDecl *FD) { Index: test/CodeGenCXX/modules-ts.cppm =================================================================== --- test/CodeGenCXX/modules-ts.cppm +++ test/CodeGenCXX/modules-ts.cppm @@ -3,14 +3,14 @@ module FooBar; +// CHECK-LABEL: define weak_odr void @_Z2f2v( +inline void f2() { } + export { // CHECK-LABEL: define i32 @_Z1fv( int f() { return 0; } } -// CHECK-LABEL: define weak_odr void @_Z2f2v( -inline void f2() { } - // FIXME: Emit global variables and their initializers with this TU. // Emit an initialization function that other TUs can call, with guard variable. Index: test/Modules/Inputs/codegen/foo.h =================================================================== --- test/Modules/Inputs/codegen/foo.h +++ test/Modules/Inputs/codegen/foo.h @@ -1,3 +1,4 @@ +asm(".byte 42"); void f1(int &); static void f2() {} inline void foo() { Index: test/Modules/codegen.test =================================================================== --- test/Modules/codegen.test +++ test/Modules/codegen.test @@ -12,14 +12,12 @@ RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - -O2 -disable-llvm-passes %t/bar.pcm -fmodule-file=%t/foo.pcm | FileCheck --check-prefix=BAR-CMN --check-prefix=BAR-OPT %s RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - -O2 -disable-llvm-passes -fmodules -fmodule-file=%t/foo.pcm -fmodule-file=%t/bar.pcm %S/Inputs/codegen/use.cpp | FileCheck --check-prefix=USE-CMN --check-prefix=USE-OPT %s -FOO-NOT: comdat +FOO-NOT: {{comdat|module asm}} FOO: $_Z3foov = comdat any FOO: $_Z4foo2v = comdat any FOO: $_ZZ3foovE1i = comdat any FOO: @_ZZ3foovE1i = linkonce_odr global i32 0, comdat FOO-NOT: {{comdat|define|declare}} -FOO: define void @_Z7foo_extv() -FOO-NOT: {{define|declare}} FOO: define weak_odr void @_Z3foov() #{{[0-9]+}} comdat FOO-NOT: {{define|declare}} FOO: declare void @_Z2f1Ri(i32* @@ -31,26 +29,37 @@ FOO: define weak_odr void @_Z4foo2v() #{{[0-9]+}} comdat FOO-NOT: {{define|declare}} +FOO: define void @_Z7foo_extv() +FOO-NOT: {{define|declare}} -BAR-CMN-NOT: comdat +BAR-CMN-NOT: {{comdat|module asm}} BAR-CMN: $_Z3barv = comdat any +BAR-CMN-NOT: comdat +BAR-OPT: $_ZZ3foovE1i = comdat any +BAR-OPT-NOT: comdat BAR-OPT: @_ZZ3foovE1i = linkonce_odr global i32 0, comdat -BAR-CMN-NOT: {{comdat|define|declare}} +BAR-CMN-NOT: {{define|declare}} BAR-CMN: define weak_odr void @_Z3barv() #{{[0-9]+}} comdat BAR-CMN-NOT: {{define|declare}} BAR: declare void @_Z3foov() +BAR-NOT: {{define|declare}} Include all the available_externally definitions required for bar (foo -> f2) BAR-OPT: define available_externally void @_Z3foov() -BAR-CMN-NOT: {{define|declare}} +BAR-OPT-NOT: {{define|declare}} BAR-OPT: declare void @_Z2f1Ri(i32* BAR-OPT-NOT: {{define|declare}} BAR-OPT: define available_externally void @_ZL2f2v() BAR-OPT-NOT: {{define|declare}} +USE-CMN-NOT: {{comdat|module asm}} +USE-CMN: module asm ".byte 42" +USE-CMN-NOT: {{comdat|module asm}} +USE-OPT: $_ZZ3foovE1i = comdat any +USE-OPT-CMN-NOT: {{comdat}} USE-OPT: @_ZZ3foovE1i = linkonce_odr global i32 0, comdat -USE-CMN-NOT: {{comdat|define|declare}} +USE-CMN-NOT: {{define|declare}} USE-CMN: define i32 @main() USE-CMN-NOT: {{define|declare}} USE: declare void @_Z3barv()