19
votes

I've never seen [[ noreturn ]] used on non-void returning functions before.

Is the following well defined?

[[ noreturn ]] int function();

int function(){
  while(true){/* impl */}
  return 0;
}

The reason the return type must be int, is because the function is passed to another function via a function pointer.

So assuming the caller looks something like this:

//call the non-returning function
int var = (*fptr)();

//use var some way (even though the function will never actually return)
std::cout << var;

will this exhibit any kind of undefined behavior?

3
You might run into pedantic trouble with the allowance of the implementation to assume that an infinite loop ends. (link)chris
@chris I'm hoping to tag the return value with [[maybe_unused]] as well.Trevor Hickey
From the link you posted : The behavior is undefined if the function with this attribute actually returns.101010

3 Answers

24
votes

The standard specification on [[noreturn]] is in [dcl.attr.noreturn]. The entire normative texts reads:

The attribute-token noreturn specifies that a function does not return. It shall appear at most once in each attribute-list and no attribute-argument-clause shall be present. The attribute may be applied to the declarator-id in a function declaration. The first declaration of a function shall specify the noreturn attribute if any declaration of that function specifies the noreturn attribute. If a function is declared with the noreturn attribute in one translation unit and the same function is declared without the noreturn attribute in another translation unit, the program is ill-formed; no diagnostic required.

If a function f is called where f was previously declared with the noreturn attribute and f eventually returns, the behavior is undefined.

There is no mention of return type. The only thing that matters is that the function not return. If the function returns (whether void or int or vector<vector<double>>), then behavior is undefined. If the function doesn't return, the return type is immaterial.

10
votes

From the C++ standard §7.6.8/p2 Noreturn attribute [dcl.attr.noreturn] (Emphasis Mine):

If a function f is called where f was previously declared with the noreturn attribute and f eventually returns, the behavior is undefined. [ Note: The function may terminate by throwing an exception. — end note ] [ Note: Implementations are encouraged to issue a warning if a function marked [[noreturn]] might return. — end note ]

Since your function will never reach the return 0; there's no UB.

0
votes

I have found one practical example of a non-void [[noreturn]] function. It is in a case, when used in ?: operator to provide a correct result type of ?: operator:

template <class T> [[noreturn]] T fail(char const *s) noexcept { puts(s); exit(1); }
enum E { V1, V2 };
int f(E e) {
  return (e == V1) ? 1 : (e == V2) ? 2 : fail<E>("bad e");
}

Note: One could have a feeling that [[noreturn]] functions in ?: operator could be ignored for calculation of ?: result type. But it is not possible because [[noreturn]] is not a part of result type of an expression (fail<T>("") has result type T and not [[noreturn]] T).