Skip to content

Conversation

@frobtech
Copy link
Contributor

This moves the libc-internal AllocChecker API out of
src/__support/CPP/new.h and updates CPP/README.md to state the
intent to keep src/__support/CPP and the LIBC_NAMESPACE::cpp
namespace a "pure" subset of standard C++ API polyfills.

This moves the libc-internal AllocChecker API out of
src/__support/CPP/new.h and updates CPP/README.md to state the
intent to keep src/__support/CPP and the LIBC_NAMESPACE::cpp
namespace a "pure" subset of standard C++ API polyfills.
@frobtech frobtech marked this pull request as ready for review December 19, 2025 21:36
@llvmbot llvmbot added the libc label Dec 19, 2025
@llvmbot
Copy link
Member

llvmbot commented Dec 19, 2025

@llvm/pr-subscribers-libc

Author: Roland McGrath (frobtech)

Changes

This moves the libc-internal AllocChecker API out of
src/__support/CPP/new.h and updates CPP/README.md to state the
intent to keep src/__support/CPP and the LIBC_NAMESPACE::cpp
namespace a "pure" subset of standard C++ API polyfills.


Full diff: https://github.com/llvm/llvm-project/pull/173104.diff

18 Files Affected:

  • (modified) libc/docs/dev/code_style.rst (+1)
  • (modified) libc/src/__support/CPP/README.md (+23-8)
  • (modified) libc/src/__support/CPP/new.h (+4-62)
  • (modified) libc/src/__support/File/dir.cpp (+1)
  • (modified) libc/src/__support/File/file.cpp (+1)
  • (modified) libc/src/__support/File/linux/file.cpp (+2-1)
  • (modified) libc/src/__support/HashTable/table.h (+1)
  • (added) libc/src/__support/alloc-checker.h (+77)
  • (modified) libc/src/__support/blockstore.h (+1)
  • (modified) libc/src/spawn/posix_spawn_file_actions_addclose.cpp (+1)
  • (modified) libc/src/spawn/posix_spawn_file_actions_adddup2.cpp (+1)
  • (modified) libc/src/spawn/posix_spawn_file_actions_addopen.cpp (+1)
  • (modified) libc/src/stdio/fopencookie.cpp (+1)
  • (modified) libc/src/string/allocating_string_utils.h (+1)
  • (modified) libc/src/string/strndup.cpp (+3-3)
  • (modified) libc/test/integration/src/pthread/pthread_create_test.cpp (+1)
  • (modified) libc/test/src/__support/File/file_test.cpp (+2-2)
  • (modified) libc/test/src/__support/hash_test.cpp (+1)
diff --git a/libc/docs/dev/code_style.rst b/libc/docs/dev/code_style.rst
index 5eafff9ef9b3d..f88d82feea367 100644
--- a/libc/docs/dev/code_style.rst
+++ b/libc/docs/dev/code_style.rst
@@ -159,6 +159,7 @@ this:
 .. code-block:: c++
 
    #include "src/__support/CPP/new.h"
+   #include "src/__support/alloc-checker.h"
 
    ...
 
diff --git a/libc/src/__support/CPP/README.md b/libc/src/__support/CPP/README.md
index b470c3f1dc343..70e2939a33653 100644
--- a/libc/src/__support/CPP/README.md
+++ b/libc/src/__support/CPP/README.md
@@ -1,13 +1,28 @@
 This directory contains partial re-implementations of some C++ standard library
 utilities. They are for use with internal LLVM libc code and tests.
 
-More utilities can be added on an as needed basis. There are certain rules to
+More utilities can be added on an as-needed basis. There are certain rules to
 be followed for future changes and additions:
 
