Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can a [[noreturn]] function have a return type?

I encountered this "beautiful" example of "highly readable" and "elegant" code, but I'm having troubles understanding it:

struct S {

    [[noreturn]] virtual inline auto f(const unsigned long int *const)
                         –> void const noexcept;
};

Here's what I understand (please correct me if I'm wrong):

  • f() is a member function of S
  • virtual - can be overridden by derived classes
  • inline - compiler should attempt to generate code for a call to f rather than calling it normally
  • const - the function is not able to change any of S's members
  • noexcept - the function will never throw (cannot throw or not allowed to throw)
  • parameter: a const pointer to a const unsigned long int
  • auto .... -> void - suffix return type void
  • [[noreturn]] - it never returns

Here are my main concerns:

  • If a function is declared as [[noreturn]], it never returns to its caller; so how can it have a return type void? What is the point of a return type in this function anyway?
  • Would this code compile with int instead of void for example?
  • What would be a practical use for a function like that? To throw an exception?
  • Where does the flow of the code go after this function finishes executing (after } )?

I couldn't get this code to run on VS2013 Preview, so I guess these features weren't implemented yet.

I'm very curious about this, so I'll appreciate it if someone can explain! Cheers

like image 915
Oleksiy Avatar asked Aug 21 '13 07:08

Oleksiy


3 Answers

If a function is declared as [[noreturn]], it never returns to its caller; so how can it have a return type void? What is the point of a return type in this function anyway?

From this Q&A you can see that noreturn is a way to tell the compiler that a function does not return. Normally this means it either has an infinite loop (often seen in servers that are supposed to run indefinitely) or it calls exit(), terminate() and the like, exiting the application without returning to main.
[[noreturn]] is optional, i.e. you don't have to specify it. It's an attribute, i.e. the basic syntax of defining/declaring the function remains untouched, so the function has to have a return type as any other function has.

Would this code compile with int instead of void for example?

Yes, it would, although the compiler might warn you that it does not make sense having something returned from a function that never returns.

What would be a practical use for a function like that? To throw an exception?

The first thing that comes to mind is some endless loop, e.g. handling incoming requests at a server. Throwing an exception is ok for [[noreturn]] functions as well, but its not really an option here, because it explicitly says noexcept. Throwing would trigger a call to std::terminate(), leading to program termination itself but previosuly to an implementation defined amount of stack unwinding, wich in fact means [[noreturn]] would still be applicable.

Where does the flow of the code go after this function finishes executing (after } )?

The function never reaches its closing }. It either runs endlessly (until someone pulls the plug), or it exits abnormally, i.e. by program termination. In other words, if the function does not execute any more, it has not really finished but aborted execution, and there is no program and no control flow to go to.

like image 134
Arne Mertz Avatar answered Oct 23 '22 15:10

Arne Mertz


The other answers are great, but I'm going to present an alternative answer for

If a function is declared as [[noreturn]], it never returns to its caller; so how can it have a return type void? What is the point of a return type in this function anyway?

One reason why you might need a return type (and a non-void return type at that) is if the function is overriding a super classes method.

struct Parent {
   virtual int f()=0;
}

struct Child {
    [[noreturn]] override int f() noexcept { ... }
};

In some contexts the compiler will be able to use the [[noreturn]] to produce better code. But in other situations f might be called polymorhically, and thus needs to conform to its parents signature.

like image 20
Michael Anderson Avatar answered Oct 23 '22 16:10

Michael Anderson


The [[noreturn]] is an attribute which has whatever semantics it has. It doesn't change, however, how the function is declared: all normal functions in C++ (i.e., all functions except the constructors, destructors, and conversion operators) have a declared return type. Adding any attribute doesn't change this rule.

The purpose of the [[noreturn]] attribute is probably to indicate that the function never returns in a normal way. Given that the function is also declared to be noexcept it basically means that the corresponding function also can't thrown an exception. One example of a function with similar behavior is exit() which terminates the program. I could imagine that functions implementing some sort of application-loop could also qualify. In any case, the [[noreturn]] tells the system that the corresponding function will never normally return, i.e., falling off the function ("after }") will probably result in undefined behavior.

like image 35
Dietmar Kühl Avatar answered Oct 23 '22 15:10

Dietmar Kühl