Skip to content

Add unreachable after FAIL #2941

@Caellian

Description

@Caellian

As FAIL (unlike FAIL_CHECK) marks the end of test execution, adding unreachable marker would help type checking in some cases.

Example where it would be useful:

#define EXPECT_NEXT_CHANGE(T)                          \
  []() {                                               \
    auto change = mock::next_state_change_t<T>();      \
    if (change) {                                      \
      return *change.value().release();                \
    } else {                                           \
      FAIL("expected '" #T "' as next state change");  \
      return *reinterpret_cast<T*>(malloc(sizeof(T))); \
    }                                                  \
  }();

As you can see, lack of unreachable hint forces me to manufacture some T value to avoid an error.

If FAIL had unreachable at the end, clangd wouldn't complain about the missing return in else branch because it would assume the function will never get to the point after FAIL.

Here's some unreachable implementation for example:

#ifdef NDEBUG
#ifdef __GNUC__  // GCC, Clang, ICC
#define UNREACHABLE() (__builtin_unreachable())
#elif defined(_MSC_VER)  // MSVC
#define UNREACHABLE() (__assume(false))
#else /* other compilers */
// unreachable_impl must be emitted in a separated TU if used from C code due to
// the difference in rule for inline functions in C.
[[noreturn]] inline void unreachable_impl() {}
#define UNREACHABLE() (unreachable_impl())
#endif /* compiler selection */
#else  /* DEBUG */
#define UNREACHABLE() (PANIC("reached unreachable"))
#endif /* NDEBUG */

Side effects might include, but are not limited to:

  • Compiler will optimize all tests with assumption that FAIL is unlikely.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions