关于 ODR 使用的另一个 clang/gcc 差异?

Yet another clang/gcc discrepancy regarding ODR usage?

为什么这段代码可以用 GCC(4.9 和 5+)编译,但不能用 clang (3.5-3.9) 编译?

void test(const int&) { }
int main() {
  const int x = 42;
  auto f = []{ test(x); };
}

我有一些模糊的想法,认为差异与 ODR(单一定义规则)的使用有关,但我不太了解,无法弄清楚这里发生了什么。

x 被 odr 使用,因为它绑定到一个引用(test 的参数)。因此必须捕获它 ([expr.prim.lambda]/13):

If a lambda-expression or an instantiation of the function call operator template of a generic lambda odr-uses ([basic.def.odr]) this or a variable with automatic storage duration from its reaching scope, that entity shall be captured by the lambda-expression.

违反此规则,与标准中未提及 "no diagnostic required" 或 "undefined behavior"、require a diagnostic.

的所有其他规则一样

不幸的是,GCC 过早地执行常量折叠,在它可以判断它是否是 odr-use 之前。这可能会导致问题 such as [&]()->const int & { return x; } returning a dangling reference.

T.C。有正确的诊断,这是更清晰的法律代码,其中 clang 做正确的事而 gcc 没有:

#include <iostream>

void test(const int&a) { std::cout << "in test() -- " << &a << "\n"; }
int main() {
  const int x = 42;
  std::cout << "in main() -- " << &x << "\n";
  auto f = [&]{ test(x); };
  f();
}

gcc 为引用捕获变量打印的地址与原始地址不同!