]> granicus.if.org Git - clang/commitdiff
[C++17] Reject shadowing of capture by parameter in lambda
authorNicolas Lesser <blitzrakete@gmail.com>
Thu, 25 Oct 2018 20:15:03 +0000 (20:15 +0000)
committerNicolas Lesser <blitzrakete@gmail.com>
Thu, 25 Oct 2018 20:15:03 +0000 (20:15 +0000)
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

include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Sema/Sema.h
lib/Sema/SemaLambda.cpp
test/CXX/drs/dr22xx.cpp
test/SemaCXX/warn-shadow-in-lambdas.cpp
www/cxx_dr_status.html

index aeaff242f7232d0229f3694346cfc431915f6ebc..2b899f2be15c9388b9c85e048e3ba53e7b7d1e9e 100644 (file)
@@ -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 "
index f0c024e9a18706d93d82d3b1351b8a7d9e03aac9..430a851d2530d0b5e71cbbc215acb21f0d073869 100644 (file)
@@ -5580,7 +5580,9 @@ public:
   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.
index 803b253e45859058e928e3142f551242bd1d09f6..aa60ce113dcbcd7c779fcd904077f73a46d9edc6 100644 (file)
@@ -493,7 +493,9 @@ 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) {
@@ -501,7 +503,19 @@ void Sema::addLambdaParameters(CXXMethodDecl *CallOperator, Scope *CurScope) {
 
     // 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);
     }
@@ -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.
index 021707d876b7e141e076bb152eac304af0853f83..70a26db757c3e16821303c30b8cb227c44cdae9c 100644 (file)
@@ -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
index b0dcd122a540d11683744b4b265b01ae564b06ce..a772af049ab41d5e098a99b3b3fd97ff2d1a36e7 100644 (file)
@@ -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}}
@@ -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.
@@ -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() {
index 44fdf8f17fe8c753dc1d744f011646edb937ce76..460978260f18cb1777a7ea7531f93dd47052d48c 100755 (executable)
@@ -13081,7 +13081,7 @@ and <I>POD class</I></td>
     <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>