[llvm] [LLVM][Support] add nonNull function helper (PR #188718)
Nathan Gauër via llvm-commits
llvm-commits at lists.llvm.org
Thu Mar 26 05:02:50 PDT 2026
https://github.com/Keenuts updated https://github.com/llvm/llvm-project/pull/188718
>From 31aed38ac641cc0e7cd14a908094f8fe621f1203 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= <brioche at google.com>
Date: Thu, 26 Mar 2026 10:54:00 +0100
Subject: [PATCH 1/4] [LLVM][Support] add nonNull function helper
We often see a pattern like:
```
T *ptr = doSomething()
assert(ptr && "doSomething() shouldn't return nullptr");
```
We also have functions like `cantFail`, but those are working with
Expected types.
This commits adds a `nonNull` function, which can be used inline.
In practice, one could use:
```
T *ptr = cast<T>(functionReturningT());
```
But it conveys the meaning that `functionReturningT` might return
a subtype/supertype that we actually cast.
Function behaves like the other error kinds: calls llvm_unreachable,
which may or may not trap depending on the build options.
Calling this function with `nullptr` won't build, but it makes no sense
to do so.
---
llvm/docs/ProgrammersManual.rst | 8 ++++++++
llvm/include/llvm/Support/Error.h | 12 ++++++++++++
llvm/unittests/Support/ErrorTest.cpp | 24 ++++++++++++++++++++++++
3 files changed, 44 insertions(+)
diff --git a/llvm/docs/ProgrammersManual.rst b/llvm/docs/ProgrammersManual.rst
index 51a813eadee73..0b32dc62b0593 100644
--- a/llvm/docs/ProgrammersManual.rst
+++ b/llvm/docs/ProgrammersManual.rst
@@ -453,6 +453,14 @@ violations even in builds that do not enable assertions:
reportFatalInternalError("Analysis 'foo' not preserved");
}
+Additionally, ``nonNull`` can be used to check/document that a pointer
+is never supposed to be null inline.
+
+.. code-block:: c++
+ setMyPointer("key", Pointer);
+ // [...]
+ Type *P = nonNull(getMyPointer("key"));
+
Recoverable Errors
^^^^^^^^^^^^^^^^^^
diff --git a/llvm/include/llvm/Support/Error.h b/llvm/include/llvm/Support/Error.h
index c9fd16fdb7c2b..442ab16734eb5 100644
--- a/llvm/include/llvm/Support/Error.h
+++ b/llvm/include/llvm/Support/Error.h
@@ -811,6 +811,18 @@ T cantFail(Expected<T> ValOrErr, const char *Msg = nullptr) {
}
}
+/// Calls llvm_unreachable if Pointer is null, otherwise returns the
+/// pointer as is.
+template<typename T>
+LLVM_ATTRIBUTE_RETURNS_NONNULL T* nonNull(T* Pointer, const char *Msg = nullptr) {
+ if (Pointer)
+ return Pointer;
+
+ if (!Msg)
+ Msg = "Expected a non-null pointer but got a null pointer";
+ llvm_unreachable(Msg);
+}
+
/// Report a fatal error if ValOrErr is a failure value, otherwise unwraps and
/// returns the contained reference.
///
diff --git a/llvm/unittests/Support/ErrorTest.cpp b/llvm/unittests/Support/ErrorTest.cpp
index 45c0a4f450b51..953160596e732 100644
--- a/llvm/unittests/Support/ErrorTest.cpp
+++ b/llvm/unittests/Support/ErrorTest.cpp
@@ -1219,4 +1219,28 @@ TEST(Error, ForwardToExpected) {
EXPECT_THAT_ERROR(ExpectedReturningFct(false).moveInto(MaybeV), Succeeded());
EXPECT_EQ(*MaybeV, 42);
}
+
+TEST(Error, NonNullSuccess) {
+ int tmp = 0;
+ int *ptr = &tmp;
+ const int *cptr = ptr;
+ const int *const ccptr = ptr;
+
+ EXPECT_EQ(ptr, nonNull(&tmp));
+ EXPECT_EQ(ptr, nonNull(ptr));
+ EXPECT_EQ(ptr, nonNull(cptr));
+ EXPECT_EQ(ptr, nonNull(ccptr));
+}
+
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS && !defined(NDEBUG)
+TEST(Error, NonNullFails) {
+ int *NullPtr = nullptr;
+ EXPECT_DEATH(nonNull(NullPtr), "Expected a non-null pointer but got a null pointer")
+ << "nonNull(NullPtr) did not cause an abort for null pointer";
+
+ EXPECT_DEATH(nonNull(NullPtr, "custom message"), "custom message")
+ << "nonNull(nullptr) did not cause an abort for null pointer";
+}
+#endif
+
} // namespace
>From e46c19b9dd6c6593f4984b2cdd77bc37aa9b51e2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= <brioche at google.com>
Date: Thu, 26 Mar 2026 11:44:45 +0100
Subject: [PATCH 2/4] clang format
---
llvm/include/llvm/Support/Error.h | 5 +++--
llvm/unittests/Support/ErrorTest.cpp | 3 ++-
2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/llvm/include/llvm/Support/Error.h b/llvm/include/llvm/Support/Error.h
index 442ab16734eb5..8474d54c42bed 100644
--- a/llvm/include/llvm/Support/Error.h
+++ b/llvm/include/llvm/Support/Error.h
@@ -813,8 +813,9 @@ T cantFail(Expected<T> ValOrErr, const char *Msg = nullptr) {
/// Calls llvm_unreachable if Pointer is null, otherwise returns the
/// pointer as is.
-template<typename T>
-LLVM_ATTRIBUTE_RETURNS_NONNULL T* nonNull(T* Pointer, const char *Msg = nullptr) {
+template <typename T>
+LLVM_ATTRIBUTE_RETURNS_NONNULL T *nonNull(T *Pointer,
+ const char *Msg = nullptr) {
if (Pointer)
return Pointer;
diff --git a/llvm/unittests/Support/ErrorTest.cpp b/llvm/unittests/Support/ErrorTest.cpp
index 953160596e732..572cac38ac094 100644
--- a/llvm/unittests/Support/ErrorTest.cpp
+++ b/llvm/unittests/Support/ErrorTest.cpp
@@ -1235,7 +1235,8 @@ TEST(Error, NonNullSuccess) {
#if LLVM_ENABLE_ABI_BREAKING_CHECKS && !defined(NDEBUG)
TEST(Error, NonNullFails) {
int *NullPtr = nullptr;
- EXPECT_DEATH(nonNull(NullPtr), "Expected a non-null pointer but got a null pointer")
+ EXPECT_DEATH(nonNull(NullPtr),
+ "Expected a non-null pointer but got a null pointer")
<< "nonNull(NullPtr) did not cause an abort for null pointer";
EXPECT_DEATH(nonNull(NullPtr, "custom message"), "custom message")
>From 43422fe9bd92043ec92cd6094702368e535b949d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= <brioche at google.com>
Date: Thu, 26 Mar 2026 11:45:26 +0100
Subject: [PATCH 3/4] fix code-block
---
llvm/docs/ProgrammersManual.rst | 1 +
1 file changed, 1 insertion(+)
diff --git a/llvm/docs/ProgrammersManual.rst b/llvm/docs/ProgrammersManual.rst
index 0b32dc62b0593..3ee59b5ecf6df 100644
--- a/llvm/docs/ProgrammersManual.rst
+++ b/llvm/docs/ProgrammersManual.rst
@@ -457,6 +457,7 @@ Additionally, ``nonNull`` can be used to check/document that a pointer
is never supposed to be null inline.
.. code-block:: c++
+
setMyPointer("key", Pointer);
// [...]
Type *P = nonNull(getMyPointer("key"));
>From 954b724c5bcc4dbc0b0d565c1010e1709f2f32ef Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= <brioche at google.com>
Date: Thu, 26 Mar 2026 13:02:08 +0100
Subject: [PATCH 4/4] pr-feedback: replace define
---
llvm/unittests/Support/ErrorTest.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/unittests/Support/ErrorTest.cpp b/llvm/unittests/Support/ErrorTest.cpp
index 572cac38ac094..30e4efd0bc391 100644
--- a/llvm/unittests/Support/ErrorTest.cpp
+++ b/llvm/unittests/Support/ErrorTest.cpp
@@ -1232,7 +1232,7 @@ TEST(Error, NonNullSuccess) {
EXPECT_EQ(ptr, nonNull(ccptr));
}
-#if LLVM_ENABLE_ABI_BREAKING_CHECKS && !defined(NDEBUG)
+#if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST
TEST(Error, NonNullFails) {
int *NullPtr = nullptr;
EXPECT_DEATH(nonNull(NullPtr),
More information about the llvm-commits
mailing list