]> granicus.if.org Git - clang/commitdiff
Allow implicit capture of 'this' in a lambda even when the capture
authorDouglas Gregor <dgregor@apple.com>
Fri, 10 Feb 2012 17:46:20 +0000 (17:46 +0000)
committerDouglas Gregor <dgregor@apple.com>
Fri, 10 Feb 2012 17:46:20 +0000 (17:46 +0000)
default is '=', and reword the warning about explicitly capturing
'this' in such lambdas to indicate that only explicit capture is
banned.

Introduce Fix-Its for this and other "save the programmer from
themself" rules regarding what can be explicitly captured and what
must be implicitly captured.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@150256 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Sema/DeclSpec.h
lib/Parse/ParseExprCXX.cpp
lib/Sema/SemaExprCXX.cpp
lib/Sema/SemaLambda.cpp
test/CXX/expr/expr.prim/expr.prim.lambda/p8.cpp
test/FixIt/fixit-cxx0x.cpp

index b79c48a224ebc7de18bc7d039c3a0b82831506dc..0caf192fad369f4a83e0bf61447a7f0202590f86 100644 (file)
@@ -4093,7 +4093,7 @@ def err_capture_more_than_once : Error<
 def err_reference_capture_with_reference_default : Error<
   "'&' cannot precede a capture when the capture default is '&'">;
 def err_this_capture_with_copy_default : Error<
-  "'this' cannot appear in a capture list when the capture default is '='">;
+  "'this' cannot be explicitly captured when the capture default is '='">;
 def err_copy_capture_with_copy_default : Error<
   "'&' must precede a capture when the capture default is '='">;
 def err_capture_does_not_name_variable : Error<
