Skip to content

Commit

Permalink
[C++17] Reject shadowing of capture by parameter in lambda
Browse files Browse the repository at this point in the history
Summary:
This change rejects the shadowing of a capture by a parameter in lambdas in C++17.

```
int main() {
  int a;
  auto f = [a](int a) { return a; };
}
```

results in:

```
main.cpp:3:20: error: a lambda parameter cannot shadow an explicitly captured entity
  auto f = [a](int a) { return a; };
                   ^
main.cpp:3:13: note: variable a is explicitly captured here
  auto f = [a](int a) { return a; };
            ^
```

Reviewers: rsmith

Reviewed By: rsmith

Subscribers: lebedev.ri, erik.pilkington, cfe-commits

Differential Revision: https://reviews.llvm.org/D53595

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@345308 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
Rakete1111 committed Oct 25, 2018
1 parent e2c6f96 commit 5897428
Show file tree
Hide file tree
Showing 6 changed files with 39 additions and 7 deletions.
4 changes: 4 additions & 0 deletions include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -6630,6 +6630,10 @@ let CategoryName = "Lambda Issue" in {
def ext_star_this_lambda_capture_cxx17 : ExtWarn<
"capture of '*this' by copy is a C++17 extension">, InGroup<CXX17>;

// C++17 parameter shadows capture
def err_parameter_shadow_capture : Error<
"a lambda parameter cannot shadow an explicitly captured entity">;

// C++2a [=, this] captures.
def warn_cxx17_compat_equals_this_lambda_capture : Warning<
"explicit capture of 'this' with a capture default of '=' is incompatible "
Expand Down
4 changes: 3 additions & 1 deletion include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -5580,7 +5580,9 @@ class Sema {
void finishLambdaExplicitCaptures(sema::LambdaScopeInfo *LSI);

/// Introduce the lambda parameters into scope.
void addLambdaParameters(CXXMethodDecl *CallOperator, Scope *CurScope);
void addLambdaParameters(
ArrayRef<LambdaIntroducer::LambdaCapture> Captures,
CXXMethodDecl *CallOperator, Scope *CurScope);

/// Deduce a block or lambda's return type based on the return
/// statements present in the body.
Expand Down
20 changes: 17 additions & 3 deletions lib/Sema/SemaLambda.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -493,15 +493,29 @@ void Sema::finishLambdaExplicitCaptures(LambdaScopeInfo *LSI) {
LSI->finishedExplicitCaptures();
}

void Sema::addLambdaParameters(CXXMethodDecl *CallOperator, Scope *CurScope) {
void Sema::addLambdaParameters(
ArrayRef<LambdaIntroducer::LambdaCapture> Captures,
CXXMethodDecl *CallOperator, Scope *CurScope) {
// Introduce our parameters into the function scope
for (unsigned p = 0, NumParams = CallOperator->getNumParams();
p < NumParams; ++p) {
ParmVarDecl *Param = CallOperator->getParamDecl(p);

// If this has an identifier, add it to the scope stack.
if (CurScope && Param->getIdentifier()) {
CheckShadow(CurScope, Param);
bool Error = false;
// Resolution of CWG 2211 in C++17 renders shadowing ill-formed, but we
// retroactively apply it.
for (const auto &Capture : Captures) {
if (Capture.Id == Param->getIdentifier()) {
Error = true;
Diag(Param->getLocation(), diag::err_parameter_shadow_capture);
Diag(Capture.Loc, diag::note_var_explicitly_captured_here)
<< Capture.Id << true;
}
}
if (!Error)
CheckShadow(CurScope, Param);

PushOnScopeChains(Param, CurScope);
}
Expand Down Expand Up @@ -1142,7 +1156,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
LSI->ContainsUnexpandedParameterPack = ContainsUnexpandedParameterPack;

// Add lambda parameters into scope.
addLambdaParameters(Method, CurScope);
addLambdaParameters(Intro.Captures, Method, CurScope);

// Enter a new evaluation context to insulate the lambda from any
// cleanups from the enclosing full-expression.
Expand Down
11 changes: 11 additions & 0 deletions test/CXX/drs/dr22xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,14 @@ struct AnonBitfieldQualifiers {
const volatile unsigned i3 : 1;
};
}

#if __cplusplus >= 201103L
namespace dr2211 { // dr2211: 8
void f() {
int a;
auto f = [a](int a) { (void)a; }; // expected-error {{a lambda parameter cannot shadow an explicitly captured entity}}
// expected-note@-1{{variable 'a' is explicitly captured here}}
auto g = [=](int a) { (void)a; };
}
}
#endif
5 changes: 3 additions & 2 deletions test/SemaCXX/warn-shadow-in-lambdas.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// RUN: %clang_cc1 -std=c++14 -verify -fsyntax-only -Wshadow -D AVOID %s
// RUN: %clang_cc1 -std=c++14 -verify -fsyntax-only -Wshadow -Wshadow-uncaptured-local %s
// RUN: %clang_cc1 -std=c++14 -verify -fsyntax-only -Wshadow-all %s
// RUN: %clang_cc1 -std=c++17 -verify -fsyntax-only -Wshadow-all %s

void foo(int param) { // expected-note 1+ {{previous declaration is here}}
int var = 0; // expected-note 1+ {{previous declaration is here}}
Expand Down Expand Up @@ -79,7 +80,7 @@ void foo(int param) { // expected-note 1+ {{previous declaration is here}}
int var = 1; // expected-warning {{declaration shadows a local variable}}
};
auto f2 = [param] // expected-note {{variable 'param' is explicitly captured here}}
(int param) { ; }; // expected-warning {{declaration shadows a local variable}}
(int param) { ; }; // expected-error {{a lambda parameter cannot shadow an explicitly captured entity}}
}

// Warn for variables defined in the capture list.
Expand Down Expand Up @@ -135,7 +136,7 @@ void foo(int param) { // expected-note 1+ {{previous declaration is here}}
auto g2 = [=](auto param) { ; }; // expected-warning {{declaration shadows a local variable}}
#endif
auto g3 = [param] // expected-note {{variable 'param' is explicitly captured here}}
(auto param) { ; }; // expected-warning {{declaration shadows a local variable}}
(auto param) { ; }; // expected-error {{a lambda parameter cannot shadow an explicitly captured entity}}
}

void avoidWarningWhenRedefining() {
Expand Down
2 changes: 1 addition & 1 deletion www/cxx_dr_status.html
Original file line number Diff line number Diff line change
Expand Up @@ -13081,7 +13081,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2211">2211</a></td>
<td>C++17</td>
<td>Hiding by lambda captures and parameters</td>
<td class="none" align="center">Unknown</td>
<td class="svn" align="center">SVN</td>
</tr>
<tr class="open" id="2212">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2212">2212</a></td>
Expand Down

0 comments on commit 5897428

Please sign in to comment.