diff options
author | Douglas Gregor <dgregor@apple.com> | 2012-02-10 17:46:20 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2012-02-10 17:46:20 +0000 |
commit | 3ac109cd17151bb8ad3a40b0cbb0e1923cd6c4a0 (patch) | |
tree | 914a4d80e3d45b83bfcf9045f4ceb45b9125dae3 | |
parent | 67b2c554dc12f589471713b7b01e9c94257ae593 (diff) |
Allow implicit capture of 'this' in a lambda even when the capture
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
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 2 | ||||
-rw-r--r-- | include/clang/Sema/DeclSpec.h | 1 | ||||
-rw-r--r-- | lib/Parse/ParseExprCXX.cpp | 4 | ||||
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 3 | ||||
-rw-r--r-- | lib/Sema/SemaLambda.cpp | 26 | ||||
-rw-r--r-- | test/CXX/expr/expr.prim/expr.prim.lambda/p8.cpp | 10 | ||||
-rw-r--r-- | test/FixIt/fixit-cxx0x.cpp | 12 |
7 files changed, 44 insertions, 14 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index b79c48a224..0caf192fad 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -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< diff --git a/include/clang/Sema/DeclSpec.h b/include/clang/Sema/DeclSpec.h index a1c1871574..8abb893c6d 100644 --- a/include/clang/Sema/DeclSpec.h +++ b/include/clang/Sema/DeclSpec.h @@ -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; diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index 19a92cc7e7..3974909cb2 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -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; } diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 63fd869e7b..5a2a827230 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -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; diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp index 64fe7f7dce..e82654ef06 100644 --- a/lib/Sema/SemaLambda.cpp +++ b/lib/Sema/SemaLambda.cpp @@ -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; } diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p8.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p8.cpp index b897d5f10a..d1384f19dd 100644 --- a/test/CXX/expr/expr.prim/expr.prim.lambda/p8.cpp +++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p8.cpp @@ -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}} } diff --git a/test/FixIt/fixit-cxx0x.cpp b/test/FixIt/fixit-cxx0x.cpp index 28a96198bd..e642b057a2 100644 --- a/test/FixIt/fixit-cxx0x.cpp +++ b/test/FixIt/fixit-cxx0x.cpp @@ -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}} +} |