Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the point of noreturn?

People also ask

Is there a point of no return?

The point of no return (PNR or PONR) is the point beyond which one must continue on one's current course of action because turning back is dangerous, physically impossible or difficult, or prohibitively expensive. The point of no return can be a calculated point during a continuous action (such as in aviation).

What is the point of no return example?

the stage at which it is no longer possible to stop what you are doing and when its effects cannot now be avoided or prevented: Russia, he said, had reached the point of no return on the road to reform and had to go forward. Scientists fear that global warming has gone beyond the point of no return.


The noreturn attribute is supposed to be used for functions that don't return to the caller. That doesn't mean void functions (which do return to the caller - they just don't return a value), but functions where the control flow will not return to the calling function after the function finishes (e.g. functions that exit the application, loop forever or throw exceptions as in your example).

This can be used by compilers to make some optimizations and generate better warnings. For example if f has the noreturn attribute, the compiler could warn you about g() being dead code when you write f(); g();. Similarly the compiler will know not to warn you about missing return statements after calls to f().


noreturn doesn't tell the compiler that the function doesn't return any value. It tells the compiler that control flow will not return to the caller. This allows the compiler to make a variety of optimizations -- it need not save and restore any volatile state around the call, it can dead-code eliminate any code that would otherwise follow the call, etc.


It means that the function will not complete. The control flow will never hit the statement after the call to f():

void g() {
   f();
   // unreachable:
   std::cout << "No! That's impossible" << std::endl;
}

The information can be used by the compiler/optimizer in different ways. The compiler can add a warning that the code above is unreachable, and it can modify the actual code of g() in different ways for example to support continuations.


Previous answers correctly explained what noreturn is, but not why it exists. I don't think the "optimization" comments is the main purpose: Functions which do not return are rare and usually do not need to be optimized. Rather I think the main raison d'être of noreturn is to avoid false-positive warnings. For example, consider this code:

int f(bool b){
    if (b) {
        return 7;
    } else {
        abort();
    }
 }

Had abort() not been marked "noreturn", the compiler might have warned about this code having a path where f does not return an integer as expected. But because abort() is marked no return it knows the code is correct.


Type theoretically speaking, void is what is called in other languages unit or top. Its logical equivalent is True. Any value can be legitimately cast to void (every type is a subtype of void). Think about it as "universe" set; there are no operations in common to all the values in the world, so there are no valid operations on a value of type void. Put it another way, telling you that something belongs to the universe set gives you no information whatsoever - you know it already. So the following is sound:

(void)5;
(void)foo(17); // whatever foo(17) does

But the assignment below is not:

void raise();
void f(int y) {
    int x = y!=0 ? 100/y : raise(); // raise() returns void, so what should x be?
    cout << x << endl;
}

[[noreturn]], on the other hand, is called sometimes empty, Nothing, Bottom or Bot and is the logical equivalent of False. It has no values at all, and an expression of this type can be cast to (i.e is subtype of) any type. This is the empty set. Note that if someone tells you "the value of the expression foo() belongs to the empty set" it is highly informative - it tells you that this expression will never complete its normal execution; it will abort, throw or hang. It is the exact opposite of void.

So the following does not make sense (pseudo-C++, since noreturn is not a first-class C++ type)

void foo();
(noreturn)5; // obviously a lie; the expression 5 does "return"
(noreturn)foo(); // foo() returns void, and therefore returns

But the assignment below is perfectly legitimate, since throw is understood by the compiler to not return:

void f(int y) {
    int x = y!=0 ? 100/y : throw exception();
    cout << x << endl;
}

In a perfect world, you could use noreturn as the return value for the function raise() above:

noreturn raise() { throw exception(); }
...
int x = y!=0 ? 100/y : raise();

Sadly C++ does not allow it, probably for practical reasons. Instead it gives you the ability to use [[ noreturn ]] attribute which helps guiding compiler optimizations and warnings.