1 //=======- PtrTypesSemantics.cpp ---------------------------------*- C++ -*-==//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "PtrTypesSemantics.h"
10 #include "ASTUtils.h"
11 #include "clang/AST/CXXInheritance.h"
12 #include "clang/AST/Decl.h"
13 #include "clang/AST/DeclCXX.h"
14 #include "clang/AST/ExprCXX.h"
15 #include "clang/AST/StmtVisitor.h"
16 #include <optional>
17
18 using namespace clang;
19
20 namespace {
21
hasPublicMethodInBaseClass(const CXXRecordDecl * R,const char * NameToMatch)22 bool hasPublicMethodInBaseClass(const CXXRecordDecl *R,
23 const char *NameToMatch) {
24 assert(R);
25 assert(R->hasDefinition());
26
27 for (const CXXMethodDecl *MD : R->methods()) {
28 const auto MethodName = safeGetName(MD);
29 if (MethodName == NameToMatch && MD->getAccess() == AS_public)
30 return true;
31 }
32 return false;
33 }
34
35 } // namespace
36
37 namespace clang {
38
39 std::optional<const clang::CXXRecordDecl *>
hasPublicMethodInBase(const CXXBaseSpecifier * Base,const char * NameToMatch)40 hasPublicMethodInBase(const CXXBaseSpecifier *Base, const char *NameToMatch) {
41 assert(Base);
42
43 const Type *T = Base->getType().getTypePtrOrNull();
44 if (!T)
45 return std::nullopt;
46
47 const CXXRecordDecl *R = T->getAsCXXRecordDecl();
48 if (!R)
49 return std::nullopt;
50 if (!R->hasDefinition())
51 return std::nullopt;
52
53 return hasPublicMethodInBaseClass(R, NameToMatch) ? R : nullptr;
54 }
55
isRefCountable(const CXXRecordDecl * R)56 std::optional<bool> isRefCountable(const CXXRecordDecl* R)
57 {
58 assert(R);
59
60 R = R->getDefinition();
61 if (!R)
62 return std::nullopt;
63
64 bool hasRef = hasPublicMethodInBaseClass(R, "ref");
65 bool hasDeref = hasPublicMethodInBaseClass(R, "deref");
66 if (hasRef && hasDeref)
67 return true;
68
69 CXXBasePaths Paths;
70 Paths.setOrigin(const_cast<CXXRecordDecl *>(R));
71
72 bool AnyInconclusiveBase = false;
73 const auto hasPublicRefInBase =
74 [&AnyInconclusiveBase](const CXXBaseSpecifier *Base, CXXBasePath &) {
75 auto hasRefInBase = clang::hasPublicMethodInBase(Base, "ref");
76 if (!hasRefInBase) {
77 AnyInconclusiveBase = true;
78 return false;
79 }
80 return (*hasRefInBase) != nullptr;
81 };
82
83 hasRef = hasRef || R->lookupInBases(hasPublicRefInBase, Paths,
84 /*LookupInDependent =*/true);
85 if (AnyInconclusiveBase)
86 return std::nullopt;
87
88 Paths.clear();
89 const auto hasPublicDerefInBase =
90 [&AnyInconclusiveBase](const CXXBaseSpecifier *Base, CXXBasePath &) {
91 auto hasDerefInBase = clang::hasPublicMethodInBase(Base, "deref");
92 if (!hasDerefInBase) {
93 AnyInconclusiveBase = true;
94 return false;
95 }
96 return (*hasDerefInBase) != nullptr;
97 };
98 hasDeref = hasDeref || R->lookupInBases(hasPublicDerefInBase, Paths,
99 /*LookupInDependent =*/true);
100 if (AnyInconclusiveBase)
101 return std::nullopt;
102
103 return hasRef && hasDeref;
104 }
105
isRefType(const std::string & Name)106 bool isRefType(const std::string &Name) {
107 return Name == "Ref" || Name == "RefAllowingPartiallyDestroyed" ||
108 Name == "RefPtr" || Name == "RefPtrAllowingPartiallyDestroyed";
109 }
110
isCtorOfRefCounted(const clang::FunctionDecl * F)111 bool isCtorOfRefCounted(const clang::FunctionDecl *F) {
112 assert(F);
113 const std::string &FunctionName = safeGetName(F);
114
115 return isRefType(FunctionName) || FunctionName == "makeRef" ||
116 FunctionName == "makeRefPtr" || FunctionName == "UniqueRef" ||
117 FunctionName == "makeUniqueRef" ||
118 FunctionName == "makeUniqueRefWithoutFastMallocCheck"
119
120 || FunctionName == "String" || FunctionName == "AtomString" ||
121 FunctionName == "UniqueString"
122 // FIXME: Implement as attribute.
123 || FunctionName == "Identifier";
124 }
125
isReturnValueRefCounted(const clang::FunctionDecl * F)126 bool isReturnValueRefCounted(const clang::FunctionDecl *F) {
127 assert(F);
128 QualType type = F->getReturnType();
129 while (!type.isNull()) {
130 if (auto *elaboratedT = type->getAs<ElaboratedType>()) {
131 type = elaboratedT->desugar();
132 continue;
133 }
134 if (auto *specialT = type->getAs<TemplateSpecializationType>()) {
135 if (auto *decl = specialT->getTemplateName().getAsTemplateDecl()) {
136 auto name = decl->getNameAsString();
137 return isRefType(name);
138 }
139 return false;
140 }
141 return false;
142 }
143 return false;
144 }
145
isUncounted(const CXXRecordDecl * Class)146 std::optional<bool> isUncounted(const CXXRecordDecl* Class)
147 {
148 // Keep isRefCounted first as it's cheaper.
149 if (isRefCounted(Class))
150 return false;
151
152 std::optional<bool> IsRefCountable = isRefCountable(Class);
153 if (!IsRefCountable)
154 return std::nullopt;
155
156 return (*IsRefCountable);
157 }
158
isUncountedPtr(const Type * T)159 std::optional<bool> isUncountedPtr(const Type* T)
160 {
161 assert(T);
162
163 if (T->isPointerType() || T->isReferenceType()) {
164 if (auto *CXXRD = T->getPointeeCXXRecordDecl()) {
165 return isUncounted(CXXRD);
166 }
167 }
168 return false;
169 }
170
isGetterOfRefCounted(const CXXMethodDecl * M)171 std::optional<bool> isGetterOfRefCounted(const CXXMethodDecl* M)
172 {
173 assert(M);
174
175 if (isa<CXXMethodDecl>(M)) {
176 const CXXRecordDecl *calleeMethodsClass = M->getParent();
177 auto className = safeGetName(calleeMethodsClass);
178 auto method = safeGetName(M);
179
180 if ((isRefType(className) && (method == "get" || method == "ptr")) ||
181 ((className == "String" || className == "AtomString" ||
182 className == "AtomStringImpl" || className == "UniqueString" ||
183 className == "UniqueStringImpl" || className == "Identifier") &&
184 method == "impl"))
185 return true;
186
187 // Ref<T> -> T conversion
188 // FIXME: Currently allowing any Ref<T> -> whatever cast.
189 if (isRefType(className)) {
190 if (auto *maybeRefToRawOperator = dyn_cast<CXXConversionDecl>(M)) {
191 if (auto *targetConversionType =
192 maybeRefToRawOperator->getConversionType().getTypePtrOrNull()) {
193 return isUncountedPtr(targetConversionType);
194 }
195 }
196 }
197 }
198 return false;
199 }
200
isRefCounted(const CXXRecordDecl * R)201 bool isRefCounted(const CXXRecordDecl *R) {
202 assert(R);
203 if (auto *TmplR = R->getTemplateInstantiationPattern()) {
204 // FIXME: String/AtomString/UniqueString
205 const auto &ClassName = safeGetName(TmplR);
206 return isRefType(ClassName);
207 }
208 return false;
209 }
210
isPtrConversion(const FunctionDecl * F)211 bool isPtrConversion(const FunctionDecl *F) {
212 assert(F);
213 if (isCtorOfRefCounted(F))
214 return true;
215
216 // FIXME: check # of params == 1
217 const auto FunctionName = safeGetName(F);
218 if (FunctionName == "getPtr" || FunctionName == "WeakPtr" ||
219 FunctionName == "dynamicDowncast" || FunctionName == "downcast" ||
220 FunctionName == "checkedDowncast" ||
221 FunctionName == "uncheckedDowncast" || FunctionName == "bitwise_cast")
222 return true;
223
224 return false;
225 }
226
isSingleton(const FunctionDecl * F)227 bool isSingleton(const FunctionDecl *F) {
228 assert(F);
229 // FIXME: check # of params == 1
230 if (auto *MethodDecl = dyn_cast<CXXMethodDecl>(F)) {
231 if (!MethodDecl->isStatic())
232 return false;
233 }
234 const auto &Name = safeGetName(F);
235 std::string SingletonStr = "singleton";
236 auto index = Name.find(SingletonStr);
237 return index != std::string::npos &&
238 index == Name.size() - SingletonStr.size();
239 }
240
241 // We only care about statements so let's use the simple
242 // (non-recursive) visitor.
243 class TrivialFunctionAnalysisVisitor
244 : public ConstStmtVisitor<TrivialFunctionAnalysisVisitor, bool> {
245
246 // Returns false if at least one child is non-trivial.
VisitChildren(const Stmt * S)247 bool VisitChildren(const Stmt *S) {
248 for (const Stmt *Child : S->children()) {
249 if (Child && !Visit(Child))
250 return false;
251 }
252
253 return true;
254 }
255
256 template <typename CheckFunction>
WithCachedResult(const Stmt * S,CheckFunction Function)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
269 public:
270 using CacheTy = TrivialFunctionAnalysis::CacheTy;
271
TrivialFunctionAnalysisVisitor(CacheTy & Cache)272 TrivialFunctionAnalysisVisitor(CacheTy &Cache) : Cache(Cache) {}
273
IsFunctionTrivial(const Decl * D)274 bool IsFunctionTrivial(const Decl *D) {
275 auto CacheIt = Cache.find(D);
276 if (CacheIt != Cache.end())
277 return CacheIt->second;
278
279 // Treat a recursive function call to be trivial until proven otherwise.
280 auto [RecursiveIt, IsNew] = RecursiveFn.insert(std::make_pair(D, true));
281 if (!IsNew)
282 return RecursiveIt->second;
283
284 bool Result = [&]() {
285 if (auto *CtorDecl = dyn_cast<CXXConstructorDecl>(D)) {
286 for (auto *CtorInit : CtorDecl->inits()) {
287 if (!Visit(CtorInit->getInit()))
288 return false;
289 }
290 }
291 const Stmt *Body = D->getBody();
292 if (!Body)
293 return false;
294 return Visit(Body);
295 }();
296
297 if (!Result) {
298 // D and its mutually recursive callers are all non-trivial.
299 for (auto &It : RecursiveFn)
300 It.second = false;
301 }
302 RecursiveIt = RecursiveFn.find(D);
303 assert(RecursiveIt != RecursiveFn.end());
304 Result = RecursiveIt->second;
305 RecursiveFn.erase(RecursiveIt);
306 Cache[D] = Result;
307
308 return Result;
309 }
310
VisitStmt(const Stmt * S)311 bool VisitStmt(const Stmt *S) {
312 // All statements are non-trivial unless overriden later.
313 // Don't even recurse into children by default.
314 return false;
315 }
316
VisitCompoundStmt(const CompoundStmt * CS)317 bool VisitCompoundStmt(const CompoundStmt *CS) {
318 // A compound statement is allowed as long each individual sub-statement
319 // is trivial.
320 return WithCachedResult(CS, [&]() { return VisitChildren(CS); });
321 }
322
VisitReturnStmt(const ReturnStmt * RS)323 bool VisitReturnStmt(const ReturnStmt *RS) {
324 // A return statement is allowed as long as the return value is trivial.
325 if (auto *RV = RS->getRetValue())
326 return Visit(RV);
327 return true;
328 }
329
VisitDeclStmt(const DeclStmt * DS)330 bool VisitDeclStmt(const DeclStmt *DS) { return VisitChildren(DS); }
VisitDoStmt(const DoStmt * DS)331 bool VisitDoStmt(const DoStmt *DS) { return VisitChildren(DS); }
VisitIfStmt(const IfStmt * IS)332 bool VisitIfStmt(const IfStmt *IS) {
333 return WithCachedResult(IS, [&]() { return VisitChildren(IS); });
334 }
VisitForStmt(const ForStmt * FS)335 bool VisitForStmt(const ForStmt *FS) {
336 return WithCachedResult(FS, [&]() { return VisitChildren(FS); });
337 }
VisitCXXForRangeStmt(const CXXForRangeStmt * FS)338 bool VisitCXXForRangeStmt(const CXXForRangeStmt *FS) {
339 return WithCachedResult(FS, [&]() { return VisitChildren(FS); });
340 }
VisitWhileStmt(const WhileStmt * WS)341 bool VisitWhileStmt(const WhileStmt *WS) {
342 return WithCachedResult(WS, [&]() { return VisitChildren(WS); });
343 }
VisitSwitchStmt(const SwitchStmt * SS)344 bool VisitSwitchStmt(const SwitchStmt *SS) { return VisitChildren(SS); }
VisitCaseStmt(const CaseStmt * CS)345 bool VisitCaseStmt(const CaseStmt *CS) { return VisitChildren(CS); }
VisitDefaultStmt(const DefaultStmt * DS)346 bool VisitDefaultStmt(const DefaultStmt *DS) { return VisitChildren(DS); }
347
348 // break, continue, goto, and label statements are always trivial.
VisitBreakStmt(const BreakStmt *)349 bool VisitBreakStmt(const BreakStmt *) { return true; }
VisitContinueStmt(const ContinueStmt *)350 bool VisitContinueStmt(const ContinueStmt *) { return true; }
VisitGotoStmt(const GotoStmt *)351 bool VisitGotoStmt(const GotoStmt *) { return true; }
VisitLabelStmt(const LabelStmt *)352 bool VisitLabelStmt(const LabelStmt *) { return true; }
353
VisitUnaryOperator(const UnaryOperator * UO)354 bool VisitUnaryOperator(const UnaryOperator *UO) {
355 // Unary operators are trivial if its operand is trivial except co_await.
356 return UO->getOpcode() != UO_Coawait && Visit(UO->getSubExpr());
357 }
358
VisitBinaryOperator(const BinaryOperator * BO)359 bool VisitBinaryOperator(const BinaryOperator *BO) {
360 // Binary operators are trivial if their operands are trivial.
361 return Visit(BO->getLHS()) && Visit(BO->getRHS());
362 }
363
VisitCompoundAssignOperator(const CompoundAssignOperator * CAO)364 bool VisitCompoundAssignOperator(const CompoundAssignOperator *CAO) {
365 // Compound assignment operator such as |= is trivial if its
366 // subexpresssions are trivial.
367 return VisitChildren(CAO);
368 }
369
VisitArraySubscriptExpr(const ArraySubscriptExpr * ASE)370 bool VisitArraySubscriptExpr(const ArraySubscriptExpr *ASE) {
371 return VisitChildren(ASE);
372 }
373
VisitConditionalOperator(const ConditionalOperator * CO)374 bool VisitConditionalOperator(const ConditionalOperator *CO) {
375 // Ternary operators are trivial if their conditions & values are trivial.
376 return VisitChildren(CO);
377 }
378
VisitAtomicExpr(const AtomicExpr * E)379 bool VisitAtomicExpr(const AtomicExpr *E) { return VisitChildren(E); }
380
VisitStaticAssertDecl(const StaticAssertDecl * SAD)381 bool VisitStaticAssertDecl(const StaticAssertDecl *SAD) {
382 // Any static_assert is considered trivial.
383 return true;
384 }
385
VisitCallExpr(const CallExpr * CE)386 bool VisitCallExpr(const CallExpr *CE) {
387 if (!checkArguments(CE))
388 return false;
389
390 auto *Callee = CE->getDirectCallee();
391 if (!Callee)
392 return false;
393 const auto &Name = safeGetName(Callee);
394
395 if (Callee->isInStdNamespace() &&
396 (Name == "addressof" || Name == "forward" || Name == "move"))
397 return true;
398
399 if (Name == "WTFCrashWithInfo" || Name == "WTFBreakpointTrap" ||
400 Name == "WTFCrashWithSecurityImplication" || Name == "WTFCrash" ||
401 Name == "WTFReportAssertionFailure" || Name == "isMainThread" ||
402 Name == "isMainThreadOrGCThread" || Name == "isMainRunLoop" ||
403 Name == "isWebThread" || Name == "isUIThread" ||
404 Name == "mayBeGCThread" || Name == "compilerFenceForCrash" ||
405 Name == "bitwise_cast" || Name.find("__builtin") == 0)
406 return true;
407
408 return IsFunctionTrivial(Callee);
409 }
410
411 bool
VisitSubstNonTypeTemplateParmExpr(const SubstNonTypeTemplateParmExpr * E)412 VisitSubstNonTypeTemplateParmExpr(const SubstNonTypeTemplateParmExpr *E) {
413 // Non-type template paramter is compile time constant and trivial.
414 return true;
415 }
416
VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr * E)417 bool VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *E) {
418 return VisitChildren(E);
419 }
420
VisitPredefinedExpr(const PredefinedExpr * E)421 bool VisitPredefinedExpr(const PredefinedExpr *E) {
422 // A predefined identifier such as "func" is considered trivial.
423 return true;
424 }
425
VisitCXXMemberCallExpr(const CXXMemberCallExpr * MCE)426 bool VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE) {
427 if (!checkArguments(MCE))
428 return false;
429
430 bool TrivialThis = Visit(MCE->getImplicitObjectArgument());
431 if (!TrivialThis)
432 return false;
433
434 auto *Callee = MCE->getMethodDecl();
435 if (!Callee)
436 return false;
437
438 std::optional<bool> IsGetterOfRefCounted = isGetterOfRefCounted(Callee);
439 if (IsGetterOfRefCounted && *IsGetterOfRefCounted)
440 return true;
441
442 // Recursively descend into the callee to confirm that it's trivial as well.
443 return IsFunctionTrivial(Callee);
444 }
445
VisitCXXOperatorCallExpr(const CXXOperatorCallExpr * OCE)446 bool VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *OCE) {
447 if (!checkArguments(OCE))
448 return false;
449 auto *Callee = OCE->getCalleeDecl();
450 if (!Callee)
451 return false;
452 // Recursively descend into the callee to confirm that it's trivial as well.
453 return IsFunctionTrivial(Callee);
454 }
455
VisitCXXDefaultArgExpr(const CXXDefaultArgExpr * E)456 bool VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E) {
457 if (auto *Expr = E->getExpr()) {
458 if (!Visit(Expr))
459 return false;
460 }
461 return true;
462 }
463
checkArguments(const CallExpr * CE)464 bool checkArguments(const CallExpr *CE) {
465 for (const Expr *Arg : CE->arguments()) {
466 if (Arg && !Visit(Arg))
467 return false;
468 }
469 return true;
470 }
471
VisitCXXConstructExpr(const CXXConstructExpr * CE)472 bool VisitCXXConstructExpr(const CXXConstructExpr *CE) {
473 for (const Expr *Arg : CE->arguments()) {
474 if (Arg && !Visit(Arg))
475 return false;
476 }
477
478 // Recursively descend into the callee to confirm that it's trivial.
479 return IsFunctionTrivial(CE->getConstructor());
480 }
481
VisitCXXNewExpr(const CXXNewExpr * NE)482 bool VisitCXXNewExpr(const CXXNewExpr *NE) { return VisitChildren(NE); }
483
VisitImplicitCastExpr(const ImplicitCastExpr * ICE)484 bool VisitImplicitCastExpr(const ImplicitCastExpr *ICE) {
485 return Visit(ICE->getSubExpr());
486 }
487
VisitExplicitCastExpr(const ExplicitCastExpr * ECE)488 bool VisitExplicitCastExpr(const ExplicitCastExpr *ECE) {
489 return Visit(ECE->getSubExpr());
490 }
491
VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr * VMT)492 bool VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *VMT) {
493 return Visit(VMT->getSubExpr());
494 }
495
VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr * BTE)496 bool VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *BTE) {
497 if (auto *Temp = BTE->getTemporary()) {
498 if (!TrivialFunctionAnalysis::isTrivialImpl(Temp->getDestructor(), Cache))
499 return false;
500 }
501 return Visit(BTE->getSubExpr());
502 }
503
VisitExprWithCleanups(const ExprWithCleanups * EWC)504 bool VisitExprWithCleanups(const ExprWithCleanups *EWC) {
505 return Visit(EWC->getSubExpr());
506 }
507
VisitParenExpr(const ParenExpr * PE)508 bool VisitParenExpr(const ParenExpr *PE) { return Visit(PE->getSubExpr()); }
509
VisitInitListExpr(const InitListExpr * ILE)510 bool VisitInitListExpr(const InitListExpr *ILE) {
511 for (const Expr *Child : ILE->inits()) {
512 if (Child && !Visit(Child))
513 return false;
514 }
515 return true;
516 }
517
VisitMemberExpr(const MemberExpr * ME)518 bool VisitMemberExpr(const MemberExpr *ME) {
519 // Field access is allowed but the base pointer may itself be non-trivial.
520 return Visit(ME->getBase());
521 }
522
VisitCXXThisExpr(const CXXThisExpr * CTE)523 bool VisitCXXThisExpr(const CXXThisExpr *CTE) {
524 // The expression 'this' is always trivial, be it explicit or implicit.
525 return true;
526 }
527
VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr * E)528 bool VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *E) {
529 // nullptr is trivial.
530 return true;
531 }
532
VisitDeclRefExpr(const DeclRefExpr * DRE)533 bool VisitDeclRefExpr(const DeclRefExpr *DRE) {
534 // The use of a variable is trivial.
535 return true;
536 }
537
538 // Constant literal expressions are always trivial
VisitIntegerLiteral(const IntegerLiteral * E)539 bool VisitIntegerLiteral(const IntegerLiteral *E) { return true; }
VisitFloatingLiteral(const FloatingLiteral * E)540 bool VisitFloatingLiteral(const FloatingLiteral *E) { return true; }
VisitFixedPointLiteral(const FixedPointLiteral * E)541 bool VisitFixedPointLiteral(const FixedPointLiteral *E) { return true; }
VisitCharacterLiteral(const CharacterLiteral * E)542 bool VisitCharacterLiteral(const CharacterLiteral *E) { return true; }
VisitStringLiteral(const StringLiteral * E)543 bool VisitStringLiteral(const StringLiteral *E) { return true; }
VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr * E)544 bool VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *E) { return true; }
545
VisitConstantExpr(const ConstantExpr * CE)546 bool VisitConstantExpr(const ConstantExpr *CE) {
547 // Constant expressions are trivial.
548 return true;
549 }
550
551 private:
552 CacheTy &Cache;
553 CacheTy RecursiveFn;
554 };
555
isTrivialImpl(const Decl * D,TrivialFunctionAnalysis::CacheTy & Cache)556 bool TrivialFunctionAnalysis::isTrivialImpl(
557 const Decl *D, TrivialFunctionAnalysis::CacheTy &Cache) {
558 TrivialFunctionAnalysisVisitor V(Cache);
559 return V.IsFunctionTrivial(D);
560 }
561
isTrivialImpl(const Stmt * S,TrivialFunctionAnalysis::CacheTy & Cache)562 bool TrivialFunctionAnalysis::isTrivialImpl(
563 const Stmt *S, TrivialFunctionAnalysis::CacheTy &Cache) {
564 // If the statement isn't in the cache, conservatively assume that
565 // it's not trivial until analysis completes. Unlike a function case,
566 // we don't insert an entry into the cache until Visit returns
567 // since Visit* functions themselves make use of the cache.
568
569 TrivialFunctionAnalysisVisitor V(Cache);
570 bool Result = V.Visit(S);
571 assert(Cache.contains(S) && "Top-level statement not properly cached!");
572 return Result;
573 }
574
575 } // namespace clang
576