[libcxx-commits] [libcxx] [libc++] Add __new_at_least (PR #215813)

Nikolas Klauser via libcxx-commits libcxx-commits at lists.llvm.org
Wed Aug 12 07:46:13 PDT 2026


https://github.com/philnik777 created https://github.com/llvm/llvm-project/pull/215813

None

>From 08a0cceee65e9a2006785a8092da214072bd91e7 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Sat, 8 Aug 2026 08:13:25 +0200
Subject: [PATCH] [libc++] Add __new_at_least

---
 libcxx/include/__configuration/availability.h | 10 +++
 libcxx/include/__memory/allocate_at_least.h   | 11 +--
 libcxx/include/__memory/allocator.h           |  6 +-
 libcxx/include/__new/allocate.h               | 15 +++++
 libcxx/include/__new/new_at_least.h           | 45 +++++++++++++
 libcxx/src/support/new.ipp                    | 67 +++++++++++++++++++
 6 files changed, 143 insertions(+), 11 deletions(-)
 create mode 100644 libcxx/include/__new/new_at_least.h

diff --git a/libcxx/include/__configuration/availability.h b/libcxx/include/__configuration/availability.h
index 0709deff47ea6..d48e0146e138a 100644
--- a/libcxx/include/__configuration/availability.h
+++ b/libcxx/include/__configuration/availability.h
@@ -39,6 +39,9 @@
 // in all versions of the library are available.
 #if !_LIBCPP_HAS_VENDOR_AVAILABILITY_ANNOTATIONS
 
+#  define _LIBCPP_INTRODUCED_IN_LLVM_24 1
+#  define _LIBCPP_INTRODUCED_IN_LLVM_24_ATTRIBUTE /* nothing */
+
 #  define _LIBCPP_INTRODUCED_IN_LLVM_23 1
 #  define _LIBCPP_INTRODUCED_IN_LLVM_23_ATTRIBUTE /* nothing */
 
@@ -73,6 +76,11 @@
 
 // clang-format off
 
+// LLVM 23
+// TODO: Fill this in
+#  define _LIBCPP_INTRODUCED_IN_LLVM_24 0
+#  define _LIBCPP_INTRODUCED_IN_LLVM_24_ATTRIBUTE __attribute__((unavailable))
+
 // LLVM 23
 // TODO: Fill this in
 #  define _LIBCPP_INTRODUCED_IN_LLVM_23 0
@@ -239,6 +247,8 @@
 
 #endif
 
+#define _LIBCPP_AVAILABILITY_HAS_NEW_AT_LEAST _LIBCPP_INTRODUCED_IN_LLVM_24
+
 // This determines whether we assume that the internal std::__bad_variant_access_with_msg class
 // (which carries a message describing the cause of the failure in bad_variant_access::what())
 // provides a key function in the dylib. This allows centralizing its vtable and typeinfo instead
diff --git a/libcxx/include/__memory/allocate_at_least.h b/libcxx/include/__memory/allocate_at_least.h
index 72140d0de27af..0cb406e1941ca 100644
--- a/libcxx/include/__memory/allocate_at_least.h
+++ b/libcxx/include/__memory/allocate_at_least.h
@@ -12,6 +12,7 @@
 #include <__config>
 #include <__cstddef/size_t.h>
 #include <__memory/allocator_traits.h>
+#include <__new/allocate.h>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -19,16 +20,6 @@
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
-template <class _Pointer, class _SizeT = size_t>
-struct __allocation_result {
-  _Pointer ptr;
-  _SizeT count;
-
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __allocation_result(_Pointer __ptr, _SizeT __count)
-      : ptr(__ptr), count(__count) {}
-};
-_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(__allocation_result);
-
 #if _LIBCPP_STD_VER >= 23
 
 template <class _Alloc>
diff --git a/libcxx/include/__memory/allocator.h b/libcxx/include/__memory/allocator.h
index dd8c8647c178a..86fabb01fb7f2 100644
--- a/libcxx/include/__memory/allocator.h
+++ b/libcxx/include/__memory/allocator.h
@@ -96,7 +96,11 @@ class allocator
 #if _LIBCPP_STD_VER >= 23
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr allocation_result<_Tp*> allocate_at_least(size_t __n) {
     static_assert(sizeof(_Tp) >= 0, "cannot allocate memory for an incomplete type");
-    return {allocate(__n), __n};
+    if consteval {
+      return {allocate(__n), __n};
+    } else {
+      return std::__libcpp_allocate_at_least<_Tp>(__n);
+    }
   }
 #endif
 
diff --git a/libcxx/include/__new/allocate.h b/libcxx/include/__new/allocate.h
index b9bc2e1a50710..09c3fd040531e 100644
--- a/libcxx/include/__new/allocate.h
+++ b/libcxx/include/__new/allocate.h
@@ -13,6 +13,7 @@
 #include <__cstddef/max_align_t.h>
 #include <__cstddef/size_t.h>
 #include <__new/align_val_t.h>
+#include <__new/new_at_least.h>
 #include <__type_traits/type_identity.h>
 #include <__utility/element_count.h>
 
@@ -42,6 +43,20 @@ __libcpp_allocate(__element_count __n, [[__maybe_unused__]] size_t __align = _LI
   return static_cast<_Tp*>(__builtin_operator_new(__size));
 }
 
+template <class _Tp>
+_LIBCPP_NO_CFI __allocation_result<_Tp*>
+__libcpp_allocate_at_least(__element_count __n, [[__maybe_unused__]] size_t __align = _LIBCPP_ALIGNOF(_Tp)) {
+  size_t __size = static_cast<size_t>(__n) * sizeof(_Tp);
+#if _LIBCPP_HAS_ALIGNED_ALLOCATION
+  if (__is_overaligned_for_new(__align)) {
+    auto [__ptr, __count] = std::__new_at_least(__size, static_cast<align_val_t>(__align));
+    return {static_cast<_Tp*>(__ptr), __count / sizeof(_Tp)};
+  }
+#endif
+  auto [__ptr, __count] = std::__new_at_least(__size);
+  return {static_cast<_Tp*>(__ptr), __count / sizeof(_Tp)};
+}
+
 #if defined(__cpp_sized_deallocation) && __cpp_sized_deallocation >= 201309L
 #  define _LIBCPP_ONLY_IF_SIZED_DEALLOCATION(...) __VA_ARGS__
 #else
diff --git a/libcxx/include/__new/new_at_least.h b/libcxx/include/__new/new_at_least.h
new file mode 100644
index 0000000000000..801b02be7e23d
--- /dev/null
+++ b/libcxx/include/__new/new_at_least.h
@@ -0,0 +1,45 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___NEW_NEW_AT_LEAST_H
+#define _LIBCPP___NEW_NEW_AT_LEAST_H
+
+#include <__config>
+#include <__cstddef/size_t.h>
+#include <__new/align_val_t.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+template <class _Pointer, class _SizeT = size_t>
+struct __allocation_result {
+  _Pointer ptr;
+  _SizeT count;
+
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __allocation_result(_Pointer __ptr, _SizeT __count)
+      : ptr(__ptr), count(__count) {}
+};
+_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(__allocation_result);
+
+#if _LIBCPP_AVAILABILITY_HAS_NEW_AT_LEAST
+_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
+
+_LIBCPP_EXPORTED_FROM_ABI __allocation_result<void*> __new_at_least(size_t);
+#  if _LIBCPP_HAS_LIBRARY_ALIGNED_ALLOCATION
+_LIBCPP_EXPORTED_FROM_ABI __allocation_result<void*> __new_at_least(size_t, align_val_t);
+#  endif
+
+_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
+#endif
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___NEW_NEW_AT_LEAST_H
diff --git a/libcxx/src/support/new.ipp b/libcxx/src/support/new.ipp
index 80be2d904af4c..6556d181ea928 100644
--- a/libcxx/src/support/new.ipp
+++ b/libcxx/src/support/new.ipp
@@ -6,6 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include <__memory/allocate_at_least.h>
 #include <cstddef>
 #include <cstdlib>
 #include <new>
@@ -211,3 +212,69 @@ OVERRIDABLE_FUNCTION void* operator new[](size_t size, std::align_val_t alignmen
   ::operator delete[](ptr, alignment);
 }
 #endif // _LIBCPP_HAS_LIBRARY_ALIGNED_ALLOCATION
+
+#ifdef __APPLE__
+#  include <malloc/malloc.h>
+#elifdef __FreeBSD__
+#  include <malloc_np.h>
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
+
+#if __has_cpp_attribute(gnu::ifunc)
+
+using new_at_least_t         = __allocation_result<void*>(std::size_t);
+using new_at_least_aligned_t = __allocation_result<void*>(std::size_t, std::align_val_t);
+
+new_at_least_t* new_at_least_resolver() {
+  if (std::__is_function_overridden < void*(std::size_t), operator new>()) {
+    return [](std::size_t size) -> __allocation_result<void*> { return {::operator new(size), size}; };
+  } else {
+    return [](std::size_t size) -> __allocation_result<void*> {
+#  ifdef __APPLE__
+      auto good_size = malloc_good_size(size);
+      return {operator_new_impl(good_size), good_size};
+#elifdef __FreeBSD__
+      auto good_size = nallocx(size, 0);
+      return {operator_new_impl(good_size), good_size};
+#  else
+      return {operator_new_impl(size), size};
+#  endif
+    };
+  }
+}
+
+[[gnu::weak, gnu::ifunc("new_at_least_resolver")]] new_at_least_t __new_at_least;
+
+new_at_least_t* new_at_least_aligned_resolver() {
+  if (std::__is_function_overridden < void*(std::size_t), operator new>()) {
+    return [](std::size_t size) -> __allocation_result<void*> { return {::operator new(size), size}; };
+  } else {
+    return [](std::size_t size) -> __allocation_result<void*> {
+#  ifdef __APPLE__
+      auto good_size = malloc_good_size(size);
+      return {operator_new_impl(good_size), good_size};
+#  else
+      return {operator_new_impl(size), size};
+#  endif
+    };
+  }
+}
+
+[[gnu::weak, gnu::ifunc("new_at_least_aligned_resolver")]] new_at_least_aligned_t __new_at_least;
+
+#else
+
+std::__allocation_result<void*> __new_at_least(std::size_t size) { return {::operator new(size), size}; }
+
+#  if _LIBCPP_HAS_LIBRARY_ALIGNED_ALLOCATION
+std::__allocation_result<void*> __new_at_least(std::size_t size, std::align_val_t align) {
+  return {::operator new(size, align), size};
+}
+#  endif
+
+#endif
+
+_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
+_LIBCPP_END_NAMESPACE_STD



More information about the libcxx-commits mailing list