32

According to cppreference, both gcc and clang have completed the implementation of P1102R2 ("Down with ()!") recently, which means we can define lambda expressions more concisely in C++23.

But I found that they are inconsistent with a certain form:

auto l = []<auto> noexcept requires true {};

clang accepts this form, and gcc rejects its grammar.

Which compiler should I trust? Is this lambda well-formed or ill-formed in C++23?

Update:

Perhaps because of the pressure of public opinion, clang quickly fixed the 49736 within five days after I reported it.

As I tried further, I accidentally found out that gcc also rejected the following valid form, which made me report the 99850 and it was fixed after 2 weeks.

auto l = []<auto> requires true -> void {};
康桓瑋
  • 33,481
  • 5
  • 40
  • 90

1 Answers1

34

Thanks for reminding me of how pointless this feature is.

The correct answer is: no, that's not a well-formed lambda. The grammar is defined in [expr.prim.lambda.general]:

enter image description here

In our case, to start with we have:

[]<auto> noexcept requires true {};
  • [] is the lambda-introducer
  • <auto> matches <template-parameter-list> and now we know we're the 2nd kind lambda-expression. So grammatically, we're need to follow with a requires-clause (optionally) then a lambda-declarator then a compound-statement.
  • noexcept does not match requires-clause, so now we're parsing a lambda-declarator. A lambda-declarator could start with (parameter-declaration-clause) but we don't have that, so we're just looking for lambda-specifiers. We consume the noexcept as part of noexcept-specifier.
  • requires true does not fit either attribute-specifier-seq or trailing-return-type so we have neither of those, and now we're done with lambda-specifiers so we're done with lambda-declarator. At this point, we're looking for a compound-statement. But we don't have that, so this is an error.

Basically, there are two spots you can put a requires-clause: either directly after the template parameters or, if we have function parameters, after the lambda-specifiers after the function parameters. So this works:

[]<auto> requires true noexcept {};

as does this:

[]<auto>() noexcept requires true {};

as does this:

[]<auto> requires true () noexcept requires true { };

But not the one in OP.

Also, don't write this.

cigien
  • 57,834
  • 11
  • 73
  • 112
Barry
  • 286,269
  • 29
  • 621
  • 977
  • 3
    I filed a [bug report](https://bugs.llvm.org/show_bug.cgi?id=49736) for llvm this morning, but I am not 100% sure that it should be ill-formed. Thanks for letting me know I'm right. – 康桓瑋 Mar 27 '21 at 17:41
  • An additional point: Would making it defined remove a wart, making the language more regular, and should it thus be defined? Contrived examples being contrived isn't all that surprising though. – Deduplicator Mar 28 '21 at 17:52
  • @Deduplicator Should it? I mean, if you're at the point where you're already writing template parameters _and_ a noexcept-specifier _and_ a requires-clause, are you really harmed by having to provide an extra `()`? – Barry Mar 28 '21 at 19:03
  • @Barry Would it make it more regular? Is it unambiguous what it should do? Having a simple workaround at most lowers priority. – Deduplicator Mar 28 '21 at 20:13
  • 2
    @Deduplicator: It was simply not considered worthwhile to make a complicated grammar to make a non-empty *lambda-specifiers* differentiate the two potential *requires-clause*s. – Davis Herring Mar 29 '21 at 02:46
  • 5
    The observation that led to the current rule is that the requires-clause is either constraining the explicit template parameter list or the explicit function parameter list. As such, an explicit `<>` list can be followed by a requires-clause, and an explicit `()` list can be followed by a requires-clause. If you omit the explicit list, you can't include a requires clause for it. – Richard Smith Mar 30 '21 at 05:29