What is the point of noreturn?

C++C++11AttributesNoreturn

C++ Problem Overview


[dcl.attr.noreturn] provides the following example:

[[ noreturn ]] void f() {
    throw "error";
    // OK
}

but I do not understand what is the point of [[noreturn]], because the return type of the function is already void.

So, what is the point of the noreturn attribute? How is it supposed to be used?

C++ Solutions


Solution 1 - C++

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().

Solution 2 - C++

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.

Solution 3 - C++

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.

Solution 4 - C++

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.

Solution 5 - C++

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionBЈовићView Question on Stackoverflow
Solution 1 - C++sepp2kView Answer on Stackoverflow
Solution 2 - C++Stephen CanonView Answer on Stackoverflow
Solution 3 - C++David Rodríguez - dribeasView Answer on Stackoverflow
Solution 4 - C++Nadav Har'ElView Answer on Stackoverflow
Solution 5 - C++ElazarView Answer on Stackoverflow