@@ -103,15 +103,18 @@ std::optional<bool> isRefCountable(const CXXRecordDecl* R)
103
103
return hasRef && hasDeref;
104
104
}
105
105
106
+ bool isRefType (const std::string &Name) {
107
+ return Name == " Ref" || Name == " RefAllowingPartiallyDestroyed" ||
108
+ Name == " RefPtr" || Name == " RefPtrAllowingPartiallyDestroyed" ;
109
+ }
110
+
106
111
bool isCtorOfRefCounted (const clang::FunctionDecl *F) {
107
112
assert (F);
108
- const auto &FunctionName = safeGetName (F);
109
-
110
- return FunctionName == " Ref" || FunctionName == " makeRef"
113
+ const std::string &FunctionName = safeGetName (F);
111
114
112
- || FunctionName == " RefPtr " || FunctionName == " makeRefPtr "
113
-
114
- || FunctionName == " UniqueRef " || FunctionName == " makeUniqueRef" ||
115
+ return isRefType (FunctionName) || FunctionName == " makeRef " ||
116
+ FunctionName == " makeRefPtr " || FunctionName == " UniqueRef " ||
117
+ FunctionName == " makeUniqueRef" ||
115
118
FunctionName == " makeUniqueRefWithoutFastMallocCheck"
116
119
117
120
|| FunctionName == " String" || FunctionName == " AtomString" ||
@@ -131,7 +134,7 @@ bool isReturnValueRefCounted(const clang::FunctionDecl *F) {
131
134
if (auto *specialT = type->getAs <TemplateSpecializationType>()) {
132
135
if (auto *decl = specialT->getTemplateName ().getAsTemplateDecl ()) {
133
136
auto name = decl->getNameAsString ();
134
- return name == " Ref " || name == " RefPtr " ;
137
+ return isRefType ( name) ;
135
138
}
136
139
return false ;
137
140
}
@@ -172,20 +175,18 @@ std::optional<bool> isGetterOfRefCounted(const CXXMethodDecl* M)
172
175
if (isa<CXXMethodDecl>(M)) {
173
176
const CXXRecordDecl *calleeMethodsClass = M->getParent ();
174
177
auto className = safeGetName (calleeMethodsClass);
175
- auto methodName = safeGetName (M);
178
+ auto method = safeGetName (M);
176
179
177
- if (((className == " Ref" || className == " RefPtr" ) &&
178
- methodName == " get" ) ||
179
- (className == " Ref" && methodName == " ptr" ) ||
180
+ if ((isRefType (className) && (method == " get" || method == " ptr" )) ||
180
181
((className == " String" || className == " AtomString" ||
181
182
className == " AtomStringImpl" || className == " UniqueString" ||
182
183
className == " UniqueStringImpl" || className == " Identifier" ) &&
183
- methodName == " impl" ))
184
+ method == " impl" ))
184
185
return true ;
185
186
186
187
// Ref<T> -> T conversion
187
188
// FIXME: Currently allowing any Ref<T> -> whatever cast.
188
- if (className == " Ref " || className == " RefPtr " ) {
189
+ if (isRefType ( className) ) {
189
190
if (auto *maybeRefToRawOperator = dyn_cast<CXXConversionDecl>(M)) {
190
191
if (auto *targetConversionType =
191
192
maybeRefToRawOperator->getConversionType ().getTypePtrOrNull ()) {
@@ -202,7 +203,7 @@ bool isRefCounted(const CXXRecordDecl *R) {
202
203
if (auto *TmplR = R->getTemplateInstantiationPattern ()) {
203
204
// FIXME: String/AtomString/UniqueString
204
205
const auto &ClassName = safeGetName (TmplR);
205
- return ClassName == " RefPtr " || ClassName == " Ref " ;
206
+ return isRefType ( ClassName) ;
206
207
}
207
208
return false ;
208
209
}
@@ -252,6 +253,19 @@ class TrivialFunctionAnalysisVisitor
252
253
return true ;
253
254
}
254
255
256
+ template <typename CheckFunction>
257
+ bool WithCachedResult (const Stmt *S, CheckFunction Function) {
258
+ // If the statement isn't in the cache, conservatively assume that
259
+ // it's not trivial until analysis completes. Insert false to the cache
260
+ // first to avoid infinite recursion.
261
+ auto [It, IsNew] = Cache.insert (std::make_pair (S, false ));
262
+ if (!IsNew)
263
+ return It->second ;
264
+ bool Result = Function ();
265
+ Cache[S] = Result;
266
+ return Result;
267
+ }
268
+
255
269
public:
256
270
using CacheTy = TrivialFunctionAnalysis::CacheTy;
257
271
@@ -266,7 +280,7 @@ class TrivialFunctionAnalysisVisitor
266
280
bool VisitCompoundStmt (const CompoundStmt *CS) {
267
281
// A compound statement is allowed as long each individual sub-statement
268
282
// is trivial.
269
- return VisitChildren (CS);
283
+ return WithCachedResult (CS, [&]() { return VisitChildren (CS); } );
270
284
}
271
285
272
286
bool VisitReturnStmt (const ReturnStmt *RS) {
@@ -278,16 +292,36 @@ class TrivialFunctionAnalysisVisitor
278
292
279
293
bool VisitDeclStmt (const DeclStmt *DS) { return VisitChildren (DS); }
280
294
bool VisitDoStmt (const DoStmt *DS) { return VisitChildren (DS); }
281
- bool VisitIfStmt (const IfStmt *IS) { return VisitChildren (IS); }
295
+ bool VisitIfStmt (const IfStmt *IS) {
296
+ return WithCachedResult (IS, [&]() { return VisitChildren (IS); });
297
+ }
298
+ bool VisitForStmt (const ForStmt *FS) {
299
+ return WithCachedResult (FS, [&]() { return VisitChildren (FS); });
300
+ }
301
+ bool VisitCXXForRangeStmt (const CXXForRangeStmt *FS) {
302
+ return WithCachedResult (FS, [&]() { return VisitChildren (FS); });
303
+ }
304
+ bool VisitWhileStmt (const WhileStmt *WS) {
305
+ return WithCachedResult (WS, [&]() { return VisitChildren (WS); });
306
+ }
282
307
bool VisitSwitchStmt (const SwitchStmt *SS) { return VisitChildren (SS); }
283
308
bool VisitCaseStmt (const CaseStmt *CS) { return VisitChildren (CS); }
284
309
bool VisitDefaultStmt (const DefaultStmt *DS) { return VisitChildren (DS); }
285
310
286
311
bool VisitUnaryOperator (const UnaryOperator *UO) {
287
312
// Operator '*' and '!' are allowed as long as the operand is trivial.
288
- if (UO->getOpcode () == UO_Deref || UO->getOpcode () == UO_LNot)
313
+ auto op = UO->getOpcode ();
314
+ if (op == UO_Deref || op == UO_AddrOf || op == UO_LNot)
289
315
return Visit (UO->getSubExpr ());
290
316
317
+ if (UO->isIncrementOp () || UO->isDecrementOp ()) {
318
+ // Allow increment or decrement of a POD type.
319
+ if (auto *RefExpr = dyn_cast<DeclRefExpr>(UO->getSubExpr ())) {
320
+ if (auto *Decl = dyn_cast<VarDecl>(RefExpr->getDecl ()))
321
+ return Decl->isLocalVarDeclOrParm () &&
322
+ Decl->getType ().isPODType (Decl->getASTContext ());
323
+ }
324
+ }
291
325
// Other operators are non-trivial.
292
326
return false ;
293
327
}
@@ -302,13 +336,7 @@ class TrivialFunctionAnalysisVisitor
302
336
return VisitChildren (CO);
303
337
}
304
338
305
- bool VisitDeclRefExpr (const DeclRefExpr *DRE) {
306
- if (auto *decl = DRE->getDecl ()) {
307
- if (isa<ParmVarDecl>(decl))
308
- return true ;
309
- }
310
- return false ;
311
- }
339
+ bool VisitAtomicExpr (const AtomicExpr *E) { return VisitChildren (E); }
312
340
313
341
bool VisitStaticAssertDecl (const StaticAssertDecl *SAD) {
314
342
// Any static_assert is considered trivial.
@@ -325,12 +353,18 @@ class TrivialFunctionAnalysisVisitor
325
353
const auto &Name = safeGetName (Callee);
326
354
327
355
if (Name == " WTFCrashWithInfo" || Name == " WTFBreakpointTrap" ||
356
+ Name == " WTFReportAssertionFailure" ||
328
357
Name == " compilerFenceForCrash" || Name == " __builtin_unreachable" )
329
358
return true ;
330
359
331
360
return TrivialFunctionAnalysis::isTrivialImpl (Callee, Cache);
332
361
}
333
362
363
+ bool VisitPredefinedExpr (const PredefinedExpr *E) {
364
+ // A predefined identifier such as "func" is considered trivial.
365
+ return true ;
366
+ }
367
+
334
368
bool VisitCXXMemberCallExpr (const CXXMemberCallExpr *MCE) {
335
369
if (!checkArguments (MCE))
336
370
return false ;
@@ -351,6 +385,14 @@ class TrivialFunctionAnalysisVisitor
351
385
return TrivialFunctionAnalysis::isTrivialImpl (Callee, Cache);
352
386
}
353
387
388
+ bool VisitCXXDefaultArgExpr (const CXXDefaultArgExpr *E) {
389
+ if (auto *Expr = E->getExpr ()) {
390
+ if (!Visit (Expr))
391
+ return false ;
392
+ }
393
+ return true ;
394
+ }
395
+
354
396
bool checkArguments (const CallExpr *CE) {
355
397
for (const Expr *Arg : CE->arguments ()) {
356
398
if (Arg && !Visit (Arg))
@@ -377,6 +419,14 @@ class TrivialFunctionAnalysisVisitor
377
419
return Visit (ECE->getSubExpr ());
378
420
}
379
421
422
+ bool VisitMaterializeTemporaryExpr (const MaterializeTemporaryExpr *VMT) {
423
+ return Visit (VMT->getSubExpr ());
424
+ }
425
+
426
+ bool VisitExprWithCleanups (const ExprWithCleanups *EWC) {
427
+ return Visit (EWC->getSubExpr ());
428
+ }
429
+
380
430
bool VisitParenExpr (const ParenExpr *PE) { return Visit (PE->getSubExpr ()); }
381
431
382
432
bool VisitInitListExpr (const InitListExpr *ILE) {
@@ -397,6 +447,16 @@ class TrivialFunctionAnalysisVisitor
397
447
return true ;
398
448
}
399
449
450
+ bool VisitCXXNullPtrLiteralExpr (const CXXNullPtrLiteralExpr *E) {
451
+ // nullptr is trivial.
452
+ return true ;
453
+ }
454
+
455
+ bool VisitDeclRefExpr (const DeclRefExpr *DRE) {
456
+ // The use of a variable is trivial.
457
+ return true ;
458
+ }
459
+
400
460
// Constant literal expressions are always trivial
401
461
bool VisitIntegerLiteral (const IntegerLiteral *E) { return true ; }
402
462
bool VisitFloatingLiteral (const FloatingLiteral *E) { return true ; }
@@ -410,7 +470,7 @@ class TrivialFunctionAnalysisVisitor
410
470
}
411
471
412
472
private:
413
- CacheTy Cache;
473
+ CacheTy & Cache;
414
474
};
415
475
416
476
bool TrivialFunctionAnalysis::isTrivialImpl (
@@ -435,4 +495,17 @@ bool TrivialFunctionAnalysis::isTrivialImpl(
435
495
return Result;
436
496
}
437
497
498
+ bool TrivialFunctionAnalysis::isTrivialImpl (
499
+ const Stmt *S, TrivialFunctionAnalysis::CacheTy &Cache) {
500
+ // If the statement isn't in the cache, conservatively assume that
501
+ // it's not trivial until analysis completes. Unlike a function case,
502
+ // we don't insert an entry into the cache until Visit returns
503
+ // since Visit* functions themselves make use of the cache.
504
+
505
+ TrivialFunctionAnalysisVisitor V (Cache);
506
+ bool Result = V.Visit (S);
507
+ assert (Cache.contains (S) && " Top-level statement not properly cached!" );
508
+ return Result;
509
+ }
510
+
438
511
} // namespace clang
0 commit comments