@@ -115,7 +115,7 @@ class UncountedLambdaCapturesChecker
115
115
if (ArgIndex >= CE->getNumArgs ())
116
116
return true ;
117
117
auto *Arg = CE->getArg (ArgIndex)->IgnoreParenCasts ();
118
- if (auto *L = dyn_cast_or_null<LambdaExpr> (Arg)) {
118
+ if (auto *L = findLambdaInArg (Arg)) {
119
119
LambdasToIgnore.insert (L);
120
120
if (!Param->hasAttr <NoEscapeAttr>() && !TreatAllArgsAsNoEscape)
121
121
Checker->visitLambdaExpr (L, shouldCheckThis ());
@@ -126,6 +126,38 @@ class UncountedLambdaCapturesChecker
126
126
return true ;
127
127
}
128
128
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
+
129
161
void checkCalleeLambda (CallExpr *CE) {
130
162
auto *Callee = CE->getCallee ();
131
163
if (!Callee)
@@ -180,11 +212,53 @@ class UncountedLambdaCapturesChecker
180
212
} else if (C.capturesThis () && shouldCheckThis) {
181
213
if (ignoreParamVarDecl) // this is always a parameter to this function.
182
214
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);
184
228
}
185
229
}
186
230
}
187
231
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
+
188
262
void reportBug (const LambdaCapture &Capture, ValueDecl *CapturedVar,
189
263
const QualType T) const {
190
264
assert (CapturedVar);
0 commit comments