@@ -253,6 +253,19 @@ class TrivialFunctionAnalysisVisitor
253
253
return true ;
254
254
}
255
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
+
256
269
public:
257
270
using CacheTy = TrivialFunctionAnalysis::CacheTy;
258
271
@@ -267,7 +280,7 @@ class TrivialFunctionAnalysisVisitor
267
280
bool VisitCompoundStmt (const CompoundStmt *CS) {
268
281
// A compound statement is allowed as long each individual sub-statement
269
282
// is trivial.
270
- return VisitChildren (CS);
283
+ return WithCachedResult (CS, [&]() { return VisitChildren (CS); } );
271
284
}
272
285
273
286
bool VisitReturnStmt (const ReturnStmt *RS) {
@@ -279,17 +292,36 @@ class TrivialFunctionAnalysisVisitor
279
292
280
293
bool VisitDeclStmt (const DeclStmt *DS) { return VisitChildren (DS); }
281
294
bool VisitDoStmt (const DoStmt *DS) { return VisitChildren (DS); }
282
- 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
+ }
283
307
bool VisitSwitchStmt (const SwitchStmt *SS) { return VisitChildren (SS); }
284
308
bool VisitCaseStmt (const CaseStmt *CS) { return VisitChildren (CS); }
285
309
bool VisitDefaultStmt (const DefaultStmt *DS) { return VisitChildren (DS); }
286
310
287
311
bool VisitUnaryOperator (const UnaryOperator *UO) {
288
312
// Operator '*' and '!' are allowed as long as the operand is trivial.
289
- if (UO-> getOpcode () == UO_Deref || UO->getOpcode () == UO_AddrOf ||
290
- UO-> getOpcode () == UO_LNot)
313
+ auto op = UO->getOpcode ();
314
+ if (op == UO_Deref || op == UO_AddrOf || op == UO_LNot)
291
315
return Visit (UO->getSubExpr ());
292
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
+ }
293
325
// Other operators are non-trivial.
294
326
return false ;
295
327
}
@@ -304,22 +336,6 @@ class TrivialFunctionAnalysisVisitor
304
336
return VisitChildren (CO);
305
337
}
306
338
307
- bool VisitDeclRefExpr (const DeclRefExpr *DRE) {
308
- if (auto *decl = DRE->getDecl ()) {
309
- if (isa<ParmVarDecl>(decl))
310
- return true ;
311
- if (isa<EnumConstantDecl>(decl))
312
- return true ;
313
- if (auto *VD = dyn_cast<VarDecl>(decl)) {
314
- if (VD->hasConstantInitialization () && VD->getEvaluatedValue ())
315
- return true ;
316
- auto *Init = VD->getInit ();
317
- return !Init || Visit (Init);
318
- }
319
- }
320
- return false ;
321
- }
322
-
323
339
bool VisitAtomicExpr (const AtomicExpr *E) { return VisitChildren (E); }
324
340
325
341
bool VisitStaticAssertDecl (const StaticAssertDecl *SAD) {
@@ -436,6 +452,11 @@ class TrivialFunctionAnalysisVisitor
436
452
return true ;
437
453
}
438
454
455
+ bool VisitDeclRefExpr (const DeclRefExpr *DRE) {
456
+ // The use of a variable is trivial.
457
+ return true ;
458
+ }
459
+
439
460
// Constant literal expressions are always trivial
440
461
bool VisitIntegerLiteral (const IntegerLiteral *E) { return true ; }
441
462
bool VisitFloatingLiteral (const FloatingLiteral *E) { return true ; }
@@ -449,7 +470,7 @@ class TrivialFunctionAnalysisVisitor
449
470
}
450
471
451
472
private:
452
- CacheTy Cache;
473
+ CacheTy & Cache;
453
474
};
454
475
455
476
bool TrivialFunctionAnalysis::isTrivialImpl (
@@ -474,4 +495,17 @@ bool TrivialFunctionAnalysis::isTrivialImpl(
474
495
return Result;
475
496
}
476
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
+
477
511
} // namespace clang
0 commit comments