C++ Logo

sg12

Advanced search

Re: [SG12] Missing non-void return on some paths

From: Arthur O'Dwyer <arthur.j.odwyer_at_[hidden]>
Date: Sat, 8 May 2021 16:45:28 -0400
On Sat, May 8, 2021 at 4:14 PM Nevin Liber via SG12 <sg12_at_[hidden]>
wrote:

>
> What about assert(b) when NDEBUG is not defined? JF said that would
> become an unconditional call to std::unreachable, but calling
> std::unreachable invokes UB. From the paper: "The author feels that the
> best way is to make the behavior of std::unreachable() be undefined."
>

I believe JF was responding to your `assert(false)` situation. The standard
`assert` actually already does the right thing; it's basically

    #define assert(x) (x ? void() : std::abort())

where `std::abort()` is (at least hypothetically) annotated with
[[noreturn]].

    constexpr int f4(int x) { assert(x > 0); if (x == 42) return 42; }

Here, in C++14-and-later, the compiler can trace individual "attempted
constant-evaluation runs" and *observe* that
- `f4(-1)` evaluates non-constexpr function std::abort() and therefore is
not a constant expression
- `f4(42)` evaluates to 42
- `f4(1)` falls off the end of the function and therefore is not a constant
expression

In JF's hypothetical future, AIUI, the compiler would also be able to do
control-flow (and data-flow?) analysis and *prove symbolically* that
- `f4(x)` for (x <= 0) evaluates [[noreturn]] function std::abort() and
therefore is OK
- `f4(x)` for (x == 42) returns a value along all codepaths and therefore
is OK
- `f4(x)` for (0 < x && x != 42) falls off the end of the function and
therefore is *not OK*
and, since there exists at least one "*not OK*" case, therefore the
definition of `f4` is ill-formed (even if `f4` is never *actually*
evaluated on any of the problematic inputs).

–Arthur

Received on 2021-05-08 15:45:41