6
votes

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]

2
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
I think comma operator takes a reference to c, and references break constexpr - Dani
clang bug? I'm not a language layer so, frankly, I don't know. - max66
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
Just log a bug at bugs.llvm.org for it being different, the one answer seems to indicate that GCC is right - JVApen

2 Answers

5
votes

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.

3
votes

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.