(I probably mis-categorized this, please feel free to move)
llvm_unreachable is being widely misused as an assertion, but in reality, its behavior is totally different depending on whether assertions are enabled. When asserts are enabled, it is an assertion. When asserts are disabled, it becomes an assumption, which is a serious departure from the typical behavior of assertions which is to merely get disabled. This misunderstanding traces back to its own comment as it says,
/// Use this instead of assert(0). It conveys intent more clearly and
/// allows compilers to omit some unnecessary code.
Iâm not denying that there are legitimate uses for llvm_unreachable. But they are a too small minority (see next paragraphs) for such blanket statements to be useful. That is then further expanded on in the coding guide section on asserts which promotes llvm_unreachable as âsomething much betterâ than assert(0) without qualification.
Most people writing assertions have the mental modal that they are enforcing something: code past the assertion will be able to assume that the asserted condition has already been enforced.
But __builtin_unreachable does the opposite: instead of enforcing, what it does is tell the compiler to assume that the condition has already been enforced. That may help the compiler generate better code (thus itâs an optimization) but at the cost of great unsafety if the assumption is ever defeated. That can only be the right trade-off of safety for performance in a small minority of performance-critical code.
Regarding the llvm_unreachable macro specifically as opposed to __builtin_unreachable, there is an additional concern: llvm_unreachable is a macro that expands to one thing or its opposite (âenforceâ vs âassume previously enforcedâ) depending on whether asserts are enabled. I understand that can still make sense for some situations but the point is, that should be made explicit.
A quick code search shows llvm_unreachable being widely used across llvm and several dependent projects in a way thatâs clearly not falling into that category. My own experience in code reviews is that reviewers will tell me to use llvm_unreachable where an assertion is meant. Iâve also seen this idiom propagate in all sorts of projects that ex-LLVM developers join e.g. this is where the pandemic reached mozilla (it was overturned fairly quickly).
Iâm sure I donât need to tell here how unsafe optimizations a compiler can do when it is given a __builtin_unreachable to work with. This Compiler Explorer playground shows for instance how a switch jump table drops its bounds-check, and how an unexpected if-branch is taken.
Potential action items:
- Fix the comments and the coding guide to make it clear that
llvm_unreachableis only useful when performance is critical and one is willing to trade safety for it, or something like that. Remove blanket statements presenting it as âlike assert(0)â. - Consider renaming
llvm_unreachableto something more explicit, possiblyllvm_assume_unreachable. - If assert(0) is deemed unsatisfactory for some purpose, consider adding some new macro.