[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