Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to declare a lambda's operator() as noreturn?

How can the operator() of a lambda be declared as noreturn ?

Ideone accepts the following code:

#include <cstdlib>  
int main() {
    []() [[noreturn]] { std::exit(1); }();
    return 0;
}

Clang 3.5 rejects it with:

error: 'noreturn' attribute cannot be applied to types

You can try it in godbolt: http://goo.gl/vsuCsF

Which one is right?

Update: the relevant standard sections appear to be 5.1.2.5, 7.6.3, 7.6.4 but after reading does it still isn't 100% clear to me (i) what is the right behavior, (ii) how to mark the operator() of a lambda as noreturn.

like image 715
gnzlbg Avatar asked Nov 12 '14 14:11

gnzlbg


2 Answers

Clang is correct. An attribute can appertain to a function being declared, or to its type; the two are different. [[noreturn]] must appertain to the function itself. The difference can be seen in

// [[noreturn]] appertains to the entity that's being declared
void f [[noreturn]] ();    // §8.3 [dcl.meaning]/p1:
                           // The optional attribute-specifier-seq following a
                           // declarator-id appertains to the entity that is declared."
[[noreturn]] void h ();    // §7 [dcl.dcl]/p2:
                           // "The attribute-specifier-seq in a simple-declaration 
                           // appertains to each of the entities declared by
                           // the declarators of the init-declarator-list."

// ill-formed - [[noreturn]] appertains to the type (§8.3.5 [dcl.fct]/p1: 
// "The optional attribute-specifier-seq appertains to the function type.")
void g () [[noreturn]] {}

Indeed if you compile this in g++ it tells you that

warning: attribute ignored [-Wattributes]
 void g () [[noreturn]] {}
                      ^
note: an attribute that appertains to a type-specifier is ignored

Note that it doesn't emit a warning that g() actually does return.

Since an "attribute-specifier-seq in the lambda-declarator appertains to the type of the corresponding function call operator or operator template" (§5.1.2 [expr.prim.lambda]/p5) rather than to that operator/operator template itself, you can't use [[noreturn]] there. More generally, the language provides no way for you to apply an attribute to the operator () of a lambda itself.

like image 84
T.C. Avatar answered Oct 07 '22 00:10

T.C.


So a lambda delcarator has the following grammar the draft C++ standard section 5.1.2 Lambda expressions:

( parameter-declaration-clause ) mutableopt exception-specificationopt attribute-specifier-seqopt trailing-return-typeopt

and the noreturn attribute is indeed a valid attribute-specifier-seq so from a grammar perspective I don't see a restriction from section 7.6.3 Noreturn attribute it says (emphasis mine going forward):

[...]The attribute may be applied to the declarator-id in a function declaration.[...]

which does not seem to forbid your use but it does suggest that it is not allowed. If we look at section 7.6.4 Carries dependency attribute it says:

[...]The attribute may be applied to the declarator-id of a parameter-declaration in a function declaration or lambda[...]

the fact that it explicitly includes the lamda case strongly indicates that section 7.6.3 is meant to exclude lambdas and therefore clang would be correct. As a side note Visual Studio also rejects this code.

like image 36
Shafik Yaghmour Avatar answered Oct 07 '22 01:10

Shafik Yaghmour