39

I have a little toy program:

static int value = 0;

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

int main() {
    function();
}

Compiling with g++ 7.2:

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

No problem.

Compiling with clang++-3.9:

clang++-3.9 -std=c++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. Who's right?

user17732522
  • 53,019
  • 2
  • 56
  • 105
gct
  • 14,100
  • 15
  • 68
  • 107
  • 5
    `int function(int &value=value)` looks really weird to me. I'd change that to `int function(int &value = ::value)` so it refers to the global `value` instead of the reference being bound to itself. – Eljay Feb 13 '18 at 16:45
  • 6
    @Eljay `gcc` binds it to the global `value` with `int& value = value`, but I think it's wrong according to the current standard. – Holt Feb 13 '18 at 16:46
  • 2
    just curious - when you run the gcc one, what's the value of the local value? (ohh god, that question has all gone wrong)... – UKMonkey Feb 13 '18 at 16:46
  • 2
    Judging by the fact that you can use `decltype(param)` in the default argument, I'd say the parameter name is in scope and GCC is wrong, but that's not a very strong basis. – chris Feb 13 '18 at 16:49
  • 1
    @UKMonkey [Apparently](http://coliru.stacked-crooked.com/a/cfaa2cc9ca1a2594) it is the actual value of `::value`, i.e. the reference does not bind to itself. – Quentin Feb 13 '18 at 16:50

3 Answers3

34

I think clang is correct. From basic.scope.pdecl:

The point of declaration for a name is immediately after its complete declarator (Clause [dcl.decl]) and before its initializer (if any), except as noted below. [ Example:

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

Here the second x is initialized with its own (indeterminate) value. — end example ]

Also, from dcl.fct.default:

Default arguments are evaluated each time the function is called. The order of evaluation of function arguments is unspecified. Consequently, parameters of a function shall not be used in a default argument, even if they are not evaluated. Parameters of a function declared before a default argument are in scope and can hide namespace and class member names

R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • 3
    That looks like the answer, surprised gcc missed that one. – gct Feb 13 '18 at 16:57
  • @SeanMcAllister, yes, it is surprising that g++ would miss this one. – R Sahu Feb 13 '18 at 16:58
  • 1
    But this quote does not prohibit default argument from referencing function parameter as clang complains. – user7860670 Feb 13 '18 at 17:00
  • 2
    @VTT [This one](https://timsong-cpp.github.io/cppwp/n3337/dcl.fct.default#9) does. – Holt Feb 13 '18 at 17:07
  • The only use case would be to take the address of the parametrr to define its own value. Who ever did it? Why exposing coder to mistakes for such a unusefull case? The standard is wrong, so gcc is right to be wrong. – Oliv Feb 13 '18 at 20:54
  • @Oliv, care to elaborate that with a live, or semi-live, example? – R Sahu Feb 13 '18 at 20:57
  • `void foo(ptrdiff_t x = reinterpret_cast( &x))` taking the address of x before its lifetime has begun is ok, accessing its value is UB in its definition... this is the only use case I see where naming the variable being defined could be not UB. This is essentialy useless. Not talking obviously of unevaluated opperand as decltype... while we already have the type! – Oliv Feb 13 '18 at 21:37
18

Since the OP tagged the question as c++11 I checked that version of the standard and in [basic.lookup.unqual] sub-clause 11 it states explicitly that:

During the lookup for a name used as a default argument (8.3.6) in a function parameter-declaration-clause or used in the expression of a mem-initializer for a constructor (12.6.2), the function parameter names are visible and hide the names of entities declared in the block, class or namespace scopes containing the function declaration.

Thus, clang is correct.

llllllllll
  • 16,169
  • 4
  • 31
  • 54
Johan
  • 3,667
  • 6
  • 20
  • 25
8

Clang is correct here. First a function's parameter scope is defined as:

A function parameter (including one appearing in a lambda-declarator) or function-local predefined variable ([dcl.fct.def]) has function parameter scope. The potential scope of a parameter or function-local predefined variable begins at its point of declaration.[...]

and the point of declaration is defined as

The point of declaration for a name is immediately after its complete declarator and before its initializer (if any), except as noted below. [ Example:

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

Here the second x is initialized with its own (indeterminate) value. — end example ]

So value should be the value you just declared and not the one from the global space

Community
  • 1
  • 1
NathanOliver
  • 171,901
  • 28
  • 288
  • 402