llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang-codegen Author: Mathew Joseph (mathew1046) <details> <summary>Changes</summary> Importing a named module before including a GNU-inline wrapper header can retain a definition owned by the global module fragment. The foreign-module body restriction then suppresses its available-external body, leaving a call that cannot be inlined and can fail to link. Allow GNU-inline definitions owned by global module fragments through that restriction while preserving their linkage and the remaining emission checks. Add regression coverage for both declaration orders at `-O0` and `-O2`, named-module ownership, and escaping function addresses, plus a release note. Testing: - Built assertion-enabled Clang 24 from upstream `f4bf388b08af`. - Confirmed the new regression fails before the fix and passes afterward. - Ran the complete `Modules`, `CodeGen`, and `CodeGenCXX` suites locally: 4,521 passed, 8 expected failures, 3,884 unsupported, and no unexpected failures. - Verified the original reproducer links in both declaration orders and both executables return 42. - Verified address-taking leaves the wrapper symbols undefined in object files at `-O0` and `-O2`. - Formatting and whitespace checks passed. Testing used an X86-only Linux build; tests requiring unavailable targets or platform features were skipped. Fixes #<!-- -->228800 --- Full diff: https://github.com/llvm/llvm-project/pull/228962.diff 3 Files Affected: - (modified) clang/docs/ReleaseNotes.md (+4) - (modified) clang/lib/CodeGen/CodeGenModule.cpp (+2-1) - (added) clang/test/CodeGenCXX/gnu-inline-global-module-fragment.cppm (+75) ``````````diff diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index 7ec126a065ae5..b76114c04d67c 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -645,6 +645,10 @@ features cannot lower the translation-unit ABI level; #### Bug Fixes to C++ Support +- Fixed an undefined reference to a GNU-inline function when its defining + header is included after importing a C++20 named module whose global module + fragment includes the same header. (#GH228800) + - Fixed lambdas with specifiers or attributes after the capture list being misparsed as function declarations in direct-initialization contexts under `-fms-extensions` or in HLSL mode. diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index b4ebc6b6abff0..fb43a103f9c92 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -5069,7 +5069,8 @@ bool CodeGenModule::shouldEmitFunction(GlobalDecl GD) { // We don't import function bodies from other named module units since that // behavior may break ABI compatibility of the current unit. if (const Module *M = F->getOwningModule(); - M && M->getTopLevelModule()->isNamedModule() && + M && !(M->isGlobalModule() && F->hasAttr<GNUInlineAttr>()) && + M->getTopLevelModule()->isNamedModule() && getContext().getCurrentNamedModule() != M->getTopLevelModule()) { // There are practices to mark template member function as always-inline // and mark the template as extern explicit instantiation but not give diff --git a/clang/test/CodeGenCXX/gnu-inline-global-module-fragment.cppm b/clang/test/CodeGenCXX/gnu-inline-global-module-fragment.cppm new file mode 100644 index 0000000000000..d44cba73b78e7 --- /dev/null +++ b/clang/test/CodeGenCXX/gnu-inline-global-module-fragment.cppm @@ -0,0 +1,75 @@ +// RUN: split-file %s %t +// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 %t/M.cppm -emit-module-interface -o %t/M.pcm +// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 -fprebuilt-module-path=%t %t/use.cpp -emit-llvm -disable-llvm-passes -o - | FileCheck %s --check-prefixes=RAW,O0 +// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 -fprebuilt-module-path=%t -DINCLUDE_FIRST %t/use.cpp -emit-llvm -disable-llvm-passes -o - | FileCheck %s --check-prefixes=RAW,O0 +// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 -fprebuilt-module-path=%t -O2 %t/use.cpp -emit-llvm -disable-llvm-passes -o - | FileCheck %s --check-prefixes=RAW,O2 +// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 -fprebuilt-module-path=%t -O2 -DINCLUDE_FIRST %t/use.cpp -emit-llvm -disable-llvm-passes -o - | FileCheck %s --check-prefixes=RAW,O2 +// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 -fprebuilt-module-path=%t %t/use.cpp -emit-llvm -o - | FileCheck %s --check-prefix=INLINE --implicit-check-not=always_wrapper +// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 -fprebuilt-module-path=%t -DINCLUDE_FIRST %t/use.cpp -emit-llvm -o - | FileCheck %s --check-prefix=INLINE --implicit-check-not=always_wrapper +// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 -fprebuilt-module-path=%t -O2 %t/use.cpp -emit-llvm -o - | FileCheck %s --check-prefix=INLINE --implicit-check-not=always_wrapper +// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 -fprebuilt-module-path=%t -O2 -DINCLUDE_FIRST %t/use.cpp -emit-llvm -o - | FileCheck %s --check-prefix=INLINE --implicit-check-not=always_wrapper +// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 -fprebuilt-module-path=%t %t/address.cpp -emit-llvm -o - | FileCheck %s --check-prefix=ADDRESS +// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 -fprebuilt-module-path=%t -DINCLUDE_FIRST %t/address.cpp -emit-llvm -o - | FileCheck %s --check-prefix=ADDRESS +// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 -fprebuilt-module-path=%t -O2 %t/address.cpp -emit-llvm -o - | FileCheck %s --check-prefix=ADDRESS +// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 -fprebuilt-module-path=%t -O2 -DINCLUDE_FIRST %t/address.cpp -emit-llvm -o - | FileCheck %s --check-prefix=ADDRESS + +// RAW-DAG: define available_externally{{.*}} @always_wrapper( +// RAW-DAG: attributes #{{[0-9]+}} = { alwaysinline +// RAW-DAG: declare{{.*}} @{{.*}}named_wrapper{{.*}}( +// O0-DAG: declare{{.*}} @plain_wrapper( +// O2-DAG: define available_externally{{.*}} @plain_wrapper( +// INLINE-LABEL: define{{.*}} @test_always( +// INLINE: call{{.*}} @real_fn( +// ADDRESS-LABEL: define{{.*}} @address_always( +// ADDRESS: ret ptr @always_wrapper +// ADDRESS-LABEL: define{{.*}} @address_plain( +// ADDRESS: ret ptr @plain_wrapper + +//--- wrappers.h +extern "C" { +long real_fn(long); + +extern inline __attribute__((gnu_inline, always_inline)) +long always_wrapper(long value) { return real_fn(value); } + +extern inline __attribute__((gnu_inline)) +long plain_wrapper(long value) { return real_fn(value); } +} + +//--- M.cppm +module; +#include "wrappers.h" +export module M; + +export extern inline __attribute__((gnu_inline, always_inline)) +long named_wrapper(long value) { return value + 1; } + +//--- use.cpp +#ifdef INCLUDE_FIRST +#include "wrappers.h" +import M; +#else +import M; +#include "wrappers.h" +#endif + +extern "C" long test_always() { return always_wrapper(41); } +extern "C" long test_plain() { return plain_wrapper(42); } +extern "C" long test_named() { return named_wrapper(43); } + +//--- address.cpp +#ifdef INCLUDE_FIRST +#include "wrappers.h" +import M; +#else +import M; +#include "wrappers.h" +#endif + +extern "C" auto address_always() -> long (*)(long) { + return &always_wrapper; +} + +extern "C" auto address_plain() -> long (*)(long) { + return &plain_wrapper; +} \ No newline at end of file `````````` </details> https://github.com/llvm/llvm-project/pull/228962 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