index a1c18715745488c6ece5d8097418d3e2d1709031..8abb893c6dc637c412f7a8e663f01d8dbebbb84a 100644 (file)
@@ -1933,6 +1933,7 @@ struct LambdaCapture {
 /// LambdaIntroducer - Represents a complete lambda introducer.
 struct LambdaIntroducer {
   SourceRange Range;
+  SourceLocation DefaultLoc;
   LambdaCaptureDefault Default;
   llvm::SmallVector<LambdaCapture, 4> Captures;
 
index 19a92cc7e7eb527f88ee2e7501d015c88dc49dbf..3974909cb2ba9eca9d79e763ccd74628d5f344be 100644 (file)
@@ -630,11 +630,11 @@ llvm::Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro)
   if (Tok.is(tok::amp) &&
       (NextToken().is(tok::comma) || NextToken().is(tok::r_square))) {
     Intro.Default = LCD_ByRef;
-    ConsumeToken();
+    Intro.DefaultLoc = ConsumeToken();
     first = false;
   } else if (Tok.is(tok::equal)) {
     Intro.Default = LCD_ByCopy;
-    ConsumeToken();
+    Intro.DefaultLoc = ConsumeToken();
     first = false;
   }
 
index 63fd869e7bc167344001720b1accd629c8c71f18..5a2a827230852df0d46a9856ca4f5d72144600b6 100644 (file)
@@ -686,11 +686,10 @@ void Sema::CheckCXXThisCapture(SourceLocation Loc, bool Explicit) {
       }
       
       if (CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_LambdaByref ||
+          CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_LambdaByval ||
           CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_Block ||
           Explicit) {
         // This closure can capture 'this'; continue looking upwards.
-        // FIXME: Is this check correct?  The rules in the standard are a bit
-        // unclear.
         NumClosures++;
         Explicit = false;
         continue;
index 64fe7f7dcea7999ca5a64443aba4cc66cd85d95b..e82654ef06d7c99c16801e14c789f6749cd79053 100644 (file)
@@ -15,6 +15,7 @@
 #include "clang/Sema/Lookup.h"
 #include "clang/Sema/ScopeInfo.h"
 #include "clang/Sema/SemaInternal.h"
+#include "clang/Lex/Preprocessor.h"
 #include "clang/AST/ExprCXX.h"
 using namespace clang;
 using namespace sema;
@@ -125,10 +126,13 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
   LSI->Mutable = (Method->getTypeQualifiers() & Qualifiers::Const) == 0;
  
   // Handle explicit captures.
+  SourceLocation PrevCaptureLoc
+    = Intro.Default == LCD_None? Intro.Range.getBegin() : Intro.DefaultLoc;
   for (llvm::SmallVector<LambdaCapture, 4>::const_iterator
          C = Intro.Captures.begin(), 
          E = Intro.Captures.end(); 
-       C != E; ++C) {
+       C != E; 
+       PrevCaptureLoc = C->Loc, ++C) {
     if (C->Kind == LCK_This) {
       // C++11 [expr.prim.lambda]p8:
       //   An identifier or this shall not appear more than once in a 
@@ -136,7 +140,9 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
       if (LSI->isCXXThisCaptured()) {
         Diag(C->Loc, diag::err_capture_more_than_once) 
           << "'this'"
-          << SourceRange(LSI->getCXXThisCapture().getLocation());
+          << SourceRange(LSI->getCXXThisCapture().getLocation())
+          << FixItHint::CreateRemoval(
+               SourceRange(PP.getLocForEndOfToken(PrevCaptureLoc), C->Loc));
         continue;
       }
 
@@ -144,7 +150,9 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
       //   If a lambda-capture includes a capture-default that is =, the 
       //   lambda-capture shall not contain this [...].
       if (Intro.Default == LCD_ByCopy) {
-        Diag(C->Loc, diag::err_this_capture_with_copy_default);
+        Diag(C->Loc, diag::err_this_capture_with_copy_default)
+          << FixItHint::CreateRemoval(
+               SourceRange(PP.getLocForEndOfToken(PrevCaptureLoc), C->Loc));
         continue;
       }
 
@@ -169,10 +177,14 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
     //   If a lambda-capture includes a capture-default that is =, [...]
     //   each identifier it contains shall be preceded by &.
     if (C->Kind == LCK_ByRef && Intro.Default == LCD_ByRef) {
-      Diag(C->Loc, diag::err_reference_capture_with_reference_default);
+      Diag(C->Loc, diag::err_reference_capture_with_reference_default)
+        << FixItHint::CreateRemoval(
+             SourceRange(PP.getLocForEndOfToken(PrevCaptureLoc), C->Loc));
       continue;
     } else if (C->Kind == LCK_ByCopy && Intro.Default == LCD_ByCopy) {
-      Diag(C->Loc, diag::err_copy_capture_with_copy_default);
+      Diag(C->Loc, diag::err_copy_capture_with_copy_default)
+        << FixItHint::CreateRemoval(
+             SourceRange(PP.getLocForEndOfToken(PrevCaptureLoc), C->Loc));
       continue;
     }
 
@@ -213,7 +225,9 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
     if (LSI->isCaptured(Var)) {
       Diag(C->Loc, diag::err_capture_more_than_once) 
         << C->Id
-        << SourceRange(LSI->getCapture(Var).getLocation());
+        << SourceRange(LSI->getCapture(Var).getLocation())
+        << FixItHint::CreateRemoval(
+             SourceRange(PP.getLocForEndOfToken(PrevCaptureLoc), C->Loc));
       continue;
     }
 
index b897d5f10a3e5da95b438361ad060eb9d8c7e1e0..d1384f19dd146f16bd014ee469de808a225d7f68 100644 (file)
@@ -8,18 +8,22 @@ class X0 {
     (void)[this, this] () {}; // expected-error {{'this' can appear only once}}
     (void)[=, foo] () {}; // expected-error {{'&' must precede a capture when}}
     (void)[=, &foo] () {};
-    (void)[=, this] () {}; // expected-error {{'this' cannot appear}}
+    (void)[=, this] () {}; // expected-error {{'this' cannot be explicitly captured}}
     (void)[&, foo] () {};
     (void)[&, &foo] () {}; // expected-error {{'&' cannot precede a capture when}} 
     (void)[&, this] () {};
   }
 };
 
-struct S2 { void f(int i); };
+struct S2 { 
+  void f(int i); 
+  void g(int i);
+};
 
 void S2::f(int i) {
   (void)[&, i]{ };
   (void)[&, &i]{ }; // expected-error{{'&' cannot precede a capture when the capture default is '&'}}
-  (void)[=, this]{ }; // expected-error{{'this' cannot appear in a capture list when the capture default is '='}}
+  (void)[=, this]{ }; // expected-error{{'this' cannot be explicitly captured}}
+  (void)[=]{ this->g(i); };
   (void)[i, i]{ }; // expected-error{{'i' can appear only once in a capture list}}
 }
index 28a96198bd0a24eaa401c5d8366f27a4ad43117d..e642b057a2185394c85f05ade2ae141d32b8d085 100644 (file)
@@ -46,3 +46,15 @@ namespace ScopedEnum {
     friend enum class E; // expected-error {{must use 'enum' not 'enum class'}}
   };
 }
+
+struct S2 { 
+  void f(int i); 
+  void g(int i);
+};
+
+void S2::f(int i) {
+  (void)[&, &i, &i]{}; // expected-error 2{{'&' cannot precede a capture when the capture default is '&'}}
+  (void)[=, this]{ this->g(5); }; // expected-error{{'this' cannot be explicitly captured}}
+  (void)[i, i]{ }; // expected-error{{'i' can appear only once in a capture list}}
+  (void)[&, i, i]{ }; // expected-error{{'i' can appear only once in a capture list}}
+}