-1. Only two kind of headers can be included: Other headers from this directory,
-and free standing C headers.
-2. Free standing C headers are to be included as C headers and not as C++
-headers. That is, use `#include <stddef.h>` and not `#include <cstddef>`.
-3. The utilities should be defined in the namespace `LIBC_NAMESPACE::cpp`. The
-higher level namespace should have a `__` prefix to avoid symbol name pollution
-when the utilities are used in implementation of public functions.
+* Only certain kind of headers can be included:
+   * Other headers from this directory
+   * Free-standing C headers (`<stdint.h>` et al)
+   * A few basic `src/__support/macros` headers used pervasively in all libc code
+
+ * Free-standing C headers are to be included as C headers and not as C++
+   headers. That is, use `#include <stddef.h>` and not `#include <cstddef>`.
+   The [proxies](../../../hdr) can also be used, as in `#include "hdr/stdint_proxy.h"`.
+
+* The utilities should be defined in the namespace `LIBC_NAMESPACE::cpp`. The
+  higher level namespace should have a `__` prefix to avoid symbol name pollution
+  when the utilities are used in implementation of public functions.
+
+* Each "CPP/foo.h" provides an exact subset of the API from standard C++ <foo>,
+  just using `LIBC_NAMESPACE::cpp::foo` names in place of `std::foo` names. The
+  implementations here need not be perfect standard-conforming implementations,
+  but their behavior must match for whatever _is_ supported at compile time.
+  That is, if each were just declared with `using std::foo;` all the libc code
+  should work the same (functionally speaking, excluding namespace entanglements).
+
+* Additional APIs specific to libc internals belong elsewhere in `src/__support`,
+  not in `src/__support/CPP`.
diff --git a/libc/src/__support/CPP/new.h b/libc/src/__support/CPP/new.h
index 67344b09e3833..e529e05d858a4 100644
--- a/libc/src/__support/CPP/new.h
+++ b/libc/src/__support/CPP/new.h
@@ -1,4 +1,4 @@
-//===-- Libc specific custom operator new and delete ------------*- C++ -*-===//
+//===-- Libc-internal alternative to <new> ------------*- C++ -*-===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -9,13 +9,10 @@
 #ifndef LLVM_LIBC_SRC___SUPPORT_CPP_NEW_H
 #define LLVM_LIBC_SRC___SUPPORT_CPP_NEW_H
 
-#include "hdr/func/aligned_alloc.h"
 #include "hdr/func/free.h"
-#include "hdr/func/malloc.h"
 #include "src/__support/common.h"
 #include "src/__support/macros/config.h"
 #include "src/__support/macros/properties/compiler.h"
-#include "src/__support/macros/properties/os.h"
 
 #include <stddef.h> // For size_t
 
@@ -29,78 +26,23 @@ enum class align_val_t : size_t {};
 } // namespace std
 
 namespace LIBC_NAMESPACE_DECL {
-
 namespace cpp {
+
 template <class T> [[nodiscard]] constexpr T *launder(T *p) {
   static_assert(__has_builtin(__builtin_launder),
                 "cpp::launder requires __builtin_launder");
   return __builtin_launder(p);
 }
-} // namespace cpp
-
-class AllocChecker {
-  bool success = false;
-
-  LIBC_INLINE AllocChecker &operator=(bool status) {
-    success = status;
-    return *this;
-  }
-
-public:
-  LIBC_INLINE AllocChecker() = default;
-
-  LIBC_INLINE operator bool() const { return success; }
-
-  LIBC_INLINE static void *alloc(size_t s, AllocChecker &ac) {
-    void *mem = ::malloc(s);
-    ac = (mem != nullptr);
-    return mem;
-  }
-
-  LIBC_INLINE static void *aligned_alloc(size_t s, std::align_val_t align,
-                                         AllocChecker &ac) {
-#ifdef LIBC_TARGET_OS_IS_WINDOWS
-    // std::aligned_alloc is not available on Windows because std::free on
-    // Windows cannot deallocate any over-aligned memory. Microsoft provides an
-    // alternative for std::aligned_alloc named _aligned_malloc, but it must be
-    // paired with _aligned_free instead of std::free.
-    void *mem = ::_aligned_malloc(static_cast<size_t>(align), s);
-#else
-    void *mem = ::aligned_alloc(static_cast<size_t>(align), s);
-#endif
-    ac = (mem != nullptr);
-    return mem;
-  }
-};
 
+} // namespace cpp
 } // namespace LIBC_NAMESPACE_DECL
 
-LIBC_INLINE void *operator new(size_t size,
-                               LIBC_NAMESPACE::AllocChecker &ac) noexcept {
-  return LIBC_NAMESPACE::AllocChecker::alloc(size, ac);
-}
-
-LIBC_INLINE void *operator new(size_t size, std::align_val_t align,
-                               LIBC_NAMESPACE::AllocChecker &ac) noexcept {
-  return LIBC_NAMESPACE::AllocChecker::aligned_alloc(size, align, ac);
-}
-
-LIBC_INLINE void *operator new[](size_t size,
-                                 LIBC_NAMESPACE::AllocChecker &ac) noexcept {
-  return LIBC_NAMESPACE::AllocChecker::alloc(size, ac);
-}
-
-LIBC_INLINE void *operator new[](size_t size, std::align_val_t align,
-                                 LIBC_NAMESPACE::AllocChecker &ac) noexcept {
-  return LIBC_NAMESPACE::AllocChecker::aligned_alloc(size, align, ac);
-}
-
 LIBC_INLINE void *operator new(size_t, void *p) { return p; }
 
 LIBC_INLINE void *operator new[](size_t, void *p) { return p; }
 
 // The ideal situation would be to define the various flavors of operator delete
