Skip to content

Commit 85c7cea

Browse files
authored
[ADT] Add DefaultUnreachable("msg") to TypeSwitch (#161970)
This is to allow making it explicit that all the cases must be handled. The error message is customizable. Something similar was already supported using the conversion operator for the typed case but less explicit. In the `void` case when `TypeSwitch` doesn't return anything, this was not possible without a custom lambda.
1 parent 8a8a589 commit 85c7cea

File tree

2 files changed

+44
-3
lines changed

2 files changed

+44
-3
lines changed

llvm/include/llvm/ADT/TypeSwitch.h

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
#include "llvm/ADT/STLExtras.h"
1919
#include "llvm/Support/Casting.h"
20+
#include "llvm/Support/ErrorHandling.h"
2021
#include <optional>
2122

2223
namespace llvm {
@@ -117,11 +118,16 @@ class TypeSwitch : public detail::TypeSwitchBase<TypeSwitch<T, ResultT>, T> {
117118
return defaultResult;
118119
}
119120

120-
[[nodiscard]] operator ResultT() {
121-
assert(result && "Fell off the end of a type-switch");
122-
return std::move(*result);
121+
/// Declare default as unreachable, making sure that all cases were handled.
122+
[[nodiscard]] ResultT DefaultUnreachable(
123+
const char *message = "Fell off the end of a type-switch") {
124+
if (result)
125+
return std::move(*result);
126+
llvm_unreachable(message);
123127
}
124128

129+
[[nodiscard]] operator ResultT() { return DefaultUnreachable(); }
130+
125131
private:
126132
/// The pointer to the result of this switch statement, once known,
127133
/// null before that.
@@ -158,6 +164,13 @@ class TypeSwitch<T, void>
158164
defaultFn(this->value);
159165
}
160166

167+
/// Declare default as unreachable, making sure that all cases were handled.
168+
void DefaultUnreachable(
169+
const char *message = "Fell off the end of a type-switch") {
170+
if (!foundMatch)
171+
llvm_unreachable(message);
172+
}
173+
161174
private:
162175
/// A flag detailing if we have already found a match.
163176
bool foundMatch = false;

llvm/unittests/ADT/TypeSwitchTest.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,3 +114,31 @@ TEST(TypeSwitchTest, CasesOptional) {
114114
EXPECT_EQ(std::nullopt, translate(DerivedC()));
115115
EXPECT_EQ(-1, translate(DerivedD()));
116116
}
117+
118+
TEST(TypeSwitchTest, DefaultUnreachableWithValue) {
119+
auto translate = [](auto value) {
120+
return TypeSwitch<Base *, int>(&value)
121+
.Case([](DerivedA *) { return 0; })
122+
.DefaultUnreachable("Unhandled type");
123+
};
124+
EXPECT_EQ(0, translate(DerivedA()));
125+
126+
#if defined(GTEST_HAS_DEATH_TEST) && !defined(NDEBUG)
127+
EXPECT_DEATH((void)translate(DerivedD()), "Unhandled type");
128+
#endif
129+
}
130+
131+
TEST(TypeSwitchTest, DefaultUnreachableWithVoid) {
132+
auto translate = [](auto value) {
133+
int result = -1;
134+
TypeSwitch<Base *>(&value)
135+
.Case([&result](DerivedA *) { result = 0; })
136+
.DefaultUnreachable("Unhandled type");
137+
return result;
138+
};
139+
EXPECT_EQ(0, translate(DerivedA()));
140+
141+
#if defined(GTEST_HAS_DEATH_TEST) && !defined(NDEBUG)
142+
EXPECT_DEATH((void)translate(DerivedD()), "Unhandled type");
143+
#endif
144+
}

0 commit comments

Comments
 (0)