Является ли gcc или clang правильной об этом поведении?

У меня есть небольшая игрушечная программа:

static int value = 0;

int function(int &value=value) {
    return value;
}

int main() {
    function();
}

Компиляция с g++ 7.2:

g++ -std = С++ 11 -Wall -Wextra test.cc -o test

Нет проблем.

Компиляция с кланом g++ -3.9:

clan g++ -3.9 -std = С++ 11 -Wall -Wextra test.cc -o test

test.cc:3:25: error: default argument references parameter 'value'
int function(int &value=value) {
                        ^~~~~
test.cc:8:5: error: no matching function for call to 'function'
    function();
    ^~~~~~~~
test.cc:3:5: note: candidate function not viable: requires single argument 'value', but no arguments were provided
int function(int &value=value) {
    ^
2 errors generated.

Kaboom. Кто прав?

Ответы

Ответ 1

Я думаю, что clang правильный. Из basic.scope.pdecl:

Точка объявления для имени сразу же после его полного объявления (Clause [dcl.decl]) и перед его инициализатором (если есть), кроме как указано ниже. [ Пример:

int x = 12;{ int x = x; }

Здесь второй x инициализируется собственным (неопределенным) значением. - конец примера]

Кроме того, из dcl.fct.default:

Аргументы по умолчанию оцениваются каждый раз при вызове функции. Порядок оценки аргументов функции не указан. Следовательно, параметры функции не должны использоваться в аргументе по умолчанию, даже если они не оцениваются. Параметры функции, объявленной до аргумента по умолчанию, находятся в области видимости и могут скрыть пространства имен и имена членов класса

Ответ 2

Поскольку OP помечен как С++ 11, я проверил эту версию стандарта и в подпункте 11 [basic.lookup.unqual], в котором явно указано, что:

Во время поиска имени, используемого в качестве аргумента по умолчанию (8.3.6) в объявлении функции-объявления-предложения или используемого в выражении mem-initializer для конструктора (12.6.2), имена параметров функции видны и скрыть имена объектов, объявленных в блоках, классах или пространствах пространства имен, содержащих объявление функции.

Таким образом, clang является правильным.

Ответ 3

Клэнг здесь прав. Сначала область параметров функции определяется как:

Параметр функции (включая один, который появляется в лямбда-деклараторе) или функционально-локальная предопределенная переменная ([dcl.fct.def]) имеет область параметров функции. Потенциальная область параметра или локальная предопределенная переменная функции начинается с момента ее объявления. [...]

и точка объявления определяется как

Точка объявления для имени сразу же после его полного декларатора и перед его инициализатором (если есть), за исключением случаев, указанных ниже. [ Пример:

unsigned char x = 12;
{ unsigned char x = x; }

Здесь второй x инициализируется собственным (неопределенным) значением. - конец примера]

Таким образом, value должно быть value вы только что объявили, а не тем из глобального пространства