5

According to [this Q&A] since c++11 comma operator is constexpr capable. According to [this Q&A] constexpr variable should not be captured by lambda but should be usable inside its body.

Both these rules make following code compilable in clang:

//Example 1

template <int>
struct Foo {};

int main() {
    constexpr int c = 1;
    static_cast<void>(Foo<(c, 2)>{});
}

//Example 2

template <int>
struct Foo {};

int main() {
    constexpr int c = 1;
    auto lambda = []{return c * 2;};
    static_cast<void>(Foo<lambda()>{});
}

However while both these examples compile successfully on clang (that declares constexpr lambda support that is -- 8.0.0) the following snippet doesn't and I can't imagine why... Any ideas?

template <int>
struct Foo {};

int main() {
    constexpr int c = 1;
    auto lambda = []{return (c, 2);};
    static_cast<void>(Foo<lambda()>{});
}

Compilation error:

variable 'c' cannot be implicitly captured in a lambda with no capture-default specified

[live demo]

W.F.
  • 13,888
  • 2
  • 34
  • 81
  • 1
    not an answer but... in wandbox clang++ complain because "variable 'c' cannot be implicitly captured in a lambda with no capture-default specified"; capturing by reference (`[&]`) complain because "reference to 'c' is not a constant expression"; capturing by value (`[=]`) compile without problems. The funny part is that g++ compile in all three cases without problem. – max66 Nov 22 '18 at 19:12
  • 2
    I think comma operator takes a reference to c, and references break constexpr – Daniel Nov 22 '18 at 19:13
  • @max66 huh! haven't tested it with `[=]` this makes things look more as a clang bug, no? – W.F. Nov 22 '18 at 19:15
  • I don't think is a comma problem: I get the same with `auto lambda = []{ c; return 2;};` – max66 Nov 22 '18 at 19:15
  • @max66 ugh so we aren't in place where clang fully supports constexpr lambda yet...? – W.F. Nov 22 '18 at 19:17
  • @Dani do you think it's legit? – W.F. Nov 22 '18 at 19:17
  • 1
    clang bug? I'm not a language layer so, frankly, I don't know. – max66 Nov 22 '18 at 19:18
  • 1
    But works perfectly `constexpr auto lambda = []{ auto a=c; return a;};`; so no problem with `c` value but error when `c` is seen as reference to `c`? – max66 Nov 22 '18 at 19:25
  • Exactly, I find this very suspicious... – W.F. Nov 22 '18 at 19:27
  • 1
    Just log a bug at bugs.llvm.org for it being different, the one answer seems to indicate that GCC is right – JVApen Nov 22 '18 at 21:13
  • @JVApen it doesn't happen cery often :) – W.F. Nov 22 '18 at 21:17

2 Answers2

5

Its seems to be a clang bug, according to [basic.def.odr]/4:

A variable x whose name appears as a potentially-evaluated expression ex is odr-used by ex unless applying the lvalue-to-rvalue conversion (7.1) to x yields a constant expression (8.20) that does not invoke any non-trivial functions and, if x is an object, ex is an element of the set of potential results of an expression e, where either the lvalue-to-rvalue conversion (7.1) is applied to e, or e is a discarded-value expression.

As has been commented, the issue is not limited to the comma operator but for every discarded expressions, these expression doesn't constitute odr-use, hence it must be accepted.

Jans
  • 11,064
  • 3
  • 37
  • 45
3

This is a clang bug, if we look at a simpler case:

constexpr int c = 1;
auto lambda =  [] {return c,2;};

clang also considers this ill-formed (see it live), the lambda is required to capture an automatic variable if it odr-uses it see expr.prim.lambda.capturep8:

An entity is captured if it is captured explicitly or implicitly. An entity captured by a lambda-expression is odr-used in the scope containing the lambda-expression. If *this is captured by a local lambda expression, its nearest enclosing function shall be a non-static member function. If a lambda-expression or an instantiation of the function call operator template of a generic lambda odr-uses this or a variable with automatic storage duration from its reaching scope, that entity shall be captured by the lambda-expression. If a lambda-expression captures an entity and that entity is not defined or captured in the immediately enclosing lambda expression or function, the program is ill-formed. ...

and discarded value expression is not an odr-use.

I found a similar bug report [rejects valid] constexpr non-scalar variable not usable in lambda without capture or local class.

Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
  • Wow I was sure I tested it without calling lambda too, but appearantly I missed that... So you are probably right that the problem runs deeper... – W.F. Nov 23 '18 at 05:06