8
votes

The following code does not compile in clang (it does in GCC):

struct A{
    int a;
};

auto test(){
    constexpr A x{10};
    return []{
        return x; // <-- here x is A: clang doesn't compile
    }();
}

Clang's error is variable 'x' cannot be implicitly captured in a lambda with no capture-default specified, but I thought that constexpr variables were always captured.

If x is an int, the code compiles:

auto test(){
    constexpr int x{10};
    return []{
        return x; // <-- here x is int: clang is ok
    }();
}

Interestingly, the following code also compiles:

auto test(){
    constexpr A x{10};
    return []{
        return x.a;
    }();
}

Is clang right? If so, what is the rationale? I'm using -std=c++17

--EDIT--

The following question: Can I use a constexpr value in a lambda without capturing it? is not related to this one, as with clang11 it is not anymore an issue: in fact, as stated above, if x is an int, clang11 compiles.

Sample code also present in https://godbolt.org/z/rxcYjz

1
Make sure to add the c++ tag to C++ questions so that more users will see the post.cigien
"The following question: Can I use a constexpr value in a lambda without capturing it? is not related to this one, as with clang11 it is not anymore an issue: in fact, as stated above, if x is an int, clang11 compiles." It's literally the same thing.Asteroids With Wings
@AsteroidsWithWings, the difference is that in that question it's not even possible to use an int. Now an int is ok, any other object is not. Is it still an issue with clang?Mario Demontis
@MarioDemontis It's not that you've used an int; it's that you've named a member (which is an odr-use of x). It's the same question and bug. x itself is not an int in either of your examples.Asteroids With Wings
Ok now I've added a second snippet in between. I don't understand why the 1st one fails and the 2nd one is okMario Demontis

1 Answers

2
votes

When you return x; in the first example, you have to invoke A’s copy constructor, which involves binding a reference to x and thus odr-uses it. The argument can be made that a trivial copy of a value usable in constant expressions shouldn’t constitute an odr-use any more than return x.a;, but there’s no such exception in that rule, so Clang is correct to reject it.

As a practical matter, you can of course make any constexpr variable static to avoid any need to capture it.