[llvm] 0029815 - [ADT] Support `.Default` with `nullptr` and `nullopt` values in TypeSwitch (#165724)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Oct 30 10:27:45 PDT 2025
Author: Jakub Kuderski
Date: 2025-10-30T13:27:41-04:00
New Revision: 0029815af7b8335054345e2f5aacf68ef9d18e81
URL: https://github.com/llvm/llvm-project/commit/0029815af7b8335054345e2f5aacf68ef9d18e81
DIFF: https://github.com/llvm/llvm-project/commit/0029815af7b8335054345e2f5aacf68ef9d18e81.diff
LOG: [ADT] Support `.Default` with `nullptr` and `nullopt` values in TypeSwitch (#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.
Added:
Modified:
llvm/include/llvm/ADT/TypeSwitch.h
llvm/unittests/ADT/TypeSwitchTest.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/ADT/TypeSwitch.h b/llvm/include/llvm/ADT/TypeSwitch.h
index 5657303b0a1f2..50ca1d5a6b5b6 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,22 @@ 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 =
+ 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..b80122837c1ad 100644
--- a/llvm/unittests/ADT/TypeSwitchTest.cpp
+++ b/llvm/unittests/ADT/TypeSwitchTest.cpp
@@ -142,3 +142,44 @@ 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()));
+}
+
+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