[libc-commits] [libc] [llvm] [libc] Move nullptr_t definition to cstddef/nullptr_t.h (PR #236712)
Pavel Labath via libc-commits
libc-commits at lists.llvm.org
Thu Oct 29 23:54:34 PDT 2026
https://github.com/labath updated https://github.com/llvm/llvm-project/pull/236712
>From c1f963e986768caa15f0c3e368ee6490868104f2 Mon Sep 17 00:00:00 2001
From: Pavel Labath <pavel at labath.sk>
Date: Thu, 29 Oct 2026 09:13:14 +0000
Subject: [PATCH 1/2] [libc] Move nullptr_t definition to cstddef/nullptr_t.h
cpp::nullptr_t was previously defined in type_traits/is_null_pointer.h,
which is an odd place for it. In standard C++, nullptr_t is defined in
<cstddef>. However, putting it directly into the umbrella cstddef.h
pulls in byte, which depends on type_traits.h for enable_if_t and
is_integral_v, creating an include cycle if type_traits wants to use
nullptr_t.
To solve this, I've placed nullptr_t into a granular
src/__support/CPP/cstddef/nullptr_t.h header (following the precedent of
headers in utility/ and libc++'s __cstddef/nullptr_t.h).
With this change:
- cstddef.h re-exports nullptr_t from cstddef/nullptr_t.h.
- is_null_pointer.h includes cstddef/nullptr_t.h and uses cpp::nullptr_t
without circular dependencies.
- unique_ptr.h, LibcTest.h, and tests include cstddef/nullptr_t.h
directly and use nullptr_t in place of decltype(nullptr).
- added CMake target libc.src.__support.CPP.nullptr_t.
- added nullptr_t construction tests in unique_ptr_test.
Assisted-by: Gemini
---
libc/src/__support/CPP/CMakeLists.txt | 11 ++++++++++
libc/src/__support/CPP/cstddef.h | 1 +
libc/src/__support/CPP/cstddef/nullptr_t.h | 22 +++++++++++++++++++
.../CPP/type_traits/is_null_pointer.h | 2 +-
libc/src/__support/CPP/unique_ptr.h | 5 +++--
libc/test/UnitTest/CMakeLists.txt | 1 +
libc/test/UnitTest/LibcTest.h | 1 +
libc/test/src/__support/CPP/CMakeLists.txt | 2 ++
.../src/__support/CPP/functional_test.cpp | 6 +++--
.../src/__support/CPP/unique_ptr_test.cpp | 15 +++++++++++++
.../llvm-project-overlay/libc/BUILD.bazel | 10 +++++++++
.../libc/test/UnitTest/BUILD.bazel | 1 +
.../libc/test/src/__support/CPP/BUILD.bazel | 1 +
13 files changed, 73 insertions(+), 5 deletions(-)
create mode 100644 libc/src/__support/CPP/cstddef/nullptr_t.h
diff --git a/libc/src/__support/CPP/CMakeLists.txt b/libc/src/__support/CPP/CMakeLists.txt
index 97898e2744f7b0..6c911333f01079 100644
--- a/libc/src/__support/CPP/CMakeLists.txt
+++ b/libc/src/__support/CPP/CMakeLists.txt
@@ -29,11 +29,20 @@ add_header_library(
bitset.h
)
+add_header_library(
+ nullptr_t
+ HDRS
+ cstddef/nullptr_t.h
+ DEPENDS
+ libc.src.__support.macros.config
+)
+
add_header_library(
cstddef
HDRS
cstddef.h
DEPENDS
+ .nullptr_t
.type_traits
)
@@ -186,6 +195,7 @@ add_header_library(
type_traits/type_identity.h
type_traits/void_t.h
DEPENDS
+ .nullptr_t
libc.include.llvm-libc-macros.stdfix_macros
libc.src.__support.macros.attributes
libc.src.__support.macros.properties.types
@@ -229,6 +239,7 @@ add_header_library(
unique_ptr.h
DEPENDS
.new
+ .nullptr_t
.type_traits
.utility
libc.hdr.types.size_t
diff --git a/libc/src/__support/CPP/cstddef.h b/libc/src/__support/CPP/cstddef.h
index 1507789cb1b10c..4b0b4a25790d08 100644
--- a/libc/src/__support/CPP/cstddef.h
+++ b/libc/src/__support/CPP/cstddef.h
@@ -9,6 +9,7 @@
#ifndef LLVM_LIBC_SRC___SUPPORT_CPP_CSTDDEF_H
#define LLVM_LIBC_SRC___SUPPORT_CPP_CSTDDEF_H
+#include "src/__support/CPP/cstddef/nullptr_t.h"
#include "src/__support/macros/attributes.h"
#include "src/__support/macros/config.h"
#include "type_traits.h" // For enable_if_t, is_integral_v.
diff --git a/libc/src/__support/CPP/cstddef/nullptr_t.h b/libc/src/__support/CPP/cstddef/nullptr_t.h
new file mode 100644
index 00000000000000..6cf39070d00356
--- /dev/null
+++ b/libc/src/__support/CPP/cstddef/nullptr_t.h
@@ -0,0 +1,22 @@
+//===-- nullptr_t type ------------------------------------------*- 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_CPP_CSTDDEF_NULLPTR_T_H
+#define LLVM_LIBC_SRC___SUPPORT_CPP_CSTDDEF_NULLPTR_T_H
+
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+namespace cpp {
+
+using nullptr_t = decltype(nullptr);
+
+} // namespace cpp
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_CPP_CSTDDEF_NULLPTR_T_H
diff --git a/libc/src/__support/CPP/type_traits/is_null_pointer.h b/libc/src/__support/CPP/type_traits/is_null_pointer.h
index acf341311be06e..87a94192f01b22 100644
--- a/libc/src/__support/CPP/type_traits/is_null_pointer.h
+++ b/libc/src/__support/CPP/type_traits/is_null_pointer.h
@@ -8,6 +8,7 @@
#ifndef LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_NULL_POINTER_H
#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_NULL_POINTER_H
+#include "src/__support/CPP/cstddef/nullptr_t.h"
#include "src/__support/CPP/type_traits/is_same.h"
#include "src/__support/CPP/type_traits/remove_cv.h"
#include "src/__support/macros/attributes.h"
@@ -17,7 +18,6 @@ namespace LIBC_NAMESPACE_DECL {
namespace cpp {
// is_null_pointer
-using nullptr_t = decltype(nullptr);
template <class T>
struct is_null_pointer : cpp::is_same<cpp::nullptr_t, cpp::remove_cv_t<T>> {};
template <class T>
diff --git a/libc/src/__support/CPP/unique_ptr.h b/libc/src/__support/CPP/unique_ptr.h
index a8cf11d2ae8a72..6a98d4223b368e 100644
--- a/libc/src/__support/CPP/unique_ptr.h
+++ b/libc/src/__support/CPP/unique_ptr.h
@@ -15,6 +15,7 @@
#define LLVM_LIBC_SRC___SUPPORT_CPP_UNIQUE_PTR_H
#include "hdr/types/size_t.h"
+#include "src/__support/CPP/cstddef/nullptr_t.h"
#include "src/__support/CPP/new.h"
#include "src/__support/CPP/type_traits.h"
#include "src/__support/CPP/utility.h"
@@ -66,7 +67,7 @@ class LIBC_TRIVIAL_ABI unique_ptr {
using pointer = T *;
LIBC_INLINE constexpr unique_ptr() = default;
- LIBC_INLINE constexpr unique_ptr(decltype(nullptr)) : ptr(nullptr) {}
+ LIBC_INLINE constexpr unique_ptr(nullptr_t) : ptr(nullptr) {}
LIBC_INLINE constexpr explicit unique_ptr(pointer p) : ptr(p) {}
LIBC_INLINE constexpr unique_ptr(pointer p, const deleter_type &d)
@@ -156,7 +157,7 @@ class LIBC_TRIVIAL_ABI unique_ptr<T[], Deleter> {
using pointer = T *;
LIBC_INLINE constexpr unique_ptr() = default;
- LIBC_INLINE constexpr unique_ptr(decltype(nullptr)) : ptr(nullptr) {}
+ LIBC_INLINE constexpr unique_ptr(nullptr_t) : ptr(nullptr) {}
LIBC_INLINE constexpr explicit unique_ptr(pointer p) : ptr(p) {}
LIBC_INLINE constexpr unique_ptr(pointer p, const deleter_type &d)
diff --git a/libc/test/UnitTest/CMakeLists.txt b/libc/test/UnitTest/CMakeLists.txt
index de82c2f1362d65..2622e74a8ec78f 100644
--- a/libc/test/UnitTest/CMakeLists.txt
+++ b/libc/test/UnitTest/CMakeLists.txt
@@ -103,6 +103,7 @@ add_unittest_framework_library(
libc.src.__support.big_int
libc.src.__support.c_string
libc.src.__support.CPP.functional
+ libc.src.__support.CPP.nullptr_t
libc.src.__support.CPP.string
libc.src.__support.CPP.string_view
libc.src.__support.CPP.type_traits
diff --git a/libc/test/UnitTest/LibcTest.h b/libc/test/UnitTest/LibcTest.h
index 56ed7f3383c053..3feecb262f4988 100644
--- a/libc/test/UnitTest/LibcTest.h
+++ b/libc/test/UnitTest/LibcTest.h
@@ -24,6 +24,7 @@
// This file can only include headers from src/__support/ or test/UnitTest. No
// other headers should be included.
+#include "src/__support/CPP/cstddef/nullptr_t.h"
#include "src/__support/CPP/functional.h"
#include "src/__support/CPP/string.h"
#include "src/__support/CPP/string_view.h"
diff --git a/libc/test/src/__support/CPP/CMakeLists.txt b/libc/test/src/__support/CPP/CMakeLists.txt
index ffb1ab6f9d61df..5116f559e71c0a 100644
--- a/libc/test/src/__support/CPP/CMakeLists.txt
+++ b/libc/test/src/__support/CPP/CMakeLists.txt
@@ -72,6 +72,7 @@ add_libc_test(
functional_test.cpp
DEPENDS
libc.src.__support.CPP.functional
+ libc.src.__support.CPP.nullptr_t
libc.src.__support.CPP.type_traits
)
@@ -174,6 +175,7 @@ add_libc_test(
unique_ptr_test.cpp
DEPENDS
libc.hdr.signal_macros
+ libc.src.__support.CPP.nullptr_t
libc.src.__support.CPP.unique_ptr
libc.src.__support.CPP.utility
)
diff --git a/libc/test/src/__support/CPP/functional_test.cpp b/libc/test/src/__support/CPP/functional_test.cpp
index db427f7e6901d2..5c803d2bf07b9c 100644
--- a/libc/test/src/__support/CPP/functional_test.cpp
+++ b/libc/test/src/__support/CPP/functional_test.cpp
@@ -11,6 +11,7 @@
///
//===----------------------------------------------------------------------===//
+#include "src/__support/CPP/cstddef/nullptr_t.h"
#include "src/__support/CPP/functional.h"
#include "src/__support/CPP/type_traits.h"
#include "test/UnitTest/Test.h"
@@ -18,6 +19,7 @@
using LIBC_NAMESPACE::cpp::function_ref;
using LIBC_NAMESPACE::cpp::is_assignable_v;
using LIBC_NAMESPACE::cpp::is_constructible_v;
+using LIBC_NAMESPACE::cpp::nullptr_t;
static int forty_two() { return 42; }
static int seven() { return 7; }
@@ -43,7 +45,7 @@ using IntIntFn = function_ref<int(int)>;
// Like std::function_ref, there is no empty state.
static_assert(!is_constructible_v<IntFn>);
-static_assert(!is_constructible_v<IntFn, decltype(nullptr)>);
+static_assert(!is_constructible_v<IntFn, nullptr_t>);
static_assert(!is_constructible_v<bool, IntFn>);
// Callables with incompatible signatures are rejected.
@@ -61,7 +63,7 @@ static_assert(is_assignable_v<IntFn &, int (&)()>);
static_assert(is_constructible_v<IntFn, Functor>);
static_assert(!is_assignable_v<IntFn &, Functor>);
static_assert(!is_assignable_v<IntFn &, Functor &>);
-static_assert(!is_assignable_v<IntFn &, decltype(nullptr)>);
+static_assert(!is_assignable_v<IntFn &, nullptr_t>);
TEST(LlvmLibcFunctionRefTest, Lambda) {
int offset = 10;
diff --git a/libc/test/src/__support/CPP/unique_ptr_test.cpp b/libc/test/src/__support/CPP/unique_ptr_test.cpp
index 56bdd77eb1e7ac..7e26a8e3449b3a 100644
--- a/libc/test/src/__support/CPP/unique_ptr_test.cpp
+++ b/libc/test/src/__support/CPP/unique_ptr_test.cpp
@@ -12,12 +12,14 @@
//===----------------------------------------------------------------------===//
#include "hdr/signal_macros.h"
+#include "src/__support/CPP/cstddef/nullptr_t.h"
#include "src/__support/CPP/unique_ptr.h"
#include "src/__support/CPP/utility.h"
#include "src/__support/alloc-checker.h"
#include "test/UnitTest/Test.h"
using LIBC_NAMESPACE::AllocChecker;
+using LIBC_NAMESPACE::cpp::nullptr_t;
using LIBC_NAMESPACE::cpp::unique_ptr;
struct DestructTracker {
@@ -48,6 +50,19 @@ TEST(LlvmLibcUniquePtrTest, Nullptr) {
unique_ptr<int> ptr(nullptr);
ASSERT_FALSE(static_cast<bool>(ptr));
ASSERT_EQ(ptr.get(), nullptr);
+
+ constexpr nullptr_t null{};
+ unique_ptr<int> ptr2(null);
+ ASSERT_FALSE(static_cast<bool>(ptr2));
+ ASSERT_EQ(ptr2.get(), nullptr);
+
+ unique_ptr<int[]> arr(nullptr);
+ ASSERT_FALSE(static_cast<bool>(arr));
+ ASSERT_EQ(arr.get(), nullptr);
+
+ unique_ptr<int[]> arr2(null);
+ ASSERT_FALSE(static_cast<bool>(arr2));
+ ASSERT_EQ(arr2.get(), nullptr);
}
// Test move construction transferring ownership.
diff --git a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
index f468f19e65edba..c97ba47c41c273 100644
--- a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
@@ -1784,10 +1784,19 @@ libc_support_library(
],
)
+libc_support_library(
+ name = "__support_cpp_nullptr_t",
+ hdrs = ["src/__support/CPP/cstddef/nullptr_t.h"],
+ deps = [
+ ":__support_macros_config",
+ ],
+)
+
libc_support_library(
name = "__support_cpp_cstddef",
hdrs = ["src/__support/CPP/cstddef.h"],
deps = [
+ ":__support_cpp_nullptr_t",
":__support_cpp_type_traits",
":__support_macros_attributes",
":__support_macros_config",
@@ -1965,6 +1974,7 @@ libc_support_library(
"src/__support/CPP/utility/forward.h",
],
deps = [
+ ":__support_cpp_nullptr_t",
":__support_macros_attributes",
":__support_macros_config",
":__support_macros_properties_compiler",
diff --git a/utils/bazel/llvm-project-overlay/libc/test/UnitTest/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/test/UnitTest/BUILD.bazel
index 70c48473105a6b..bc926453af3fc6 100644
--- a/utils/bazel/llvm-project-overlay/libc/test/UnitTest/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/libc/test/UnitTest/BUILD.bazel
@@ -55,6 +55,7 @@ libc_test_library(
"//libc:__support_cpp_bitset",
"//libc:__support_cpp_functional",
"//libc:__support_cpp_limits",
+ "//libc:__support_cpp_nullptr_t",
"//libc:__support_cpp_scope",
"//libc:__support_cpp_span",
"//libc:__support_cpp_string",
diff --git a/utils/bazel/llvm-project-overlay/libc/test/src/__support/CPP/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/test/src/__support/CPP/BUILD.bazel
index 56a64bf0c3c918..139e9412218bec 100644
--- a/utils/bazel/llvm-project-overlay/libc/test/src/__support/CPP/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/libc/test/src/__support/CPP/BUILD.bazel
@@ -43,6 +43,7 @@ libc_test(
srcs = ["functional_test.cpp"],
deps = [
"//libc:__support_cpp_functional",
+ "//libc:__support_cpp_nullptr_t",
"//libc:__support_cpp_type_traits",
],
)
>From 5c1cb9b5b51e61392f95224c3e82937151e77ccf Mon Sep 17 00:00:00 2001
From: Pavel Labath <pavel at labath.sk>
Date: Fri, 30 Oct 2026 06:54:11 +0000
Subject: [PATCH 2/2] fix header
---
libc/src/__support/CPP/cstddef/nullptr_t.h | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/libc/src/__support/CPP/cstddef/nullptr_t.h b/libc/src/__support/CPP/cstddef/nullptr_t.h
index 6cf39070d00356..334143c47d8d3a 100644
--- a/libc/src/__support/CPP/cstddef/nullptr_t.h
+++ b/libc/src/__support/CPP/cstddef/nullptr_t.h
@@ -1,10 +1,15 @@
-//===-- nullptr_t type ------------------------------------------*- 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
//
//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Implementation of cpp::nullptr_t.
+///
+//===----------------------------------------------------------------------===//
#ifndef LLVM_LIBC_SRC___SUPPORT_CPP_CSTDDEF_NULLPTR_T_H
#define LLVM_LIBC_SRC___SUPPORT_CPP_CSTDDEF_NULLPTR_T_H
More information about the libc-commits
mailing list