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

Reply via email to