PDA

View Full Version : How to declare attribute 'noreturn'



JustBobC
24th May 2019, 21:05
I just opened a project in QT Creator 4.9 and in the application .cpp I get a warning that this function could include attribute 'noreturn', but I have not found how to declare this. I find examples of code such as:

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

void q [[ noreturn ]] (int i) {
// behavior is undefined if called with an argument <= 0
if (i > 0) {
throw "positive";
}
}

but no clue as to where this goes--in the function .cpp? or the main.cpp? before the function? within the function?
and I'm not at all familiar with the syntax [[ something ]].

Or does it even matter whether the attribute is declared or not?

Thanks,
Bob

ChrisW67
25th May 2019, 04:44
The items between [[ ]] in a function (variable...) declaration are attributes that provide the compiler with extra information about the item they are attached to. The compiler can use these in a range of ways. The "noreturn" attribute has been around since C++ 11.

[[ noreturn ]] attached to a function declaration informs the compiler that control will not return from the function (as in the case of an unconditional throw()). They go in the first declaration of the function. If f() is declared in a header file then this is the place to put it. If the function exists only in a single CPP file, i.e. it is private, with no other declaration then it goes there.

The second code snippet you posted is an example that can lead to undefined behaviour, i.e. returning from a function you explicitly declared would not return control.



// >>> function.h
#ifndef FUNCTION_H
#define FUNCTION_H

[[ noreturn ]] void f();
void g();

#endif // FUNCTION_H

// >>> function.cpp
#include <iostream>
using namespace std;

#include "function.h"

void f() {
cout << "No return" << endl;
throw 1;
}

void g() {
cout << "No return" << endl;;
throw 1;
}

// >>> main.cpp
#include <iostream>
using namespace std;

#include "function.h"

[[ noreturn ]] void h() {
cout << "No return" << endl;
throw 3;
}

int main(int argc, char **argv) {
cout << "Before f()" << endl;
f();
// this should be unreachable code
cout << "Before g()" << endl;
g();
cout << "Before h()" << endl;
h();
}


Functions f() and g() have identical function code but, because the compiler knows that f() will not return, it may generate different code for these function or calls to them. In my experiments with GNU C++ there is no code generated for the calls to g() and h() because they cannot be reached after a call to f().

d_stranz
25th May 2019, 18:59
In my experiments with GNU C++ there is no code generated for the calls to g() and h() because they cannot be reached after a call to f().

Wow, that seems like a recipe for descent into debugging hell and unsupportable code. What looks like perfectly acceptable code isn't, but that cannot be determined unless you are aware of the declaration of f().

Corny
24th October 2019, 18:26
I realize this post is a little bit old, but I didn't see the solution that I had found so I thought I would respond. This may only be relevant if you're using MinGW. I found the following on the GCC online documentation web site at https://gcc.gnu.org/onlinedocs/gcc-4.7.2/gcc/Function-Attributes.html.


You may also specify attributes with `__' preceding and following each keyword. This allows you to use them in header files without being concerned about a possible macro of the same name. For example, you may use __noreturn__ instead of noreturn.
...
Some programs define their own functions that never return. You can declare them noreturn to tell the compiler this fact. For example,


void fatal () __attribute__ ((noreturn));
void
fatal (/* ... */)
{
/* ... */ /* Print error message. */ /* ... */
exit (1);
}


This solved my problem, hope it helps anybody else in this situation.