From 99d7e9960aff8eb0ce140aaef81a060883187a96 Mon Sep 17 00:00:00 2001 From: Akira Hatanaka Date: Wed, 1 Mar 2017 06:11:25 +0000 Subject: [PATCH] [Sema] Add variable captured by a block to the enclosing lambda's potential capture list. Fix Sema::getCurLambda() to return the innermost lambda scope when there is a block enclosed in the lambda. Previously, the method would return a nullptr in such cases, which would prevent a variable captured by the enclosed block to be added to the lambda scope's potential capture list. rdar://problem/28412462 Differential Revision: https://reviews.llvm.org/D25556 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@296584 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Sema/Sema.h | 8 +++++--- lib/Sema/Sema.cpp | 6 +++--- lib/Sema/SemaExpr.cpp | 5 +++-- test/SemaObjCXX/blocks.mm | 13 ++++++++++++- 4 files changed, 23 insertions(+), 9 deletions(-) diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index a23948181a..3ab7c1b568 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -1244,9 +1244,11 @@ public: sema::BlockScopeInfo *getCurBlock(); /// Retrieve the current lambda scope info, if any. - /// \param IgnoreCapturedRegions true if should find the top-most lambda scope - /// info ignoring all inner captured regions scope infos. - sema::LambdaScopeInfo *getCurLambda(bool IgnoreCapturedRegions = false); + /// \param IgnoreNonLambdaCapturingScope true if should find the top-most + /// lambda scope info ignoring all inner capturing scopes that are not + /// lambda scopes. + sema::LambdaScopeInfo * + getCurLambda(bool IgnoreNonLambdaCapturingScope = false); /// \brief Retrieve the current generic lambda info, if any. sema::LambdaScopeInfo *getCurGenericLambda(); diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 9edd4f2edc..1677d340fb 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -1237,14 +1237,14 @@ BlockScopeInfo *Sema::getCurBlock() { return CurBSI; } -LambdaScopeInfo *Sema::getCurLambda(bool IgnoreCapturedRegions) { +LambdaScopeInfo *Sema::getCurLambda(bool IgnoreNonLambdaCapturingScope) { if (FunctionScopes.empty()) return nullptr; auto I = FunctionScopes.rbegin(); - if (IgnoreCapturedRegions) { + if (IgnoreNonLambdaCapturingScope) { auto E = FunctionScopes.rend(); - while (I != E && isa(*I)) + while (I != E && isa(*I) && !isa(*I)) ++I; if (I == E) return nullptr; diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index af06162bf4..e422fe0226 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -14303,8 +14303,9 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc, (SemaRef.CurContext != Var->getDeclContext() && Var->getDeclContext()->isFunctionOrMethod() && Var->hasLocalStorage()); if (RefersToEnclosingScope) { - if (LambdaScopeInfo *const LSI = - SemaRef.getCurLambda(/*IgnoreCapturedRegions=*/true)) { + LambdaScopeInfo *const LSI = + SemaRef.getCurLambda(/*IgnoreNonLambdaCapturingScope=*/true); + if (LSI && !LSI->CallOperator->Encloses(Var->getDeclContext())) { // If a variable could potentially be odr-used, defer marking it so // until we finish analyzing the full expression for any // lvalue-to-rvalue diff --git a/test/SemaObjCXX/blocks.mm b/test/SemaObjCXX/blocks.mm index 3f901cc0a8..bdd5538e92 100644 --- a/test/SemaObjCXX/blocks.mm +++ b/test/SemaObjCXX/blocks.mm @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -verify -fblocks -Wno-objc-root-class -std=c++11 %s +// RUN: %clang_cc1 -fsyntax-only -verify -fblocks -Wno-objc-root-class -std=c++14 %s @protocol NSObject; void bar(id(^)(void)); @@ -145,6 +145,17 @@ namespace DependentReturn { template void f(X); } +namespace GenericLambdaCapture { +int test(int outerp) { + auto lambda =[&](auto p) { + return ^{ + return p + outerp; + }(); + }; + return lambda(1); +} +} + namespace MoveBlockVariable { struct B0 { }; -- 2.40.0