@@ -118,7 +118,7 @@ class UncountedLambdaCapturesChecker
118118 if (ArgIndex >= CE->getNumArgs ())
119119 return true ;
120120 auto *Arg = CE->getArg (ArgIndex)->IgnoreParenCasts ();
121- if (auto *L = dyn_cast_or_null<LambdaExpr> (Arg)) {
121+ if (auto *L = findLambdaInArg (Arg)) {
122122 LambdasToIgnore.insert (L);
123123 if (!Param->hasAttr <NoEscapeAttr>() && !TreatAllArgsAsNoEscape)
124124 Checker->visitLambdaExpr (L, shouldCheckThis ());
@@ -129,6 +129,38 @@ class UncountedLambdaCapturesChecker
129129 return true ;
130130 }
131131
132+ LambdaExpr *findLambdaInArg (Expr *E) {
133+ if (auto *Lambda = dyn_cast_or_null<LambdaExpr>(E))
134+ return Lambda;
135+ auto *TempExpr = dyn_cast_or_null<CXXBindTemporaryExpr>(E);
136+ if (!TempExpr)
137+ return nullptr ;
138+ E = TempExpr->getSubExpr ()->IgnoreParenCasts ();
139+ if (!E)
140+ return nullptr ;
141+ if (auto *Lambda = dyn_cast<LambdaExpr>(E))
142+ return Lambda;
143+ auto *CE = dyn_cast_or_null<CXXConstructExpr>(E);
144+ if (!CE || !CE->getNumArgs ())
145+ return nullptr ;
146+ auto *CtorArg = CE->getArg (0 )->IgnoreParenCasts ();
147+ if (!CtorArg)
148+ return nullptr ;
149+ if (auto *Lambda = dyn_cast<LambdaExpr>(CtorArg))
150+ return Lambda;
151+ auto *DRE = dyn_cast<DeclRefExpr>(CtorArg);
152+ if (!DRE)
153+ return nullptr ;
154+ auto *VD = dyn_cast_or_null<VarDecl>(DRE->getDecl ());
155+ if (!VD)
156+ return nullptr ;
157+ auto *Init = VD->getInit ();
158+ if (!Init)
159+ return nullptr ;
160+ TempExpr = dyn_cast<CXXBindTemporaryExpr>(Init->IgnoreParenCasts ());
161+ return dyn_cast_or_null<LambdaExpr>(TempExpr->getSubExpr ());
162+ }
163+
132164 void checkCalleeLambda (CallExpr *CE) {
133165 auto *Callee = CE->getCallee ();
134166 if (!Callee)
@@ -183,11 +215,53 @@ class UncountedLambdaCapturesChecker
183215 } else if (C.capturesThis () && shouldCheckThis) {
184216 if (ignoreParamVarDecl) // this is always a parameter to this function.
185217 continue ;
186- reportBugOnThisPtr (C);
218+ bool hasProtectThis = false ;
219+ for (const LambdaCapture &OtherCapture : L->captures ()) {
220+ if (!OtherCapture.capturesVariable ())
221+ continue ;
222+ if (auto *ValueDecl = OtherCapture.getCapturedVar ()) {
223+ if (protectThis (ValueDecl)) {
224+ hasProtectThis = true ;
225+ break ;
226+ }
227+ }
228+ }
229+ if (!hasProtectThis)
230+ reportBugOnThisPtr (C);
187231 }
188232 }
189233 }
190234
235+ bool protectThis (const ValueDecl *ValueDecl) const {
236+ auto *VD = dyn_cast<VarDecl>(ValueDecl);
237+ if (!VD)
238+ return false ;
239+ auto *Init = VD->getInit ()->IgnoreParenCasts ();
240+ if (!Init)
241+ return false ;
242+ auto *BTE = dyn_cast<CXXBindTemporaryExpr>(Init);
243+ if (!BTE)
244+ return false ;
245+ auto *CE = dyn_cast_or_null<CXXConstructExpr>(BTE->getSubExpr ());
246+ if (!CE)
247+ return false ;
248+ auto *Ctor = CE->getConstructor ();
249+ if (!Ctor)
250+ return false ;
251+ auto clsName = safeGetName (Ctor->getParent ());
252+ if (!isRefType (clsName) || !CE->getNumArgs ())
253+ return false ;
254+ auto *Arg = CE->getArg (0 )->IgnoreParenCasts ();
255+ while (auto *UO = dyn_cast<UnaryOperator>(Arg)) {
256+ auto OpCode = UO->getOpcode ();
257+ if (OpCode == UO_Deref || OpCode == UO_AddrOf)
258+ Arg = UO->getSubExpr ();
259+ else
260+ break ;
261+ }
262+ return isa<CXXThisExpr>(Arg);
263+ }
264+
191265 void reportBug (const LambdaCapture &Capture, ValueDecl *CapturedVar,
192266 const QualType T) const {
193267 assert (CapturedVar);
0 commit comments