@@ -118,7 +118,7 @@ class UncountedLambdaCapturesChecker
118
118
if (ArgIndex >= CE->getNumArgs ())
119
119
return true ;
120
120
auto *Arg = CE->getArg (ArgIndex)->IgnoreParenCasts ();
121
- if (auto *L = dyn_cast_or_null<LambdaExpr> (Arg)) {
121
+ if (auto *L = findLambdaInArg (Arg)) {
122
122
LambdasToIgnore.insert (L);
123
123
if (!Param->hasAttr <NoEscapeAttr>() && !TreatAllArgsAsNoEscape)
124
124
Checker->visitLambdaExpr (L, shouldCheckThis ());
@@ -129,6 +129,38 @@ class UncountedLambdaCapturesChecker
129
129
return true ;
130
130
}
131
131
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
+
132
164
void checkCalleeLambda (CallExpr *CE) {
133
165
auto *Callee = CE->getCallee ();
134
166
if (!Callee)
@@ -183,11 +215,53 @@ class UncountedLambdaCapturesChecker
183
215
} else if (C.capturesThis () && shouldCheckThis) {
184
216
if (ignoreParamVarDecl) // this is always a parameter to this function.
185
217
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);
187
231
}
188
232
}
189
233
}
190
234
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
+
191
265
void reportBug (const LambdaCapture &Capture, ValueDecl *CapturedVar,
192
266
const QualType T) const {
193
267
assert (CapturedVar);
0 commit comments