diff options
author | Alexey Bataev <a.bataev@hotmail.com> | 2016-11-11 12:36:20 +0000 |
---|---|---|
committer | Alexey Bataev <a.bataev@hotmail.com> | 2016-11-11 12:36:20 +0000 |
commit | 31939e39db2ca3f26868f1f961be0e6c9026a45c (patch) | |
tree | a0bd1889030cc7429def9f841ae3aca8002d998b | |
parent | cdfdff0b182a8a4a06ba99d7410f0d129b743a45 (diff) | |
download | bcm5719-llvm-31939e39db2ca3f26868f1f961be0e6c9026a45c.tar.gz bcm5719-llvm-31939e39db2ca3f26868f1f961be0e6c9026a45c.zip |
Fix for PR28523: unexpected compilation error.
Clang emits error message for the following code:
```
template <class F> void parallel_loop(F &&f) { f(0); }
int main() {
int x;
parallel_loop([&](auto y) {
{
x = y;
};
});
}
```
$ clang++ --std=gnu++14 clang_test.cc -o clang_test
clang_test.cc:9:7: error: reference to local variable 'x' declared in enclosing function 'main'
x = y;
^
clang_test.cc:2:48: note: in instantiation of function template specialization 'main()::(anonymous class)::operator()<int>' requested here
template <class F> void parallel_loop(F &&f) { f(0); }
^
clang_test.cc:6:3: note: in instantiation of function template specialization 'parallel_loop<(lambda at clang_test.cc:6:17)>' requested here parallel_loop([&](auto y) {
^
clang_test.cc:5:7: note: 'x' declared here
int x;
^
1 error generated.
Patch fixes this issue.
llvm-svn: 286584
-rw-r--r-- | clang/include/clang/Sema/Sema.h | 6 | ||||
-rw-r--r-- | clang/lib/Sema/Sema.cpp | 12 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 3 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExprCXX.cpp | 16 | ||||
-rw-r--r-- | clang/lib/Sema/SemaLambda.cpp | 11 | ||||
-rw-r--r-- | clang/test/CodeGenCXX/PR28523.cpp | 19 |
6 files changed, 55 insertions, 12 deletions
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 23ec47d02fe..f18a6ee4b96 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -1228,8 +1228,10 @@ public: /// \brief Retrieve the current block, if any. sema::BlockScopeInfo *getCurBlock(); - /// \brief Retrieve the current lambda scope info, if any. - sema::LambdaScopeInfo *getCurLambda(); + /// 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); /// \brief Retrieve the current generic lambda info, if any. sema::LambdaScopeInfo *getCurGenericLambda(); diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index c2622ecab4b..250e31bc33a 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -1201,11 +1201,19 @@ BlockScopeInfo *Sema::getCurBlock() { return CurBSI; } -LambdaScopeInfo *Sema::getCurLambda() { +LambdaScopeInfo *Sema::getCurLambda(bool IgnoreCapturedRegions) { if (FunctionScopes.empty()) return nullptr; - auto CurLSI = dyn_cast<LambdaScopeInfo>(FunctionScopes.back()); + auto I = FunctionScopes.rbegin(); + if (IgnoreCapturedRegions) { + auto E = FunctionScopes.rend(); + while (I != E && isa<CapturedRegionScopeInfo>(*I)) + ++I; + if (I == E) + return nullptr; + } + auto *CurLSI = dyn_cast<LambdaScopeInfo>(*I); if (CurLSI && CurLSI->Lambda && !CurLSI->Lambda->Encloses(CurContext)) { // We have switched contexts due to template instantiation. diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 114dba31d93..fae8bf0f548 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -14079,7 +14079,8 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc, (SemaRef.CurContext != Var->getDeclContext() && Var->getDeclContext()->isFunctionOrMethod() && Var->hasLocalStorage()); if (RefersToEnclosingScope) { - if (LambdaScopeInfo *const LSI = SemaRef.getCurLambda()) { + if (LambdaScopeInfo *const LSI = + SemaRef.getCurLambda(/*IgnoreCapturedRegions=*/true)) { // 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/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 0dab27affea..634954c3e85 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -6879,8 +6879,14 @@ static void CheckIfAnyEnclosingLambdasMustCaptureAnyPotentialCaptures( assert(!S.isUnevaluatedContext()); assert(S.CurContext->isDependentContext()); - assert(CurrentLSI->CallOperator == S.CurContext && +#ifndef NDEBUG + DeclContext *DC = S.CurContext; + while (DC && isa<CapturedDecl>(DC)) + DC = DC->getParent(); + assert( + CurrentLSI->CallOperator == DC && "The current call operator must be synchronized with Sema's CurContext"); +#endif // NDEBUG const bool IsFullExprInstantiationDependent = FE->isInstantiationDependent(); @@ -7346,7 +7352,8 @@ ExprResult Sema::ActOnFinishFullExpr(Expr *FE, SourceLocation CC, // and then the full-expression +n + ({ 0; }); ends, but it's too late // for us to see that we need to capture n after all. - LambdaScopeInfo *const CurrentLSI = getCurLambda(); + LambdaScopeInfo *const CurrentLSI = + getCurLambda(/*IgnoreCapturedRegions=*/true); // FIXME: PR 17877 showed that getCurLambda() can return a valid pointer // even if CurContext is not a lambda call operator. Refer to that Bug Report // for an example of the code that might cause this asynchrony. @@ -7361,7 +7368,10 @@ ExprResult Sema::ActOnFinishFullExpr(Expr *FE, SourceLocation CC, // constructor/destructor. // - Teach the handful of places that iterate over FunctionScopes to // stop at the outermost enclosing lexical scope." - const bool IsInLambdaDeclContext = isLambdaCallOperator(CurContext); + DeclContext *DC = CurContext; + while (DC && isa<CapturedDecl>(DC)) + DC = DC->getParent(); + const bool IsInLambdaDeclContext = isLambdaCallOperator(DC); if (IsInLambdaDeclContext && CurrentLSI && CurrentLSI->hasPotentialCaptures() && !FullExpr.isInvalid()) CheckIfAnyEnclosingLambdasMustCaptureAnyPotentialCaptures(FE, CurrentLSI, diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp index da4ba8b2a26..fb3ac072f1e 100644 --- a/clang/lib/Sema/SemaLambda.cpp +++ b/clang/lib/Sema/SemaLambda.cpp @@ -66,17 +66,20 @@ getStackIndexOfNearestEnclosingCaptureReadyLambda( // Label failure to capture. const Optional<unsigned> NoLambdaIsCaptureReady; + // Ignore all inner captured regions. + unsigned CurScopeIndex = FunctionScopes.size() - 1; + while (CurScopeIndex > 0 && isa<clang::sema::CapturedRegionScopeInfo>( + FunctionScopes[CurScopeIndex])) + --CurScopeIndex; assert( - isa<clang::sema::LambdaScopeInfo>( - FunctionScopes[FunctionScopes.size() - 1]) && + isa<clang::sema::LambdaScopeInfo>(FunctionScopes[CurScopeIndex]) && "The function on the top of sema's function-info stack must be a lambda"); - + // If VarToCapture is null, we are attempting to capture 'this'. const bool IsCapturingThis = !VarToCapture; const bool IsCapturingVariable = !IsCapturingThis; // Start with the current lambda at the top of the stack (highest index). - unsigned CurScopeIndex = FunctionScopes.size() - 1; DeclContext *EnclosingDC = cast<sema::LambdaScopeInfo>(FunctionScopes[CurScopeIndex])->CallOperator; diff --git a/clang/test/CodeGenCXX/PR28523.cpp b/clang/test/CodeGenCXX/PR28523.cpp new file mode 100644 index 00000000000..4c3a81c8b85 --- /dev/null +++ b/clang/test/CodeGenCXX/PR28523.cpp @@ -0,0 +1,19 @@ +// RUN: %clang_cc1 -std=c++14 -verify -triple %itanium_abi_triple -emit-llvm %s -o - | FileCheck %s +// expected-no-diagnostics + +template <class F> void parallel_loop(F &&f) { f(0); } + +//CHECK-LABEL: @main +int main() { +// CHECK: [[X_ADDR:%.+]] = alloca i32, + int x; +// CHECK: getelementptr inbounds +// CHECK: store i32* [[X_ADDR]], i32** % +// CHECK: call + parallel_loop([&](auto y) { +#pragma clang __debug captured + { + x = y; + }; + }); +} |