@@ -244,18 +244,41 @@ class TrivialFunctionAnalysisVisitor
244
244
245
245
// Returns false if at least one child is non-trivial.
246
246
bool VisitChildren (const Stmt *S) {
247
- for (const Stmt *Child : S->children ()) {
248
- if (Child && !Visit (Child))
247
+ return withCachedResult (S, [&]() {
248
+ for (const Stmt *Child : S->children ()) {
249
+ if (Child && !Visit (Child))
250
+ return false ;
251
+ }
252
+ return true ;
253
+ });
254
+ }
255
+
256
+ bool VisitSubExpr (const Expr *Parent, const Expr *E) {
257
+ return withCachedResult (Parent, [&]() {
258
+ if (!Visit (E))
249
259
return false ;
250
- }
260
+ return true ;
261
+ });
262
+ }
251
263
252
- return true ;
264
+ template <typename StmtType, typename CheckFunction>
265
+ bool withCachedResult (const StmtType *S, CheckFunction Function) {
266
+ // Insert false to the cache first to avoid infinite recursion.
267
+ auto [It, IsNew] = StatementCache.insert (std::make_pair (S, false ));
268
+ if (!IsNew)
269
+ return It->second ;
270
+ bool Result = Function ();
271
+ It->second = Result;
272
+ return Result;
253
273
}
254
274
255
275
public:
256
- using CacheTy = TrivialFunctionAnalysis::CacheTy;
276
+ using FunctionCacheTy = TrivialFunctionAnalysis::FunctionCacheTy;
277
+ using StatementCacheTy = TrivialFunctionAnalysis::StatementCacheTy;
257
278
258
- TrivialFunctionAnalysisVisitor (CacheTy &Cache) : Cache(Cache) {}
279
+ TrivialFunctionAnalysisVisitor (FunctionCacheTy &FunctionCache,
280
+ StatementCacheTy &StatementCache)
281
+ : FunctionCache(FunctionCache), StatementCache(StatementCache) {}
259
282
260
283
bool VisitStmt (const Stmt *S) {
261
284
// All statements are non-trivial unless overriden later.
@@ -271,31 +294,48 @@ class TrivialFunctionAnalysisVisitor
271
294
272
295
bool VisitReturnStmt (const ReturnStmt *RS) {
273
296
// A return statement is allowed as long as the return value is trivial.
274
- if (auto *RV = RS->getRetValue ())
275
- return Visit (RV);
276
- return true ;
297
+ return withCachedResult (RS, [&]() {
298
+ if (auto *RV = RS->getRetValue ())
299
+ return Visit (RV);
300
+ return true ;
301
+ });
302
+ }
303
+
304
+ bool VisitCXXForRangeStmt (const CXXForRangeStmt *FS) {
305
+ return VisitChildren (FS);
277
306
}
278
307
279
308
bool VisitDeclStmt (const DeclStmt *DS) { return VisitChildren (DS); }
280
309
bool VisitDoStmt (const DoStmt *DS) { return VisitChildren (DS); }
310
+ bool VisitForStmt (const ForStmt *FS) { return VisitChildren (FS); }
311
+ bool VisitWhileStmt (const WhileStmt *WS) { return VisitChildren (WS); }
281
312
bool VisitIfStmt (const IfStmt *IS) { return VisitChildren (IS); }
282
313
bool VisitSwitchStmt (const SwitchStmt *SS) { return VisitChildren (SS); }
283
314
bool VisitCaseStmt (const CaseStmt *CS) { return VisitChildren (CS); }
284
315
bool VisitDefaultStmt (const DefaultStmt *DS) { return VisitChildren (DS); }
285
316
286
317
bool VisitUnaryOperator (const UnaryOperator *UO) {
287
318
// Operator '*' and '!' are allowed as long as the operand is trivial.
288
- if (UO->getOpcode () == UO_Deref || UO->getOpcode () == UO_AddrOf ||
289
- UO->getOpcode () == UO_LNot)
290
- return Visit (UO->getSubExpr ());
291
-
292
- // Other operators are non-trivial.
293
- return false ;
319
+ return withCachedResult (UO, [&]() {
320
+ auto op = UO->getOpcode ();
321
+ if (op == UO_Deref || op == UO_AddrOf || op == UO_LNot)
322
+ return Visit (UO->getSubExpr ());
323
+ if (UO->isIncrementOp () || UO->isDecrementOp ()) {
324
+ if (auto *RefExpr = dyn_cast<DeclRefExpr>(UO->getSubExpr ())) {
325
+ if (auto *Decl = dyn_cast<VarDecl>(RefExpr->getDecl ()))
326
+ return Decl->isLocalVarDeclOrParm () &&
327
+ Decl->getType ().isPODType (Decl->getASTContext ());
328
+ }
329
+ }
330
+ // Other operators are non-trivial.
331
+ return false ;
332
+ });
294
333
}
295
334
296
335
bool VisitBinaryOperator (const BinaryOperator *BO) {
297
336
// Binary operators are trivial if their operands are trivial.
298
- return Visit (BO->getLHS ()) && Visit (BO->getRHS ());
337
+ return withCachedResult (
338
+ BO, [&]() { return Visit (BO->getLHS ()) && Visit (BO->getRHS ()); });
299
339
}
300
340
301
341
bool VisitConditionalOperator (const ConditionalOperator *CO) {
@@ -304,15 +344,20 @@ class TrivialFunctionAnalysisVisitor
304
344
}
305
345
306
346
bool VisitDeclRefExpr (const DeclRefExpr *DRE) {
307
- if (auto *decl = DRE->getDecl ()) {
308
- if (isa<ParmVarDecl>(decl))
309
- return true ;
310
- if (isa<EnumConstantDecl>(decl))
311
- return true ;
312
- if (auto *VD = dyn_cast<VarDecl>(decl))
313
- return VD->hasConstantInitialization () && VD->getEvaluatedValue ();
314
- }
315
- return false ;
347
+ return withCachedResult (DRE, [&]() {
348
+ if (auto *decl = DRE->getDecl ()) {
349
+ if (isa<ParmVarDecl>(decl))
350
+ return true ;
351
+ if (isa<EnumConstantDecl>(decl))
352
+ return true ;
353
+ if (auto *VD = dyn_cast<VarDecl>(decl)) {
354
+ if (VD->hasConstantInitialization () && VD->getEvaluatedValue ())
355
+ return true ;
356
+ return VD->getInit () ? Visit (VD->getInit ()) : true ;
357
+ }
358
+ }
359
+ return false ;
360
+ });
316
361
}
317
362
318
363
bool VisitAtomicExpr (const AtomicExpr *E) { return VisitChildren (E); }
@@ -323,20 +368,23 @@ class TrivialFunctionAnalysisVisitor
323
368
}
324
369
325
370
bool VisitCallExpr (const CallExpr *CE) {
326
- if (!checkArguments (CE))
327
- return false ;
371
+ return withCachedResult (CE, [&]() {
372
+ if (!checkArguments (CE))
373
+ return false ;
328
374
329
- auto *Callee = CE->getDirectCallee ();
330
- if (!Callee)
331
- return false ;
332
- const auto &Name = safeGetName (Callee);
375
+ auto *Callee = CE->getDirectCallee ();
376
+ if (!Callee)
377
+ return false ;
378
+ const auto &Name = safeGetName (Callee);
333
379
334
- if (Name == " WTFCrashWithInfo" || Name == " WTFBreakpointTrap" ||
335
- Name == " WTFReportAssertionFailure" ||
336
- Name == " compilerFenceForCrash" || Name == " __builtin_unreachable" )
337
- return true ;
380
+ if (Name == " WTFCrashWithInfo" || Name == " WTFBreakpointTrap" ||
381
+ Name == " WTFReportAssertionFailure" ||
382
+ Name == " compilerFenceForCrash" || Name == " __builtin_unreachable" )
383
+ return true ;
338
384
339
- return TrivialFunctionAnalysis::isTrivialImpl (Callee, Cache);
385
+ return TrivialFunctionAnalysis::isTrivialImpl (Callee, FunctionCache,
386
+ StatementCache);
387
+ });
340
388
}
341
389
342
390
bool VisitPredefinedExpr (const PredefinedExpr *E) {
@@ -345,23 +393,26 @@ class TrivialFunctionAnalysisVisitor
345
393
}
346
394
347
395
bool VisitCXXMemberCallExpr (const CXXMemberCallExpr *MCE) {
348
- if (!checkArguments (MCE))
349
- return false ;
396
+ return withCachedResult (MCE, [&]() {
397
+ if (!checkArguments (MCE))
398
+ return false ;
350
399
351
- bool TrivialThis = Visit (MCE->getImplicitObjectArgument ());
352
- if (!TrivialThis)
353
- return false ;
400
+ bool TrivialThis = Visit (MCE->getImplicitObjectArgument ());
401
+ if (!TrivialThis)
402
+ return false ;
354
403
355
- auto *Callee = MCE->getMethodDecl ();
356
- if (!Callee)
357
- return false ;
404
+ auto *Callee = MCE->getMethodDecl ();
405
+ if (!Callee)
406
+ return false ;
358
407
359
- std::optional<bool > IsGetterOfRefCounted = isGetterOfRefCounted (Callee);
360
- if (IsGetterOfRefCounted && *IsGetterOfRefCounted)
361
- return true ;
408
+ std::optional<bool > IsGetterOfRefCounted = isGetterOfRefCounted (Callee);
409
+ if (IsGetterOfRefCounted && *IsGetterOfRefCounted)
410
+ return true ;
362
411
363
- // Recursively descend into the callee to confirm that it's trivial as well.
364
- return TrivialFunctionAnalysis::isTrivialImpl (Callee, Cache);
412
+ // Recursively descend into the callee to confirm it's trivial as well.
413
+ return TrivialFunctionAnalysis::isTrivialImpl (Callee, FunctionCache,
414
+ StatementCache);
415
+ });
365
416
}
366
417
367
418
bool VisitCXXDefaultArgExpr (const CXXDefaultArgExpr *E) {
@@ -381,44 +432,51 @@ class TrivialFunctionAnalysisVisitor
381
432
}
382
433
383
434
bool VisitCXXConstructExpr (const CXXConstructExpr *CE) {
384
- for (const Expr *Arg : CE->arguments ()) {
385
- if (Arg && !Visit (Arg))
386
- return false ;
387
- }
435
+ return withCachedResult (CE, [&]() {
436
+ for (const Expr *Arg : CE->arguments ()) {
437
+ if (Arg && !Visit (Arg))
438
+ return false ;
439
+ }
388
440
389
- // Recursively descend into the callee to confirm that it's trivial.
390
- return TrivialFunctionAnalysis::isTrivialImpl (CE->getConstructor (), Cache);
441
+ // Recursively descend into the callee to confirm that it's trivial.
442
+ return TrivialFunctionAnalysis::isTrivialImpl (
443
+ CE->getConstructor (), FunctionCache, StatementCache);
444
+ });
391
445
}
392
446
393
447
bool VisitImplicitCastExpr (const ImplicitCastExpr *ICE) {
394
- return Visit ( ICE->getSubExpr ());
448
+ return VisitSubExpr (ICE, ICE->getSubExpr ());
395
449
}
396
450
397
451
bool VisitExplicitCastExpr (const ExplicitCastExpr *ECE) {
398
- return Visit ( ECE->getSubExpr ());
452
+ return VisitSubExpr (ECE, ECE->getSubExpr ());
399
453
}
400
454
401
455
bool VisitMaterializeTemporaryExpr (const MaterializeTemporaryExpr *VMT) {
402
- return Visit ( VMT->getSubExpr ());
456
+ return VisitSubExpr (VMT, VMT->getSubExpr ());
403
457
}
404
458
405
459
bool VisitExprWithCleanups (const ExprWithCleanups *EWC) {
406
- return Visit ( EWC->getSubExpr ());
460
+ return VisitSubExpr (EWC, EWC->getSubExpr ());
407
461
}
408
462
409
- bool VisitParenExpr (const ParenExpr *PE) { return Visit (PE->getSubExpr ()); }
463
+ bool VisitParenExpr (const ParenExpr *PE) {
464
+ return VisitSubExpr (PE, PE->getSubExpr ());
465
+ }
410
466
411
467
bool VisitInitListExpr (const InitListExpr *ILE) {
412
- for (const Expr *Child : ILE->inits ()) {
413
- if (Child && !Visit (Child))
414
- return false ;
415
- }
416
- return true ;
468
+ return withCachedResult (ILE, [&]() {
469
+ for (const Expr *Child : ILE->inits ()) {
470
+ if (Child && !Visit (Child))
471
+ return false ;
472
+ }
473
+ return true ;
474
+ });
417
475
}
418
476
419
477
bool VisitMemberExpr (const MemberExpr *ME) {
420
478
// Field access is allowed but the base pointer may itself be non-trivial.
421
- return Visit ( ME->getBase ());
479
+ return VisitSubExpr (ME, ME->getBase ());
422
480
}
423
481
424
482
bool VisitCXXThisExpr (const CXXThisExpr *CTE) {
@@ -444,27 +502,48 @@ class TrivialFunctionAnalysisVisitor
444
502
}
445
503
446
504
private:
447
- CacheTy Cache;
505
+ FunctionCacheTy FunctionCache;
506
+ StatementCacheTy StatementCache;
448
507
};
449
508
450
509
bool TrivialFunctionAnalysis::isTrivialImpl (
451
- const Decl *D, TrivialFunctionAnalysis::CacheTy &Cache) {
510
+ const Decl *D, TrivialFunctionAnalysis::FunctionCacheTy &FunctionCache,
511
+ TrivialFunctionAnalysis::StatementCacheTy &StatementCache) {
452
512
// If the function isn't in the cache, conservatively assume that
453
513
// it's not trivial until analysis completes. This makes every recursive
454
514
// function non-trivial. This also guarantees that each function
455
515
// will be scanned at most once.
456
- auto [It, IsNew] = Cache .insert (std::make_pair (D, false ));
516
+ auto [It, IsNew] = FunctionCache .insert (std::make_pair (D, false ));
457
517
if (!IsNew)
458
518
return It->second ;
459
519
460
520
const Stmt *Body = D->getBody ();
461
521
if (!Body)
462
522
return false ;
463
523
464
- TrivialFunctionAnalysisVisitor V (Cache );
524
+ TrivialFunctionAnalysisVisitor V (FunctionCache, StatementCache );
465
525
bool Result = V.Visit (Body);
466
526
if (Result)
467
- Cache[D] = true ;
527
+ FunctionCache[D] = true ;
528
+
529
+ return Result;
530
+ }
531
+
532
+ bool TrivialFunctionAnalysis::isTrivialImpl (
533
+ const Stmt *S, TrivialFunctionAnalysis::FunctionCacheTy &FunctionCache,
534
+ TrivialFunctionAnalysis::StatementCacheTy &StatementCache) {
535
+ // If the statement isn't in the cache, conservatively assume that
536
+ // it's not trivial until analysis completes. Unlike a function case,
537
+ // we don't insert an entry into the cache until Visit returns
538
+ // since Visit* functions themselves make use of the cache.
539
+
540
+ auto It = StatementCache.find (S);
541
+ if (It != StatementCache.end ())
542
+ return It->second ;
543
+
544
+ TrivialFunctionAnalysisVisitor V (FunctionCache, StatementCache);
545
+ bool Result = V.Visit (S);
546
+ StatementCache[S] = Result;
468
547
469
548
return Result;
470
549
}
0 commit comments