[libcxx-commits] [libcxx] [libc++] Fix hypotf linker error with Clang modules on Windows UCRT (PR #209403)
via libcxx-commits
libcxx-commits at lists.llvm.org
Tue Jul 14 02:05:25 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-libcxx
Author: Junji Watanabe (Jwata)
<details>
<summary>Changes</summary>
This commit resolves an undefined symbol `hypotf` linking error that occurs when compiling standard C++ headers with Clang modules enabled targeting Windows with MSVC C-Runtime (UCRT).
You can find the minimal repro at Chromium here: https://crrev.com/c/8085003
### Context & Cause
Under Windows UCRT, the import libraries (`ucrt.lib`/`ucrtd.lib`) do not export the symbol `hypotf` directly. Instead, they export `_hypotf`. The UCRT header `corecrt_math.h` declares `hypotf` as an inline wrapper function:
```cpp
_Check_return_ __inline float __CRTDECL hypotf(_In_ float _X, _In_ float _Y) {
return _hypotf(_X, _Y);
}
```
When building libc++ with Clang modules enabled at Chromium, the `std_core.math.hypot` submodule (mapping to `__math/hypot.h`) is precompiled into a binary module file in isolation.
Because `__math/hypot.h` does not include `<math.h>` or `<cmath>`, Clang's front-end parses the submodule without visibility of the UCRT inline declaration of `hypotf`.
1. During AST resolution of `std::hypot` (defined using `__builtin_hypotf`), the front-end fails to bind the builtin to the inline wrapper `hypotf` since it is not present in the symbol table.
2. Clang passes `__builtin_hypotf` down to the LLVM backend.
3. The LLVM backend's `TargetLibraryInfo` config for MSVC expects the standard `hypotf` symbol to be available, and thus lowers it to a direct external call to the symbol `hypotf`.
4. This results in the object file containing a direct external reference to `hypotf` rather than an imported call to `__imp__hypotf`.
5. The link phase fails because no `hypotf` symbol exists in `ucrt.lib`.
### Solution
We bypass `__builtin_hypotf` and `__builtin_hypotl` on Windows targeting UCRT (when `_LIBCPP_MSVCRT` is defined):
1. **For `float`**: We explicitly declare the imported UCRT `_hypotf` function (using the `_LIBCPP_CRT_FUNC` macro to dynamically support both static `/MT` and DLL `/MD` runtime linking) and route `std::hypot(float, float)` to it.
2. **For `long double`**: Since `long double` is represented as a 64-bit float (identical to `double`) on MSVC, and `_hypotl` is also inline-only in UCRT, we promote the arguments to `double` and forward to the `double` implementation (which maps to the exported `hypot` symbol).
Assisted-by: Gemini
---
Full diff: https://github.com/llvm/llvm-project/pull/209403.diff
1 Files Affected:
- (modified) libcxx/include/__math/hypot.h (+17-1)
``````````diff
diff --git a/libcxx/include/__math/hypot.h b/libcxx/include/__math/hypot.h
index 2b12d7be21072..37788e542fa66 100644
--- a/libcxx/include/__math/hypot.h
+++ b/libcxx/include/__math/hypot.h
@@ -27,11 +27,23 @@
_LIBCPP_PUSH_MACROS
#include <__undef_macros>
+#if defined(_LIBCPP_MSVCRT)
+extern "C" {
+_LIBCPP_CRT_FUNC float __cdecl _hypotf(float, float);
+}
+#endif
+
_LIBCPP_BEGIN_NAMESPACE_STD
namespace __math {
-inline _LIBCPP_HIDE_FROM_ABI float hypot(float __x, float __y) _NOEXCEPT { return __builtin_hypotf(__x, __y); }
+inline _LIBCPP_HIDE_FROM_ABI float hypot(float __x, float __y) _NOEXCEPT {
+#if defined(_LIBCPP_MSVCRT)
+ return ::_hypotf(__x, __y);
+#else
+ return __builtin_hypotf(__x, __y);
+#endif
+}
template <class = int>
_LIBCPP_HIDE_FROM_ABI double hypot(double __x, double __y) _NOEXCEPT {
@@ -39,7 +51,11 @@ _LIBCPP_HIDE_FROM_ABI double hypot(double __x, double __y) _NOEXCEPT {
}
inline _LIBCPP_HIDE_FROM_ABI long double hypot(long double __x, long double __y) _NOEXCEPT {
+#if defined(_LIBCPP_MSVCRT)
+ return (long double)__math::hypot((double)__x, (double)__y);
+#else
return __builtin_hypotl(__x, __y);
+#endif
}
template <class _A1, class _A2, __enable_if_t<is_arithmetic<_A1>::value && is_arithmetic<_A2>::value, int> = 0>
``````````
</details>
https://github.com/llvm/llvm-project/pull/209403
More information about the libcxx-commits
mailing list