-// inlinelike we do with operator new above. However, since we need operator
+// inline like we do with operator new above. However, since we need operator
 // delete prototypes to match those specified by the C++ standard, we cannot
 // define them inline as the C++ standard does not allow inline definitions of
 // replacement operator delete implementations. Note also that we assign a
diff --git a/libc/src/__support/File/dir.cpp b/libc/src/__support/File/dir.cpp
index aea8862c15f7f..eb33656808414 100644
--- a/libc/src/__support/File/dir.cpp
+++ b/libc/src/__support/File/dir.cpp
@@ -10,6 +10,7 @@
 
 #include "src/__support/CPP/mutex.h" // lock_guard
 #include "src/__support/CPP/new.h"
+#include "src/__support/alloc-checker.h"
 #include "src/__support/error_or.h"
 #include "src/__support/libc_errno.h" // For error macros
 #include "src/__support/macros/config.h"
diff --git a/libc/src/__support/File/file.cpp b/libc/src/__support/File/file.cpp
index 15ec1a23e2b8d..ccc7acf9387f5 100644
--- a/libc/src/__support/File/file.cpp
+++ b/libc/src/__support/File/file.cpp
@@ -13,6 +13,7 @@
 #include "hdr/types/off_t.h"
 #include "src/__support/CPP/new.h"
 #include "src/__support/CPP/span.h"
+#include "src/__support/alloc-checker.h"
 #include "src/__support/libc_errno.h" // For error macros
 #include "src/__support/macros/config.h"
 #include "src/string/memory_utils/inline_memcpy.h"
diff --git a/libc/src/__support/File/linux/file.cpp b/libc/src/__support/File/linux/file.cpp
index 4594dadf1ccdf..28f819db83d49 100644
--- a/libc/src/__support/File/linux/file.cpp
+++ b/libc/src/__support/File/linux/file.cpp
@@ -15,7 +15,8 @@
 #include "src/__support/File/linux/lseekImpl.h"
 #include "src/__support/OSUtil/fcntl.h"
 #include "src/__support/OSUtil/syscall.h" // For internal syscall function.
-#include "src/__support/libc_errno.h"     // For error macros
+#include "src/__support/alloc-checker.h"
+#include "src/__support/libc_errno.h" // For error macros
 #include "src/__support/macros/config.h"
 
 #include "hdr/fcntl_macros.h" // For mode_t and other flags to the open syscall
diff --git a/libc/src/__support/HashTable/table.h b/libc/src/__support/HashTable/table.h
index 966ee0fcaf0ae..f42eead2efcf2 100644
--- a/libc/src/__support/HashTable/table.h
+++ b/libc/src/__support/HashTable/table.h
@@ -14,6 +14,7 @@
 #include "src/__support/CPP/bit.h" // bit_ceil
 #include "src/__support/CPP/new.h"
 #include "src/__support/HashTable/bitmask.h"
+#include "src/__support/alloc-checker.h"
 #include "src/__support/hash.h"
 #include "src/__support/macros/attributes.h"
 #include "src/__support/macros/config.h"
