[libcxx-commits] [libcxx] [libc++] Do not define std::nothrow with VCRuntime ABI (PR #217694)
Corentin Kerisit via libcxx-commits
libcxx-commits at lists.llvm.org
Thu Aug 20 10:00:08 PDT 2026
https://github.com/cerisier created https://github.com/llvm/llvm-project/pull/217694
## Motivation
Static libc++ builds that use the VCRuntime ABI currently provide a strong definition of `std::nothrow` in `libc++.lib`, even though the Microsoft runtime provides the same object in `msvcrt.lib(std_nothrow.obj)`. A link that deliberately includes the complete libc++ archive, for example with `/WHOLEARCHIVE:libc++.lib`, therefore fails with a duplicate definition of `?nothrow at std@@3Unothrow_t at 1@B`.
This is not a request to weaken the link or stop using static libc++. The two ABI libraries must not claim ownership of the same object.
## Invariant / contract
When libc++ is configured with `_LIBCPP_ABI_VCRUNTIME`, VCRuntime owns the global allocation ABI, including `std::nothrow`. libc++ must consume that ABI rather than emit a second strong definition.
libc++ already applies this contract in `libcxx/src/new.cpp`: the global new/delete implementation is excluded when either libstdc++ or VCRuntime supplies the ABI. `std::nothrow` needs the same ownership guard.
## Root cause
Commit `3956a34e4fc6` moved non-operator-new definitions from `new.cpp` to `new_helpers.cpp`. The moved `std::nothrow` definition retained the `__GLIBCXX__` exclusion, but it did not retain the equivalent `_LIBCPP_ABI_VCRUNTIME` exclusion used by `new.cpp`.
As a result, the VCRuntime configuration has inconsistent ownership: `new.cpp` defers to VCRuntime, while `new_helpers.cpp` still defines `std::nothrow`.
## Change
Guard the `std::nothrow` definition with both existing ABI-provider conditions:
- do not define it when libstdc++ owns it;
- do not define it when VCRuntime owns it.
The change is limited to ABI configurations that already delegate the allocation ABI. Other libc++ configurations are unchanged.
Add a clang-cl vendor test that inspects the built static archive. It proves that the VCRuntime build no longer defines the decorated `std::nothrow` symbol and also checks that the neighboring libc++ `__throw_bad_alloc` helper remains present, so the test cannot pass merely because `new_helpers.cpp` was omitted wholesale.
## Tests
- `git diff --check`
- Downstream Windows x86_64 and ARM64 full LLVM links reproduced the duplicate between `msvcrt.lib(std_nothrow.obj)` and `libc++.lib(new_helpers.obj)` before the guard.
- The same full links completed when the VCRuntime-owned `std::nothrow` definition was excluded; the resulting executables were native AMD64 and ARM64 PE/COFF respectively.
- The new `libcxx/test/libcxx/vendor/clang-cl/static-lib-nothrow.sh.cpp` test was added for upstream Windows libc++ CI. It was not run locally because this host does not provide a Windows MSVC execution environment.
>From d84e43e4344b043ec514c2b6be9805c61cedbcd1 Mon Sep 17 00:00:00 2001
From: Corentin Kerisit <corentin.kerisit at gmail.com>
Date: Fri, 21 Aug 2026 01:58:23 +0900
Subject: [PATCH] [libc++] Do not define std::nothrow with VCRuntime ABI
---
libcxx/src/new_helpers.cpp | 4 ++--
.../vendor/clang-cl/static-lib-nothrow.sh.cpp | 16 ++++++++++++++++
2 files changed, 18 insertions(+), 2 deletions(-)
create mode 100644 libcxx/test/libcxx/vendor/clang-cl/static-lib-nothrow.sh.cpp
diff --git a/libcxx/src/new_helpers.cpp b/libcxx/src/new_helpers.cpp
index 2119d82b3e00f..a60fa630aa771 100644
--- a/libcxx/src/new_helpers.cpp
+++ b/libcxx/src/new_helpers.cpp
@@ -11,9 +11,9 @@
namespace std { // purposefully not versioned
-#ifndef __GLIBCXX__
+#if !defined(__GLIBCXX__) && !defined(_LIBCPP_ABI_VCRUNTIME)
const nothrow_t nothrow{};
-#endif
+#endif // !defined(__GLIBCXX__) && !defined(_LIBCPP_ABI_VCRUNTIME)
#ifndef LIBSTDCXX
diff --git a/libcxx/test/libcxx/vendor/clang-cl/static-lib-nothrow.sh.cpp b/libcxx/test/libcxx/vendor/clang-cl/static-lib-nothrow.sh.cpp
new file mode 100644
index 0000000000000..0db6f5679e033
--- /dev/null
+++ b/libcxx/test/libcxx/vendor/clang-cl/static-lib-nothrow.sh.cpp
@@ -0,0 +1,16 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: target={{.+}}-windows-msvc
+
+// The VCRuntime library owns std::nothrow when libc++ uses its ABI. Defining
+// the object in libc++.lib as well makes whole-archive links fail with a
+// duplicate symbol.
+
+// RUN: llvm-nm --defined-only "%{lib-dir}/libc++.lib" | not grep -F '?nothrow at std@@3Unothrow_t at 1@B'
+// RUN: llvm-nm --defined-only "%{lib-dir}/libc++.lib" | grep -F '?__throw_bad_alloc at std@@YAXXZ'
More information about the libcxx-commits
mailing list