Update: as promised by the Core chair in the bottom quote, the code is now ill-formed:
If an identifier in a simple-capture appears as the declarator-id of a parameter of the lambda-declarator's parameter-declaration-clause, the program is ill-formed.
There were a few issues concerning name lookup in lambdas a while ago. They were resolved by N2927:
The new wording no longer relies on lookup to remap uses of captured entities. It more clearly
denies the interpretations that a lambda's compound-statement is processed in two passes or that any names in that compound-statement might resolve to a member of the closure type.
Lookup is always done in the context of the lambda-expression, never "after" the transformation to a closure type's member function body. See [expr.prim.lambda]/8:
The lambda-expression's compound-statement yields the function-body ([dcl.fct.def]) of the function call operator, but for purposes of name lookup, […], the compound-statement is considered in the context of the lambda-expression. [ Example:
struct S1 {
int x, y;
int operator()(int);
void f() {
[=]()->int {
return operator()(this->x+y); // equivalent to: S1::operator()(this->x+(*this).y)
// and this has type S1*
};
}
};
—end example ]
(The example also makes clear that lookup does not somehow consider the generated capture member of the closure type.)
The name foo
is not (re)declared in the capture; it is declared in the block enclosing the lambda expression. The parameter foo
is declared in a block that is nested in that outer block (see [basic.scope.block]/2, which also explicitly mentions lambda parameters). The order of lookup is clearly from inner to outer blocks. Hence the parameter should be selected, that is, Clang is right.
If you were to make the capture an init-capture, i.e. foo = ""
instead of foo
, the answer would not be clear. This is because the capture now actually induces a declaration whose "block" is not given. I messaged the core chair on this, who replied
This is issue 2211 (a new issues list will appear on the open-std.org site shortly, unfortunately with just placeholders for a number of issues, of which this is one; I'm working hard to fill in those gaps before the Kona meeting at the end of the month). CWG discussed this during our January teleconference, and the direction is to make the program ill-formed if a capture name is also a parameter name.