llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang-codegen Author: Takuto Ikuta (atetubou) <details> <summary>Changes</summary> Unlike normal function calls where Sema performs name lookup during parsing and triggers lazy deserialization of AST declarations from Clang Modules (PCMs), built-in library function calls (e.g., __builtin_hypotf) bypass Sema name lookup for the target C function name (hypotf). Consequently, Clang Modules does not lazily deserialize module-defined declarations (such as MSVC UCRT's inline hypotf wrapper in corecrt_math.h) from PCM files. CodeGen then falls back to emitting direct external references to non-existent symbols like hypotf, causing unresolved symbol linker errors. This change triggers an explicit AST name lookup on TranslationUnitDecl for the target library function name in CodeGenModule::getBuiltinLibFunction. When a corresponding C-linkage FunctionDecl (isExternC) is deserialized from modules, CodeGen uses its address (GetAddrOfFunction) to properly emit its inline definition and dependent DLL import symbols (e.g. _hypotf). Added regression test in clang/test/Modules/builtin-libfunction-lookup.cpp. This fixes https://github.com/llvm/llvm-project/issues/209989 Assisted-by: Gemini --- Full diff: https://github.com/llvm/llvm-project/pull/209997.diff 2 Files Affected: - (modified) clang/lib/CodeGen/CGBuiltin.cpp (+20) - (added) clang/test/Modules/builtin-libfunction-lookup.cpp (+79) ``````````diff diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 37846bbb0b5ec..6c4742b3853f2 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -247,6 +247,26 @@ llvm::Constant *CodeGenModule::getBuiltinLibFunction(const FunctionDecl *FD, Name = Context.BuiltinInfo.getName(BuiltinID).substr(10); } + // Look up the corresponding standard library C function in the AST. Unlike + // normal function calls where Sema performs name lookup and lazily + // deserializes declarations from Clang Modules (PCMs), built-in library + // function calls (e.g. __builtin_hypotf) bypass Sema name lookup for the C + // function name ("hypotf"). Explicitly looking up the name in + // TranslationUnitDecl triggers ASTReader to lazily deserialize any + // module-defined declaration (such as MSVC UCRT's inline hypotf wrapper). If + // a definition is found, use GetAddrOfFunction to properly emit its + // definition and dependencies. + DeclarationName DecName = &Context.Idents.get(Name); + DeclContext::lookup_result Decls = + Context.getTranslationUnitDecl()->lookup(DecName); + for (NamedDecl *ND : Decls) { + if (auto *TargetFD = dyn_cast<FunctionDecl>(ND)) { + if (TargetFD->isExternC() && TargetFD->hasBody()) { + return GetAddrOfFunction(TargetFD); + } + } + } + llvm::FunctionType *Ty = cast<llvm::FunctionType>(getTypes().ConvertType(FD->getType())); diff --git a/clang/test/Modules/builtin-libfunction-lookup.cpp b/clang/test/Modules/builtin-libfunction-lookup.cpp new file mode 100644 index 0000000000000..b764d7274a8d7 --- /dev/null +++ b/clang/test/Modules/builtin-libfunction-lookup.cpp @@ -0,0 +1,79 @@ +// Test that calling built-in library functions like __builtin_hypotf under Clang Modules +// triggers AST name lookup for the target C function (hypotf). This ensures that +// module-defined inline wrappers (e.g. MSVC UCRT's hypotf wrapper calling _hypotf) +// are lazily deserialized from PCMs rather than emitting external non-existent function calls. +// +// RUN: rm -rf %t +// RUN: split-file %s %t +// RUN: cd %t +// +// RUN: %clang_cc1 -xc++ -emit-module -fmodules -fmodule-name=ucrt -fmodule-map-file=ucrt.modulemap -triple x86_64-pc-windows-msvc -fms-extensions -I. ucrt.modulemap -o ucrt.pcm +// RUN: %clang_cc1 -xc++ -emit-module -fmodules -fmodule-name=std -fmodule-map-file=std.modulemap -fmodule-file=ucrt=ucrt.pcm -triple x86_64-pc-windows-msvc -fms-extensions -I. std.modulemap -o std.pcm +// RUN: %clang_cc1 -xc++ -emit-llvm -fmodules -fmodule-map-file=std.modulemap -fmodule-map-file=ucrt.modulemap -fmodule-file=std=std.pcm -fmodule-file=ucrt=ucrt.pcm -triple x86_64-pc-windows-msvc -fms-extensions -I. main.cc -o - | FileCheck %s + +//--- corecrt_math.h +#ifndef MOCK_CORECRT_MATH_H +#define MOCK_CORECRT_MATH_H +extern "C" { +__declspec(dllimport) float __cdecl _hypotf(float x, float y); +inline float __cdecl hypotf(float x, float y) { + return _hypotf(x, y); +} +} +#endif + +//--- math.h +#ifndef MOCK_MATH_H +#define MOCK_MATH_H +#include "corecrt_math.h" +#endif + +//--- __math/hypot.h +#ifndef MOCK_MATH_HYPOT_H +#define MOCK_MATH_HYPOT_H +inline float hypot(float x, float y) { + return __builtin_hypotf(x, y); +} +#endif + +//--- cmath +#ifndef MOCK_CMATH +#define MOCK_CMATH +#include "math.h" +#include "__math/hypot.h" +#endif + +//--- std.modulemap +module std { + module cmath { + header "cmath" + export * + } + module math_hypot { + header "__math/hypot.h" + export * + } +} + +//--- ucrt.modulemap +module ucrt { + module math { + header "math.h" + export * + } + module corecrt_math { + header "corecrt_math.h" + export * + } +} + +//--- main.cc +#include "cmath" + +float test_call(float x, float y) { + return hypot(x, y); +} + +// CHECK: define linkonce_odr dso_local float @hypotf(float noundef %{{.*}}, float noundef %{{.*}}) +// CHECK: call float @_hypotf(float noundef %{{.*}}, float noundef %{{.*}}) +// CHECK: declare dllimport float @_hypotf(float noundef, float noundef) `````````` </details> https://github.com/llvm/llvm-project/pull/209997 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
