@@ -115,7 +115,7 @@ class UncountedLambdaCapturesChecker
115115 if (ArgIndex >= CE->getNumArgs ())
116116 return true ;
117117 auto *Arg = CE->getArg (ArgIndex)->IgnoreParenCasts ();
118- if (auto *L = dyn_cast_or_null<LambdaExpr> (Arg)) {
118+ if (auto *L = findLambdaInArg (Arg)) {
119119 LambdasToIgnore.insert (L);
120120 if (!Param->hasAttr <NoEscapeAttr>() && !TreatAllArgsAsNoEscape)
121121 Checker->visitLambdaExpr (L, shouldCheckThis ());
@@ -126,6 +126,38 @@ class UncountedLambdaCapturesChecker
126126 return true ;
127127 }
128128
129+ LambdaExpr *findLambdaInArg (Expr *E) {
130+ if (auto *Lambda = dyn_cast_or_null<LambdaExpr>(E))
131+ return Lambda;
132+ auto *TempExpr = dyn_cast_or_null<CXXBindTemporaryExpr>(E);
133+ if (!TempExpr)
134+ return nullptr ;
135+ E = TempExpr->getSubExpr ()->IgnoreParenCasts ();
136+ if (!E)
137+ return nullptr ;
138+ if (auto *Lambda = dyn_cast<LambdaExpr>(E))
139+ return Lambda;
140+ auto *CE = dyn_cast_or_null<CXXConstructExpr>(E);
141+ if (!CE || !CE->getNumArgs ())
142+ return nullptr ;
143+ auto *CtorArg = CE->getArg (0 )->IgnoreParenCasts ();
144+ if (!CtorArg)
145+ return nullptr ;
146+ if (auto *Lambda = dyn_cast<LambdaExpr>(CtorArg))
147+ return Lambda;
148+ auto *DRE = dyn_cast<DeclRefExpr>(CtorArg);
149+ if (!DRE)
150+ return nullptr ;
151+ auto *VD = dyn_cast_or_null<VarDecl>(DRE->getDecl ());
152+ if (!VD)
153+ return nullptr ;
154+ auto *Init = VD->getInit ();
155+ if (!Init)
156+ return nullptr ;
157+ TempExpr = dyn_cast<CXXBindTemporaryExpr>(Init->IgnoreParenCasts ());
158+ return dyn_cast_or_null<LambdaExpr>(TempExpr->getSubExpr ());
159+ }
160+
129161 void checkCalleeLambda (CallExpr *CE) {
130162 auto *Callee = CE->getCallee ();
131163 if (!Callee)
@@ -180,11 +212,53 @@ class UncountedLambdaCapturesChecker
180212 } else if (C.capturesThis () && shouldCheckThis) {
181213 if (ignoreParamVarDecl) // this is always a parameter to this function.
182214 continue ;
183- reportBugOnThisPtr (C);
215+ bool hasProtectThis = false ;
216+ for (const LambdaCapture &OtherCapture : L->captures ()) {
217+ if (!OtherCapture.capturesVariable ())
218+ continue ;
219+ if (auto *ValueDecl = OtherCapture.getCapturedVar ()) {
220+ if (protectThis (ValueDecl)) {
221+ hasProtectThis = true ;
222+ break ;
223+ }
224+ }
225+ }
226+ if (!hasProtectThis)
227+ reportBugOnThisPtr (C);
184228 }
185229 }
186230 }
187231
232+ bool protectThis (const ValueDecl *ValueDecl) const {
233+ auto *VD = dyn_cast<VarDecl>(ValueDecl);
234+ if (!VD)
235+ return false ;
236+ auto *Init = VD->getInit ()->IgnoreParenCasts ();
237+ if (!Init)
238+ return false ;
239+ auto *BTE = dyn_cast<CXXBindTemporaryExpr>(Init);
240+ if (!BTE)
241+ return false ;
242+ auto *CE = dyn_cast_or_null<CXXConstructExpr>(BTE->getSubExpr ());
243+ if (!CE)
244+ return false ;
245+ auto *Ctor = CE->getConstructor ();
246+ if (!Ctor)
247+ return false ;
248+ auto clsName = safeGetName (Ctor->getParent ());
249+ if (!isRefType (clsName) || !CE->getNumArgs ())
250+ return false ;
251+ auto *Arg = CE->getArg (0 )->IgnoreParenCasts ();
252+ while (auto *UO = dyn_cast<UnaryOperator>(Arg)) {
253+ auto OpCode = UO->getOpcode ();
254+ if (OpCode == UO_Deref || OpCode == UO_AddrOf)
255+ Arg = UO->getSubExpr ();
256+ else
257+ break ;
258+ }
259+ return isa<CXXThisExpr>(Arg);
260+ }
261+
188262 void reportBug (const LambdaCapture &Capture, ValueDecl *CapturedVar,
189263 const QualType T) const {
190264 assert (CapturedVar);
0 commit comments