diff --git a/libc/src/__support/alloc-checker.h b/libc/src/__support/alloc-checker.h
new file mode 100644
index 0000000000000..ecef094453cc8
--- /dev/null
+++ b/libc/src/__support/alloc-checker.h
@@ -0,0 +1,77 @@
+//===-- Libc specific custom operator new and delete ------------*- C++ -*-===//
+//
+// 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 LLVM_LIBC_SRC___SUPPORT_ALLOC_CHECKER_H
+#define LLVM_LIBC_SRC___SUPPORT_ALLOC_CHECKER_H
+
+#include "hdr/func/aligned_alloc.h"
+#include "hdr/func/malloc.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/properties/os.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+class AllocChecker {
+  bool success = false;
+
+  LIBC_INLINE AllocChecker &operator=(bool status) {
+    success = status;
+    return *this;
+  }
+
+public:
+  LIBC_INLINE AllocChecker() = default;
+
+  LIBC_INLINE operator bool() const { return success; }
+
+  LIBC_INLINE static void *alloc(size_t s, AllocChecker &ac) {
+    void *mem = ::malloc(s);
+    ac = (mem != nullptr);
+    return mem;
+  }
+
+  LIBC_INLINE static void *aligned_alloc(size_t s, std::align_val_t align,
+                                         AllocChecker &ac) {
+#ifdef LIBC_TARGET_OS_IS_WINDOWS
+    // std::aligned_alloc is not available on Windows because std::free on
+    // Windows cannot deallocate any over-aligned memory. Microsoft provides an
+    // alternative for std::aligned_alloc named _aligned_malloc, but it must be
+    // paired with _aligned_free instead of std::free.
+    void *mem = ::_aligned_malloc(static_cast<size_t>(align), s);
+#else
+    void *mem = ::aligned_alloc(static_cast<size_t>(align), s);
+#endif
+    ac = (mem != nullptr);
+    return mem;
+  }
+};
+
+} // namespace LIBC_NAMESPACE_DECL
+
+LIBC_INLINE void *operator new(size_t size,
+                               LIBC_NAMESPACE::AllocChecker &ac) noexcept {
+  return LIBC_NAMESPACE::AllocChecker::alloc(size, ac);
+}
+
+LIBC_INLINE void *operator new(size_t size, std::align_val_t align,
+                               LIBC_NAMESPACE::AllocChecker &ac) noexcept {
+  return LIBC_NAMESPACE::AllocChecker::aligned_alloc(size, align, ac);
+}
+
+LIBC_INLINE void *operator new[](size_t size,
+                                 LIBC_NAMESPACE::AllocChecker &ac) noexcept {
+  return LIBC_NAMESPACE::AllocChecker::alloc(size, ac);
+}
+
+LIBC_INLINE void *operator new[](size_t size, std::align_val_t align,
+                                 LIBC_NAMESPACE::AllocChecker &ac) noexcept {
+  return LIBC_NAMESPACE::AllocChecker::aligned_alloc(size, align, ac);
+}
+
+#endif // LLVM_LIBC_SRC___SUPPORT_ALLOC_CHECKER_H
diff --git a/libc/src/__support/blockstore.h b/libc/src/__support/blockstore.h
index 61ee0ee80a2bf..af84262222c60 100644
--- a/libc/src/__support/blockstore.h
+++ b/libc/src/__support/blockstore.h
@@ -13,6 +13,7 @@
 #include "src/__support/CPP/array.h"
 #include "src/__support/CPP/new.h"
 #include "src/__support/CPP/type_traits.h"
+#include "src/__support/alloc-checker.h"
 #include "src/__support/libc_assert.h"
 #include "src/__support/macros/config.h"
 
diff --git a/libc/src/spawn/posix_spawn_file_actions_addclose.cpp b/libc/src/spawn/posix_spawn_file_actions_addclose.cpp
index 9a575bd591632..04213a82ec726 100644
--- a/libc/src/spawn/posix_spawn_file_actions_addclose.cpp
+++ b/libc/src/spawn/posix_spawn_file_actions_addclose.cpp
@@ -10,6 +10,7 @@
 
 #include "file_actions.h"
 #include "src/__support/CPP/new.h"
+#include "src/__support/alloc-checker.h"
 #include "src/__support/common.h"
 #include "src/__support/libc_errno.h"
 #include "src/__support/macros/config.h"
diff --git a/libc/src/spawn/posix_spawn_file_actions_adddup2.cpp b/libc/src/spawn/posix_spawn_file_actions_adddup2.cpp
index 1ad45ed942bb9..569fc20e73d60 100644
--- a/libc/src/spawn/posix_spawn_file_actions_adddup2.cpp
+++ b/libc/src/spawn/posix_spawn_file_actions_adddup2.cpp
@@ -10,6 +10,7 @@
 
 #include "file_actions.h"
 #include "src/__support/CPP/new.h"
+#include "src/__support/alloc-checker.h"
 #include "src/__support/common.h"
 #include "src/__support/libc_errno.h"
 #include "src/__support/macros/config.h"
diff --git a/libc/src/spawn/posix_spawn_file_actions_addopen.cpp b/libc/src/spawn/posix_spawn_file_actions_addopen.cpp
index 9977fc2d0a218..23a8907596932 100644
--- a/libc/src/spawn/posix_spawn_file_actions_addopen.cpp
+++ b/libc/src/spawn/posix_spawn_file_actions_addopen.cpp
@@ -10,6 +10,7 @@
 
 #include "file_actions.h"
 #include "src/__support/CPP/new.h"
