[llvm] [ADT] Support `.Default` with `nullptr` and `nullopt` values in TypeSwitch (PR #165724)
Jakub Kuderski via llvm-commits
llvm-commits at lists.llvm.org
Thu Oct 30 07:24:48 PDT 2025
https://github.com/kuhar created https://github.com/llvm/llvm-project/pull/165724
In the previous implementation, this would fail for cases like `TypeSwitch<T*, std::optional<U>>` because `std::nullopt` does not match `ResultT` exactly and the overload for callable types would be selected.
Add new overloads that support `nullptr` and `std::nullopt`. These can be added alongside generic callables because we wouldn't want to call any 'null' function refs anyway.
I selected the `nullptr` and `nullopt` specializations because how often they appear in the codebase -- currently, you will see lots of code like `.Default(std::optional<T>())` that can be simplified with this patch.
>From cc6f8cc84c9f879e7e45213a00477ef6cf583abc Mon Sep 17 00:00:00 2001
From: Jakub Kuderski <jakub at nod-labs.com>
Date: Thu, 30 Oct 2025 10:07:29 -0400
Subject: [PATCH 1/2] [ADT] Allow `std::nullopt` Default in TypeSwitch
---
llvm/include/llvm/ADT/TypeSwitch.h | 9 +++++++++
llvm/unittests/ADT/TypeSwitchTest.cpp | 10 ++++++++++
2 files changed, 19 insertions(+)
diff --git a/llvm/include/llvm/ADT/TypeSwitch.h b/llvm/include/llvm/ADT/TypeSwitch.h
index 5657303b0a1f2..8bdb4d27cda52 100644
--- a/llvm/include/llvm/ADT/TypeSwitch.h
+++ b/llvm/include/llvm/ADT/TypeSwitch.h
@@ -111,6 +111,7 @@ class TypeSwitch : public detail::TypeSwitchBase<TypeSwitch<T, ResultT>, T> {
return std::move(*result);
return defaultFn(this->value);
}
+
/// As a default, return the given value.
[[nodiscard]] ResultT Default(ResultT defaultResult) {
if (result)
@@ -118,6 +119,14 @@ class TypeSwitch : public detail::TypeSwitchBase<TypeSwitch<T, ResultT>, T> {
return defaultResult;
}
+ /// Default for optional results types that accept `std::nullopt`.
+ template <typename ArgT = ResultT,
+ typename =
+ std::enable_if_t<std::is_constructible_v<ArgT, std::nullopt_t>>>
+ [[nodiscard]] ResultT Default(std::nullopt_t) {
+ return Default(ResultT(std::nullopt));
+ }
+
/// Declare default as unreachable, making sure that all cases were handled.
[[nodiscard]] ResultT DefaultUnreachable(
const char *message = "Fell off the end of a type-switch") {
diff --git a/llvm/unittests/ADT/TypeSwitchTest.cpp b/llvm/unittests/ADT/TypeSwitchTest.cpp
index a7d934265c5f0..0f656f451ce4c 100644
--- a/llvm/unittests/ADT/TypeSwitchTest.cpp
+++ b/llvm/unittests/ADT/TypeSwitchTest.cpp
@@ -142,3 +142,13 @@ TEST(TypeSwitchTest, DefaultUnreachableWithVoid) {
EXPECT_DEATH((void)translate(DerivedD()), "Unhandled type");
#endif
}
+
+TEST(TypeSwitchTest, DefaultNullopt) {
+ auto translate = [](auto value) {
+ return TypeSwitch<Base *, std::optional<int>>(&value)
+ .Case([](DerivedA *) { return 0; })
+ .Default(std::nullopt);
+ };
+ EXPECT_EQ(0, translate(DerivedA()));
+ EXPECT_EQ(std::nullopt, translate(DerivedD()));
+}
>From 342bba2fbeff36feb91d80101c935e980b54f8af Mon Sep 17 00:00:00 2001
From: Jakub Kuderski <jakub at nod-labs.com>
Date: Thu, 30 Oct 2025 10:19:42 -0400
Subject: [PATCH 2/2] Support nullptr:
---
llvm/include/llvm/ADT/TypeSwitch.h | 8 +++++++
llvm/unittests/ADT/TypeSwitchTest.cpp | 31 +++++++++++++++++++++++++++
2 files changed, 39 insertions(+)
diff --git a/llvm/include/llvm/ADT/TypeSwitch.h b/llvm/include/llvm/ADT/TypeSwitch.h
index 8bdb4d27cda52..50ca1d5a6b5b6 100644
--- a/llvm/include/llvm/ADT/TypeSwitch.h
+++ b/llvm/include/llvm/ADT/TypeSwitch.h
@@ -119,6 +119,14 @@ class TypeSwitch : public detail::TypeSwitchBase<TypeSwitch<T, ResultT>, T> {
return defaultResult;
}
+ /// Default for pointer-like results types that accept `nullptr`.
+ template <typename ArgT = ResultT,
+ typename =
+ std::enable_if_t<std::is_constructible_v<ArgT, std::nullptr_t>>>
+ [[nodiscard]] ResultT Default(std::nullptr_t) {
+ return Default(ResultT(nullptr));
+ }
+
/// Default for optional results types that accept `std::nullopt`.
template <typename ArgT = ResultT,
typename =
diff --git a/llvm/unittests/ADT/TypeSwitchTest.cpp b/llvm/unittests/ADT/TypeSwitchTest.cpp
index 0f656f451ce4c..b80122837c1ad 100644
--- a/llvm/unittests/ADT/TypeSwitchTest.cpp
+++ b/llvm/unittests/ADT/TypeSwitchTest.cpp
@@ -152,3 +152,34 @@ TEST(TypeSwitchTest, DefaultNullopt) {
EXPECT_EQ(0, translate(DerivedA()));
EXPECT_EQ(std::nullopt, translate(DerivedD()));
}
+
+TEST(TypeSwitchTest, DefaultNullptr) {
+ float foo = 0.0f;
+ auto translate = [&](auto value) {
+ return TypeSwitch<Base *, float *>(&value)
+ .Case([&](DerivedA *) { return &foo; })
+ .Default(nullptr);
+ };
+ EXPECT_EQ(&foo, translate(DerivedA()));
+ EXPECT_EQ(nullptr, translate(DerivedD()));
+}
+
+TEST(TypeSwitchTest, DefaultNullptrForPointerLike) {
+ struct Value {
+ void *ptr;
+ Value(const Value &other) : ptr(other.ptr) {}
+ Value(std::nullptr_t) : ptr(nullptr) {}
+ Value() : Value(nullptr) {}
+ };
+
+ float foo = 0.0f;
+ Value fooVal;
+ fooVal.ptr = &foo;
+ auto translate = [&](auto value) {
+ return TypeSwitch<Base *, Value>(&value)
+ .Case([&](DerivedA *) { return fooVal; })
+ .Default(nullptr);
+ };
+ EXPECT_EQ(&foo, translate(DerivedA()).ptr);
+ EXPECT_EQ(nullptr, translate(DerivedD()).ptr);
+}
More information about the llvm-commits
mailing list