Подтвердить что ты не робот

Еще одно несоответствие clang/gcc в отношении использования ODR?

Почему этот код компилируется с помощью GCC (4.9 и 5+), но не с clang (3.5-3.9)?

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

У меня есть неопределенное представление о том, что расхождение связано с использованием ODR (One Definition Rule), но я не понимаю этого достаточно хорошо, чтобы понять, что происходит здесь.

4b9b3361

Ответ 1

x используется odr, поскольку он привязан к эталонному параметру (test). Поэтому он должен быть захвачен ([expr.prim.lambda]/13):

Если лямбда-выражение или инстанцирование вызова функции шаблон оператора общего использования лямбда-odr ([basic.def.odr]) thisили переменная с автоматическим временем хранения от ее объема охвата, этот объект должен быть захвачен лямбда-выражением.

Нарушения этого правила, как и все другие правила в стандарте, которые не говорят "нет необходимости в диагностике" или "поведение w90", требуют диагностики.

GCC, к сожалению, выполняет постоянную фальцовку слишком рано, прежде чем он сможет определить, является ли это неприемлемым или нет. Это может привести к проблемам например, [&]()->const int & { return x; }, возвращающему ссылку на обвиску.

Ответ 2

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 печатает разные адреса для переменной-записями, чем оригинал!