creturnlanguage-lawyerundefined-behavior

If there is [[noreturn]], then why there is no [[always_return]]?


If there is [[noreturn]] (C2X, n3301), then why there is no [[always_return]]?

The semantics of [[always_return]] may be the following:

A function declared with an [[always_return]] attribute shall always return to its caller.

The rationale for [[always_return]] is a hint to compiler to perform optimizations.

Example (taken from N3128):

extern void g(int x);
int f(int a, int b)
{
    g(b ? 42 : 43);
    return a / b;
}

A compiler is free to (optimistically) assume that UB doesn't happen.

However, any (hazardous) consequences of UB happen only if UB happens (i.e. present in execution at abstract machine level).

In this example g may terminate the program (i.e. not return). Hence, as I understand, compiler may not fold b ? 42 : 43 to 42, because at abstract machine level a / b may not be executed, hence compiler may not propagate / use an assumption that b is non-zero.

However, if g is declared with [[always_return]], then, as I understand, compiler may fold b ? 42 : 43 to 42, because at abstract machine level a / b is always executed, hence compiler may propagate / use an assumption that b is non-zero.


P.S. The same question goes for [[may_return]].


UPD. In order to fold b ? 42 : 43 to 42 g needs not only to always return, but also to not have observable behavior (OB). This is so, because in C OB is required to happen before UB. Hence, more attributes may be needed: [[observable]], [[noobservable]]. And g may be declared as:

extern [[always_return]] [[noobservable]] void g(int x);

Solution

  • If there is [[noreturn]] (C2X, n3301), then why there is no [[always_return]]?

    Ultimately, because the committee did not see (sufficient) value in adding such an attribute. I'm inclined to guess that they did not see value because it wasn't even proposed, but if it was proposed then it was rejected. Certainly the proposal to add [[noreturn]] did not contemplate an [[always_return]].

    And why would it? There is nothing a user function can do to ensure that it will always return. It is always possible that the program is killed during execution of the function, or its return is prevented via a debugger, or any of a variety of other things outside the control of the function's programmer happens to prevent the function from returning.

    And what good would it do? In the absence of any attribute and / or special knowledge of particular functions, the C implementation must presume that function calls will return. But even if an [[always_return]] promise could in fact be kept reliably, the information is not useful to the implementation. It's like me asserting that the sun will rise tomorrow. Even supposing that you have absolute faith in me on those grounds, would you do anything different? No, because to any extent that it makes a difference, you were taking that as a working assumption already.

    [[noreturn]] is different. It affords performance enhancements and improved diagnostics relative to unmarked functions that, by design, do not return.

    Additionally, the [[noreturn]] attribute is an alternative to the _Noreturn function specifier that has been in C since C11, so it's not really a new feature. Switching to an attribute instead of a specifier supports harmonization with C++. There is no function specifier analogous to your hypothetical [[always_return]].