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