-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[ADT] Add DefaultUnreachable("msg")
to TypeSwitch
#161970
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
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.
@llvm/pr-subscribers-llvm-adt Author: Jakub Kuderski (kuhar) ChangesThis 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 Full diff: https://github.com/llvm/llvm-project/pull/161970.diff 2 Files Affected:
diff --git a/llvm/include/llvm/ADT/TypeSwitch.h b/llvm/include/llvm/ADT/TypeSwitch.h
index 5bbbdf23b257e..5657303b0a1f2 100644
--- a/llvm/include/llvm/ADT/TypeSwitch.h
+++ b/llvm/include/llvm/ADT/TypeSwitch.h
@@ -17,6 +17,7 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Casting.h"
+#include "llvm/Support/ErrorHandling.h"
#include <optional>
namespace llvm {
@@ -117,11 +118,16 @@ class TypeSwitch : public detail::TypeSwitchBase<TypeSwitch<T, ResultT>, T> {
return defaultResult;
}
- [[nodiscard]] operator ResultT() {
- assert(result && "Fell off the end of a type-switch");
- return std::move(*result);
+ /// 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") {
+ if (result)
+ return std::move(*result);
+ llvm_unreachable(message);
}
+ [[nodiscard]] operator ResultT() { return DefaultUnreachable(); }
+
private:
/// The pointer to the result of this switch statement, once known,
/// null before that.
@@ -158,6 +164,13 @@ class TypeSwitch<T, void>
defaultFn(this->value);
}
+ /// Declare default as unreachable, making sure that all cases were handled.
+ void DefaultUnreachable(
+ const char *message = "Fell off the end of a type-switch") {
+ if (!foundMatch)
+ llvm_unreachable(message);
+ }
+
private:
/// A flag detailing if we have already found a match.
bool foundMatch = false;
diff --git a/llvm/unittests/ADT/TypeSwitchTest.cpp b/llvm/unittests/ADT/TypeSwitchTest.cpp
index c54b7987edf7e..1778df73be5f4 100644
--- a/llvm/unittests/ADT/TypeSwitchTest.cpp
+++ b/llvm/unittests/ADT/TypeSwitchTest.cpp
@@ -114,3 +114,31 @@ TEST(TypeSwitchTest, CasesOptional) {
EXPECT_EQ(std::nullopt, translate(DerivedC()));
EXPECT_EQ(-1, translate(DerivedD()));
}
+
+TEST(TypeSwitchTest, DefaultUnreachableWithValue) {
+ auto translate = [](auto value) {
+ return TypeSwitch<Base *, int>(&value)
+ .Case([](DerivedA *) { return 0; })
+ .DefaultUnreachable("Unhandled type");
+ };
+ EXPECT_EQ(0, translate(DerivedA()));
+
+#if defined(GTEST_HAS_DEATH_TEST) && !defined(NDEBUG)
+ EXPECT_DEATH((void)translate(DerivedD(DerivedD())), "Unhandled type");
+#endif
+}
+
+TEST(TypeSwitchTest, DefaultUnreachableWithVoid) {
+ auto translate = [](auto value) {
+ int result = -1;
+ TypeSwitch<Base *>(&value)
+ .Case([&result](DerivedA *) { result = 0; })
+ .DefaultUnreachable("Unhandled type");
+ return result;
+ };
+ EXPECT_EQ(0, translate(DerivedA()));
+
+#if defined(GTEST_HAS_DEATH_TEST) && !defined(NDEBUG)
+ EXPECT_DEATH((void)translate(DerivedD(DerivedD())), "Unhandled type");
+#endif
+}
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, I was looking for this recently and surprised it doesn't exist...
Similar to TypeSwitch (llvm#161970), allow for explicit unreachable default case with a custom error message on unhandled cases. StringSwitch already allowed for checking if any of the cases matched with the conversion operator, but `DefaultUnreachable` is more explicit and allows for a custom message.
Similar to TypeSwitch (#161970), allow for explicit unreachable default case with a custom error message on unhandled cases. StringSwitch already allowed for checking if any of the cases matched with the conversion operator, but `DefaultUnreachable` is more explicit and allows for a custom message.
Using `DefaultUnreachable` from llvm#161970.
Use `DefaultUnreachable` from llvm#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.
Similar to TypeSwitch (llvm#161970), allow for explicit unreachable default case with a custom error message on unhandled cases. StringSwitch already allowed for checking if any of the cases matched with the conversion operator, but `DefaultUnreachable` is more explicit and allows for a custom message.
…witch. NFC. (#162010) Use `DefaultUnreachable` from llvm/llvm-project#161970.
Use `DefaultUnreachable` from #161970.
Use `DefaultUnreachable` from llvm/llvm-project#161970.
Use `DefaultUnreachable` from llvm/llvm-project#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 whenTypeSwitch
doesn't return anything, this was not possible without a custom lambda.