+#include "src/__support/alloc-checker.h"
 #include "src/__support/common.h"
 #include "src/__support/libc_errno.h"
 #include "src/__support/macros/config.h"
diff --git a/libc/src/stdio/fopencookie.cpp b/libc/src/stdio/fopencookie.cpp
index da8a132a4db6e..dafc7823e5fd9 100644
--- a/libc/src/stdio/fopencookie.cpp
+++ b/libc/src/stdio/fopencookie.cpp
@@ -13,6 +13,7 @@
 #include "hdr/types/off_t.h"
 #include "src/__support/CPP/new.h"
 #include "src/__support/File/file.h"
+#include "src/__support/alloc-checker.h"
 
 #include "src/__support/libc_errno.h"
 #include "src/__support/macros/config.h"
diff --git a/libc/src/string/allocating_string_utils.h b/libc/src/string/allocating_string_utils.h
index e2f61f77b0c75..dfaa794298889 100644
--- a/libc/src/string/allocating_string_utils.h
+++ b/libc/src/string/allocating_string_utils.h
@@ -11,6 +11,7 @@
 
 #include "src/__support/CPP/new.h"
 #include "src/__support/CPP/optional.h"
+#include "src/__support/alloc-checker.h"
 #include "src/__support/macros/config.h" // LIBC_NAMESPACE_DECL
 #include "src/string/memory_utils/inline_memcpy.h"
 #include "src/string/string_utils.h"
diff --git a/libc/src/string/strndup.cpp b/libc/src/string/strndup.cpp
index b19d7c060baa1..40f473a0167fe 100644
--- a/libc/src/string/strndup.cpp
+++ b/libc/src/string/strndup.cpp
@@ -7,13 +7,13 @@
 //===----------------------------------------------------------------------===//
 
 #include "src/string/strndup.h"
+#include "src/__support/CPP/new.h"
+#include "src/__support/alloc-checker.h"
+#include "src/__support/common.h"
 #include "src/__support/macros/config.h"
 #include "src/string/memory_utils/inline_memcpy.h"
 #include "src/string/string_utils.h"
 
-#include "src/__support/CPP/new.h"
-#include "src/__support/common.h"
-
 #include <stddef.h>
 
 namespace LIBC_NAMESPACE_DECL {
diff --git a/libc/test/integration/src/pthread/pthread_create_test.cpp b/libc/test/integration/src/pthread/pthread_create_test.cpp
index d436cc3270d9c..6fae8e747a204 100644
--- a/libc/test/integration/src/pthread/pthread_create_test.cpp
+++ b/libc/test/integration/src/pthread/pthread_create_test.cpp
@@ -27,6 +27,7 @@
 #include "src/__support/CPP/array.h"
 #include "src/__support/CPP/atomic.h"
 #include "src/__support/CPP/new.h"
+#include "src/__support/alloc-checker.h"
 #include "src/__support/threads/thread.h"
 
 #include "test/IntegrationTest/test.h"
diff --git a/libc/test/src/__support/File/file_test.cpp b/libc/test/src/__support/File/file_test.cpp
index 17dad4d5ac917..ed2200b879048 100644
--- a/libc/test/src/__support/File/file_test.cpp
+++ b/libc/test/src/__support/File/file_test.cpp
@@ -6,14 +6,14 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "hdr/types/size_t.h"
 #include "src/__support/CPP/new.h"
 #include "src/__support/File/file.h"
+#include "src/__support/alloc-checker.h"
 #include "src/__support/error_or.h"
 #include "test/UnitTest/MemoryMatcher.h"
 #include "test/UnitTest/Test.h"
 
-#include "hdr/types/size_t.h"
-
 using ModeFlags = LIBC_NAMESPACE::File::ModeFlags;
 using MemoryView = LIBC_NAMESPACE::testing::MemoryView;
 using LIBC_NAMESPACE::ErrorOr;
diff --git a/libc/test/src/__support/hash_test.cpp b/libc/test/src/__support/hash_test.cpp
index 94c884cc7fb17..417a43a58b340 100644
--- a/libc/test/src/__support/hash_test.cpp
+++ b/libc/test/src/__support/hash_test.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "src/__support/CPP/new.h"
+#include "src/__support/alloc-checker.h"
 #include "src/__support/hash.h"
 #include "src/stdlib/rand.h"
 #include "src/stdlib/srand.h"

Copy link
Contributor

@michaelrj-google michaelrj-google left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants