diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 1cb8d2b331bc495896e9a5bba398373b304f04fa..0d1c8fa48cdc7988d7b4de27301908665fd88694 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -1218,8 +1218,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/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index a242ace9f64eeb66eaa31b7c4f8e785bbaad8680..7777476063041c0875caef60eb4c73d0cf0e3deb 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -1197,11 +1197,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/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index e9023c829591bd7947b53da29c1f2c5415bab1eb..719e1e3502cad4b50e09f5101af0c924f48189be 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -13885,7 +13885,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/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index b7a968e09d4d6ae1f9c848770d842e6864f364d2..56f4019bfbb661c2a4afc5f0344e893157119b10 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -6582,10 +6582,16 @@ static inline bool VariableCanNeverBeAConstantExpression(VarDecl *Var, static void CheckIfAnyEnclosingLambdasMustCaptureAnyPotentialCaptures( Expr *const FE, LambdaScopeInfo *const CurrentLSI, Sema &S) { - assert(!S.isUnevaluatedContext()); - assert(S.CurContext->isDependentContext()); - assert(CurrentLSI->CallOperator == S.CurContext && + assert(!S.isUnevaluatedContext()); + assert(S.CurContext->isDependentContext()); +#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(); @@ -7051,7 +7057,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. @@ -7066,7 +7073,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/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp index 8a2bf929dfc0e3dea9a209bab6358482bef7e505..070c2fa2c71df4712e24cf831e72243e71ee7c1f 100644 --- a/lib/Sema/SemaLambda.cpp +++ b/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/test/CodeGenCXX/PR28523.cpp b/test/CodeGenCXX/PR28523.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4c3a81c8b85485c3d8bd695dd1bf4b4c2f6ed0a3 --- /dev/null +++ b/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; + }; + }); +}