https://github.com/atetubou updated https://github.com/llvm/llvm-project/pull/209997
>From b0c8b27062988285159c7cc6a0a55ff0bf161bab Mon Sep 17 00:00:00 2001 From: Takuto Ikuta <[email protected]> Date: Thu, 16 Jul 2026 16:37:25 +0900 Subject: [PATCH] [clang][CodeGen] Trigger AST lookup for libfunction builtins 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. --- clang/lib/CodeGen/CGBuiltin.cpp | 19 +++++ .../Modules/builtin-libfunction-lookup.cpp | 79 +++++++++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 clang/test/Modules/builtin-libfunction-lookup.cpp diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 37846bbb0b5ec..c0022ae14bc88 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -247,6 +247,25 @@ 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 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()) { + 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) _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
