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?

5 upvote
  flag
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
6 upvote
  flag
@Eljay gcc binds it to the global value with int& value = value, but I think it's wrong according to the current standard. – Holt
2 upvote
  flag
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
2 upvote
  flag
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
1 upvote
  flag
@UKMonkey Apparently it is the actual value of ::value, i.e. the reference does not bind to itself. – Quentin

3 Answers 11

up vote 29 down vote accepted

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

3 upvote
  flag
That looks like the answer, surprised gcc missed that one. – Sean McAllister
upvote
  flag
@SeanMcAllister, yes, it is surprising that g++ would miss this one. – R Sahu
1 upvote
  flag
But this quote does not prohibit default argument from referencing function parameter as clang complains. – VTT
2 upvote
  flag
@VTT This one does. – Holt
upvote
  flag
@Holt, thanks for looking that up. – R Sahu
upvote
  flag
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
upvote
  flag
@Oliv, care to elaborate that with a live, or semi-live, example? – R Sahu
upvote
  flag
void foo(ptrdiff_t x = reinterpret_cast<ptrdiff_t>( &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

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

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.

Not the answer you're looking for? Browse other questions tagged or ask your own question.