Index: clang/include/clang/Basic/CodeGenOptions.def =================================================================== --- clang/include/clang/Basic/CodeGenOptions.def +++ clang/include/clang/Basic/CodeGenOptions.def @@ -506,6 +506,10 @@ /// non-deleting destructors. (No effect on Microsoft ABI.) CODEGENOPT(CtorDtorReturnThis, 1, 0) +/// Whether to import function definitions from inter module function +/// definitions. +CODEGENOPT(ImportInterModuleFunctionDefs, 1, 0) + #undef CODEGENOPT #undef ENUM_CODEGENOPT #undef VALUE_CODEGENOPT Index: clang/include/clang/Driver/Options.td =================================================================== --- clang/include/clang/Driver/Options.td +++ clang/include/clang/Driver/Options.td @@ -545,6 +545,8 @@ defvar std = !strconcat("LangStandard::getLangStandardForKind(", lang_std.KeyPath, ")"); +defvar opt_level = CodeGenOpts<"OptimizationLevel">; + ///////// // Options @@ -2355,6 +2357,11 @@ def fmodule_output : Flag<["-"], "fmodule-output">, Flags<[NoXarchOption, CC1Option]>, HelpText<"Save intermediate module file results when compiling a standard C++ module unit.">; +defm import_inter_module_function_defs : BoolOption<"f", "import-inter-module-function-defs", + CodeGenOpts<"ImportInterModuleFunctionDefs">, Default, + PosFlag, + NegFlag>; + def fmodules_prune_interval : Joined<["-"], "fmodules-prune-interval=">, Group, Flags<[CC1Option]>, MetaVarName<"">, HelpText<"Specify the interval (in seconds) between attempts to prune the module cache">, Index: clang/lib/CodeGen/CodeGenModule.cpp =================================================================== --- clang/lib/CodeGen/CodeGenModule.cpp +++ clang/lib/CodeGen/CodeGenModule.cpp @@ -3541,7 +3541,8 @@ if (getFunctionLinkage(GD) != llvm::Function::AvailableExternallyLinkage) return true; const auto *F = cast(GD.getDecl()); - if (CodeGenOpts.OptimizationLevel == 0 && !F->hasAttr()) + if (!CodeGenOpts.ImportInterModuleFunctionDefs && + !F->hasAttr()) return false; if (F->hasAttr() && !F->hasAttr()) { Index: clang/lib/Driver/ToolChains/Clang.cpp =================================================================== --- clang/lib/Driver/ToolChains/Clang.cpp +++ clang/lib/Driver/ToolChains/Clang.cpp @@ -3850,6 +3850,10 @@ Args.ClaimAllArgs(options::OPT_fmodule_output); Args.ClaimAllArgs(options::OPT_fmodule_output_EQ); + if (Args.hasFlag(options::OPT_fno_import_inter_module_function_defs, + options::OPT_fimport_inter_module_function_defs, false)) + CmdArgs.push_back("-fno-import-inter-module-function-defs"); + return HaveModules; } Index: clang/test/Driver/module-no-import-from-other-tu.cppm =================================================================== --- /dev/null +++ clang/test/Driver/module-no-import-from-other-tu.cppm @@ -0,0 +1,6 @@ +// RUN: %clang -O3 -fno-import-inter-module-function-defs -std=c++20 \ +// RUN: %s -### 2>&1 | FileCheck %s + +export module x; + +// CHECK: -fno-import-inter-module-function-defs Index: clang/test/Modules/inter-module-imports-function-defs.cppm =================================================================== --- /dev/null +++ clang/test/Modules/inter-module-imports-function-defs.cppm @@ -0,0 +1,57 @@ +// RUN: rm -rf %t +// RUN: split-file %s %t +// RUN: cd %t +// +// RUN: %clang_cc1 -std=c++20 -triple %itanium_abi_triple %t/a.cppm \ +// RUN: -emit-module-interface -o %t/a.pcm +// RUN: %clang_cc1 -std=c++20 -triple %itanium_abi_triple %t/b.cppm \ +// RUN: -emit-module-interface -fprebuilt-module-path=%t -o %t/b.pcm +// RUN: %clang_cc1 -std=c++20 -triple %itanium_abi_triple %t/c.cppm \ +// RUN: -emit-module-interface -fprebuilt-module-path=%t -o %t/c.pcm +// RUN: %clang_cc1 -std=c++20 -triple %itanium_abi_triple %t/c.pcm -S \ +// RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %t/c.cppm --check-prefix=NO-IMPORT +// +// RUN: %clang_cc1 -std=c++20 -triple %itanium_abi_triple -O3 %t/a.cppm \ +// RUN: -emit-module-interface -o %t/a.pcm +// RUN: %clang_cc1 -std=c++20 -triple %itanium_abi_triple -O3 %t/b.cppm \ +// RUN: -emit-module-interface -fprebuilt-module-path=%t -o %t/b.pcm +// RUN: %clang_cc1 -std=c++20 -triple %itanium_abi_triple -O3 %t/c.cppm \ +// RUN: -emit-module-interface -fprebuilt-module-path=%t -o %t/c.pcm +// RUN: %clang_cc1 -std=c++20 -triple %itanium_abi_triple -O3 %t/c.pcm \ +// RUN: -S -emit-llvm -disable-llvm-passes -o - | FileCheck %t/c.cppm --check-prefix=IMPORT +// +// RUN: %clang_cc1 -std=c++20 -triple %itanium_abi_triple -O3 \ +// RUN: %t/a.cppm -emit-module-interface -o %t/a.pcm +// RUN: %clang_cc1 -std=c++20 -triple %itanium_abi_triple -O3 \ +// RUN: %t/b.cppm -emit-module-interface -fprebuilt-module-path=%t -o %t/b.pcm +// RUN: %clang_cc1 -std=c++20 -triple %itanium_abi_triple -O3 \ +// RUN: %t/c.cppm -emit-module-interface -fprebuilt-module-path=%t -o %t/c.pcm +// RUN: %clang_cc1 -std=c++20 -triple %itanium_abi_triple -O3 \ +// RUN: -fno-import-inter-module-function-defs %t/c.pcm \ +// RUN: -S -emit-llvm -disable-llvm-passes -o - | FileCheck %t/c.cppm --check-prefix=NO-IMPORT + +//--- a.cppm +export module a; +export int a() { + return 43; +} + +//--- b.cppm +export module b; +export import a; +export int b() { + return 43 + a(); +} + +//--- c.cppm +export module c; +export import b; +export int c() { + return 43 + b() + a(); +} + +// NO-IMPORT: declare{{.*}}@_ZW1b1bv +// NO-IMPORT: declare{{.*}}@_ZW1a1av + +// IMPORT: define available_externally{{.*}}@_ZW1b1bv +// IMPORT: define available_externally{{.*}}@_ZW1a1av