From cefc7b20fdb97b989163199e0849b4325e9b7804 Mon Sep 17 00:00:00 2001 From: Eli Friedman Date: Fri, 3 Feb 2012 23:06:43 +0000 Subject: [PATCH] Make explicit captures which cause implicit captures work correctly. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@149719 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Sema/Sema.h | 6 +++++- lib/Sema/SemaExpr.cpp | 10 ++++++++-- lib/Sema/SemaExprCXX.cpp | 17 ++++------------- test/SemaCXX/lambda-expressions.cpp | 7 +++++-- 4 files changed, 22 insertions(+), 18 deletions(-) diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index efa57cb8a5..6a9384daec 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -2284,7 +2284,11 @@ public: void UpdateMarkingForLValueToRValue(Expr *E); void CleanupVarDeclMarking(); - void TryCaptureVar(VarDecl *var, SourceLocation loc); + enum TryCaptureKind { + TryCapture_Implicit, TryCapture_ExplicitByVal, TryCapture_ExplicitByRef + }; + void TryCaptureVar(VarDecl *var, SourceLocation loc, + TryCaptureKind Kind = TryCapture_Implicit); void MarkDeclarationsReferencedInType(SourceLocation Loc, QualType T); void MarkDeclarationsReferencedInExpr(Expr *E); diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 8e196fbfe2..8c49c537c5 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -9453,7 +9453,8 @@ static bool shouldAddConstForScope(CapturingScopeInfo *CSI, VarDecl *VD) { // Check if the variable needs to be captured; if so, try to perform // the capture. // FIXME: Add support for explicit captures. -void Sema::TryCaptureVar(VarDecl *var, SourceLocation loc) { +void Sema::TryCaptureVar(VarDecl *var, SourceLocation loc, + TryCaptureKind Kind) { DeclContext *DC = CurContext; if (var->getDeclContext() == DC) return; if (!var->hasLocalStorage()) return; @@ -9536,7 +9537,12 @@ void Sema::TryCaptureVar(VarDecl *var, SourceLocation loc) { } bool byRef; - if (CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_None) { + bool isInnermostCapture = (i == e - 1); + if (isInnermostCapture && Kind == TryCapture_ExplicitByVal) { + byRef = false; + } else if (isInnermostCapture && Kind == TryCapture_ExplicitByRef) { + byRef = true; + } else if (CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_None) { // No capture-default Diag(loc, diag::err_lambda_impcap) << var->getDeclName(); Diag(var->getLocation(), diag::note_previous_decl) << var->getDeclName(); diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 3dd271bb8a..b35ea802e5 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -5030,12 +5030,6 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, Diag(Var->getLocation(), diag::note_previous_decl) << C->Id; continue; } - - if (Var->hasAttr()) { - Diag(C->Loc, diag::err_lambda_capture_block) << C->Id; - Diag(Var->getLocation(), diag::note_previous_decl) << C->Id; - continue; - } // C++11 [expr.prim.lambda]p8: // An identifier or this shall not appear more than once in a @@ -5046,13 +5040,10 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, << SourceRange(LSI->getCapture(Var).getLocation()); continue; } - - // FIXME: If this is capture by copy, make sure that we can in fact copy - // the variable. - // FIXME: Unify with normal capture path, so we get all of the necessary - // nested captures. - LSI->AddCapture(Var, /*isBlock*/false, C->Kind == LCK_ByRef, - /*isNested=*/false, C->Loc, 0); + + TryCaptureKind Kind = C->Kind == LCK_ByRef ? TryCapture_ExplicitByRef : + TryCapture_ExplicitByVal; + TryCaptureVar(Var, C->Loc, Kind); } LSI->finishedExplicitCaptures(); diff --git a/test/SemaCXX/lambda-expressions.cpp b/test/SemaCXX/lambda-expressions.cpp index 0f7d5484a8..05aba53dbb 100644 --- a/test/SemaCXX/lambda-expressions.cpp +++ b/test/SemaCXX/lambda-expressions.cpp @@ -45,7 +45,7 @@ namespace ReturnDeduction { namespace ImplicitCapture { void test() { - int a = 0; // expected-note 3 {{declared}} + int a = 0; // expected-note 5 {{declared}} []() { return a; }; // expected-error {{variable 'a' cannot be implicitly captured in a lambda with no capture-default specified}} expected-note {{begins here}} expected-error {{not supported yet}} [&]() { return a; }; // expected-error {{not supported yet}} [=]() { return a; }; // expected-error {{not supported yet}} @@ -53,6 +53,8 @@ namespace ImplicitCapture { [=]() { return [&]() { return a; }; }; // expected-error 2 {{not supported yet}} []() { return [&]() { return a; }; }; // expected-error {{variable 'a' cannot be implicitly captured in a lambda with no capture-default specified}} expected-note {{lambda expression begins here}} expected-error 2 {{not supported yet}} []() { return ^{ return a; }; };// expected-error {{variable 'a' cannot be implicitly captured in a lambda with no capture-default specified}} expected-note {{lambda expression begins here}} expected-error {{not supported yet}} + []() { return [&a] { return a; }; }; // expected-error 2 {{variable 'a' cannot be implicitly captured in a lambda with no capture-default specified}} expected-note 2 {{lambda expression begins here}} expected-error 2 {{not supported yet}} + [=]() { return [&a] { return a; }; }; // expected-error 2 {{not supported yet}} const int b = 2; []() { return b; }; // expected-error {{not supported yet}} @@ -64,8 +66,9 @@ namespace ImplicitCapture { d = 3; [=]() { return c; }; // expected-error {{unnamed variable cannot be implicitly captured in a lambda expression}} expected-error {{not supported yet}} - __block int e; // expected-note {{declared}} + __block int e; // expected-note 3 {{declared}} [&]() { return e; }; // expected-error {{__block variable 'e' cannot be captured in a lambda expression}} expected-error {{not supported yet}} + [&e]() { return e; }; // expected-error 2 {{__block variable 'e' cannot be captured in a lambda expression}} expected-error {{not supported yet}} int f[10]; // expected-note {{declared}} [&]() { return f[2]; }; // expected-error {{not supported yet}}