diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -806,6 +806,9 @@ /// context. unsigned FunctionScopesStart = 0; + /// Track the number of currently active capturing scopes. + unsigned CapturingFunctionScopes = 0; + ArrayRef getFunctionScopes() const { return llvm::ArrayRef(FunctionScopes.begin() + FunctionScopesStart, FunctionScopes.end()); diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -2138,11 +2138,13 @@ void Sema::PushBlockScope(Scope *BlockScope, BlockDecl *Block) { FunctionScopes.push_back(new BlockScopeInfo(getDiagnostics(), BlockScope, Block)); + CapturingFunctionScopes++; } LambdaScopeInfo *Sema::PushLambdaScope() { LambdaScopeInfo *const LSI = new LambdaScopeInfo(getDiagnostics()); FunctionScopes.push_back(LSI); + CapturingFunctionScopes++; return LSI; } @@ -2264,6 +2266,8 @@ void Sema::PoppedFunctionScopeDeleter:: operator()(sema::FunctionScopeInfo *Scope) const { + if (!Scope->isPlainFunction()) + Self->CapturingFunctionScopes--; // Stash the function scope for later reuse if it's for a normal function. if (Scope->isPlainFunction() && !Self->CachedFunctionScope) Self->CachedFunctionScope.reset(Scope); @@ -2694,6 +2698,7 @@ OpenMPCaptureLevel); CSI->ReturnType = Context.VoidTy; FunctionScopes.push_back(CSI); + CapturingFunctionScopes++; } CapturedRegionScopeInfo *Sema::getCurCapturedRegion() { diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -19221,6 +19221,15 @@ // An init-capture is notionally from the context surrounding its // declaration, but its parent DC is the lambda class. DeclContext *VarDC = Var->getDeclContext(); + DeclContext *DC = CurContext; + + // tryCaptureVariable is called every time a DeclRef is formed, + // it can therefore have non-negigible impact on performances. + // For local variables and when there is no capturing scope, + // we can bailout early. + if (CapturingFunctionScopes == 0 && (!BuildAndDiagnose || VarDC == DC)) + return true; + const auto *VD = dyn_cast(Var); if (VD) { if (VD->isInitCapture()) @@ -19230,7 +19239,6 @@ } assert(VD && "Cannot capture a null variable"); - DeclContext *DC = CurContext; const unsigned MaxFunctionScopesIndex = FunctionScopeIndexToStopAt ? *FunctionScopeIndexToStopAt : FunctionScopes.size() - 1; // We need to sync up the Declaration Context with the