8

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

Mario Demontis
  • 469
  • 3
  • 11
  • 2
    Make sure to add the c++ tag to C++ questions so that more users will see the post. – cigien Dec 09 '20 at 22:48
  • _"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 Dec 10 '20 at 12:01
  • @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 Dec 10 '20 at 12:26
  • @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 Dec 10 '20 at 13:35
  • Ok now I've added a second snippet in between. I don't understand why the 1st one fails and the 2nd one is ok – Mario Demontis Dec 10 '20 at 13:45
  • It's not particularly useful to obsess over every possible permutation of a bug like this. It's broken, that's all you need to know – Asteroids With Wings Dec 10 '20 at 13:52
  • Maybe the bug is similar, but it's not the same. Try to compile the snippet in " Can I use a constexpr value in a lambda without capturing it? " . It works also with clang5! – Mario Demontis Dec 10 '20 at 14:02

1 Answers1

3

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.

Davis Herring
  • 36,443
  • 4
  • 48
  • 76