GCC and Clang disagree about C++17 constexpr lambda captures

眉间皱痕 提交于 2019-11-30 17:25:32

Both implementations are bugged, but I'm inclined to think that GCC got the right answer here.


Dropping the capture of i causes Clang to refuse to compile the code. That means it clearly has a bug somewhere.

[expr.const]/2.12:

An expression e is a core constant expression unless the evaluation of e, following the rules of the abstract machine, would evaluate one of the following expressions:

  • [...]
  • in a lambda-expression, a reference to [...] a variable with automatic storage duration defined outside that lambda-expression, where the reference would be an odr-use;
  • [...]

Clang's behavior is schizophrenic: if the use of i in the body is not an odr-use, then it doesn't need to be captured, yet it rejects the code in the OP if the explicit capture is removed; OTOH, if it is an odr-use, then by the above unwrap(i) isn't a constant expression, and so it should reject the initialization of x.


GCC's lambda implementation is woefully bad with respect to odr-use. It does constant-folding ultra-early, resulting in all kinds of subtle mischief. On the other hand, for explicit captures it transforms all uses, whether or not it's actually an odr-use. The aggressive constant folding means that it accepts OP's code if the capture of i is removed.

Assuming that unwrap(i) does odr-use i, then it is correct that, per [expr.const]/2.12, OP's code is ill-formed.


Does unwrap(i) actually odr-use i? That question boils down to whether copy-initializing the parameter object of unwrap counts as applying an lvalue-to-rvalue conversion to i. I don't see anything in the standard that explicitly says that an lvalue-to-rvalue conversion is applied here, and instead [dcl.init]/17.6.2 indicates that we call a constructor (in this case, the trivial implicitly defined copy constructor) passing i as the argument bound to its parameter, and reference binding is a classic example of odr-use.

To be sure, applying an l-to-r conversion would result in a copy-initialization of an integral_constant<int, 42> object from i, but the problem here is that nothing in the standard says the converse - that all copy-initializations of an integral_constant<int, 42> object from i count as l-to-r conversions.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!