C++ switch-case statements enable writing conditional statements that are checked for exhaustiveness by the compiler. However, C++ compilers don't enforce exhaustiveness very well. These macros enable you to explicitly opt into truly exhaustive switch-cases, that are useful for scenarios where you may want to deal with enums that are inputs, rather than internal invariants.
Declared in <folly/lang/Switch.h>
#define FOLLY_EXHAUSTIVE_SWITCH(...)
Historically, we have encountered one too many instances of SEVs caused by improper handling of enums, so these macros are used to enable stronger, and more explicit guarantees when writing switch-cases.
For example:
enum class logposition_t { sealed = -1, nonexistent = -2, };
void foo(logposition_t logpos) { FOLLY_EXHAUSTIVE_SWITCH({ switch (logpos) { case logposition_t::sealed: // handle sealed case case logposition_t::nonexistent: // handle nonexistent case default: // handle non-exceptional value } }); }
For the above, if you miss handling any case, or if you miss the default case, the compiler will complain.
When you switch on the value of a concretely defined enum with a very large set of values, and only need to address a sane subset of the values, you write a non-exhaustive switch. Additionally, when you switch on the a non-enum value (like an int), you write a non-exhaustive switch.
enum class Color { // every color in a 64 color palette named as an enum value };
bool isRedColor(Color c) { FOLLY_NON_EXHAUSTIVE_SWITCH({ switch (c) { case Color::Red: case Color::LightRed: case Color::DarkRed: return true; default: return false; } }); }
The above is the less common pattern for switch statements.
Note: The two macros here do not work well before llvm-18, they are known to work for most recent versions of gcc, however.