17fe43adaSDoug Wyatt //=== SemaFunctionEffects.cpp - Sema handling of function effects ---------===// 27fe43adaSDoug Wyatt // 37fe43adaSDoug Wyatt // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 47fe43adaSDoug Wyatt // See https://llvm.org/LICENSE.txt for license information. 57fe43adaSDoug Wyatt // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 67fe43adaSDoug Wyatt // 77fe43adaSDoug Wyatt //===----------------------------------------------------------------------===// 87fe43adaSDoug Wyatt // 97fe43adaSDoug Wyatt // This file implements Sema handling of function effects. 107fe43adaSDoug Wyatt // 117fe43adaSDoug Wyatt //===----------------------------------------------------------------------===// 127fe43adaSDoug Wyatt 137fe43adaSDoug Wyatt #include "clang/AST/Decl.h" 147fe43adaSDoug Wyatt #include "clang/AST/DeclCXX.h" 15dde802b1SSirraide #include "clang/AST/DynamicRecursiveASTVisitor.h" 16dde802b1SSirraide #include "clang/AST/ExprObjC.h" 177fe43adaSDoug Wyatt #include "clang/AST/Stmt.h" 18dde802b1SSirraide #include "clang/AST/StmtObjC.h" 197fe43adaSDoug Wyatt #include "clang/AST/Type.h" 207fe43adaSDoug Wyatt #include "clang/Basic/SourceManager.h" 217fe43adaSDoug Wyatt #include "clang/Sema/SemaInternal.h" 227fe43adaSDoug Wyatt 237fe43adaSDoug Wyatt #define DEBUG_TYPE "effectanalysis" 247fe43adaSDoug Wyatt 257fe43adaSDoug Wyatt using namespace clang; 267fe43adaSDoug Wyatt 277fe43adaSDoug Wyatt namespace { 287fe43adaSDoug Wyatt 297fe43adaSDoug Wyatt enum class ViolationID : uint8_t { 307fe43adaSDoug Wyatt None = 0, // Sentinel for an empty Violation. 317fe43adaSDoug Wyatt // These first 5 map to a %select{} in one of several FunctionEffects 327fe43adaSDoug Wyatt // diagnostics, e.g. warn_func_effect_violation. 337fe43adaSDoug Wyatt BaseDiagnosticIndex, 347fe43adaSDoug Wyatt AllocatesMemory = BaseDiagnosticIndex, 357fe43adaSDoug Wyatt ThrowsOrCatchesExceptions, 367fe43adaSDoug Wyatt HasStaticLocalVariable, 377fe43adaSDoug Wyatt AccessesThreadLocalVariable, 387fe43adaSDoug Wyatt AccessesObjCMethodOrProperty, 397fe43adaSDoug Wyatt 407fe43adaSDoug Wyatt // These only apply to callees, where the analysis stops at the Decl. 417fe43adaSDoug Wyatt DeclDisallowsInference, 427fe43adaSDoug Wyatt 437fe43adaSDoug Wyatt // These both apply to indirect calls. The difference is that sometimes 447fe43adaSDoug Wyatt // we have an actual Decl (generally a variable) which is the function 457fe43adaSDoug Wyatt // pointer being called, and sometimes, typically due to a cast, we only 467fe43adaSDoug Wyatt // have an expression. 477fe43adaSDoug Wyatt CallsDeclWithoutEffect, 487fe43adaSDoug Wyatt CallsExprWithoutEffect, 497fe43adaSDoug Wyatt }; 507fe43adaSDoug Wyatt 517fe43adaSDoug Wyatt // Information about the AST context in which a violation was found, so 527fe43adaSDoug Wyatt // that diagnostics can point to the correct source. 537fe43adaSDoug Wyatt class ViolationSite { 547fe43adaSDoug Wyatt public: 557fe43adaSDoug Wyatt enum class Kind : uint8_t { 567fe43adaSDoug Wyatt Default, // Function body. 577fe43adaSDoug Wyatt MemberInitializer, 587fe43adaSDoug Wyatt DefaultArgExpr 597fe43adaSDoug Wyatt }; 607fe43adaSDoug Wyatt 617fe43adaSDoug Wyatt private: 627fe43adaSDoug Wyatt llvm::PointerIntPair<CXXDefaultArgExpr *, 2, Kind> Impl; 637fe43adaSDoug Wyatt 647fe43adaSDoug Wyatt public: 657fe43adaSDoug Wyatt ViolationSite() = default; 667fe43adaSDoug Wyatt 677fe43adaSDoug Wyatt explicit ViolationSite(CXXDefaultArgExpr *E) 687fe43adaSDoug Wyatt : Impl(E, Kind::DefaultArgExpr) {} 697fe43adaSDoug Wyatt 707fe43adaSDoug Wyatt Kind kind() const { return static_cast<Kind>(Impl.getInt()); } 717fe43adaSDoug Wyatt CXXDefaultArgExpr *defaultArgExpr() const { return Impl.getPointer(); } 727fe43adaSDoug Wyatt 737fe43adaSDoug Wyatt void setKind(Kind K) { Impl.setPointerAndInt(nullptr, K); } 747fe43adaSDoug Wyatt }; 757fe43adaSDoug Wyatt 767fe43adaSDoug Wyatt // Represents a violation of the rules, potentially for the entire duration of 777fe43adaSDoug Wyatt // the analysis phase, in order to refer to it when explaining why a caller has 787fe43adaSDoug Wyatt // been made unsafe by a callee. Can be transformed into either a Diagnostic 797fe43adaSDoug Wyatt // (warning or a note), depending on whether the violation pertains to a 807fe43adaSDoug Wyatt // function failing to be verifed as holding an effect vs. a function failing to 817fe43adaSDoug Wyatt // be inferred as holding that effect. 827fe43adaSDoug Wyatt struct Violation { 837fe43adaSDoug Wyatt FunctionEffect Effect; 847fe43adaSDoug Wyatt std::optional<FunctionEffect> 857fe43adaSDoug Wyatt CalleeEffectPreventingInference; // Only for certain IDs; can be nullopt. 867fe43adaSDoug Wyatt ViolationID ID = ViolationID::None; 877fe43adaSDoug Wyatt ViolationSite Site; 887fe43adaSDoug Wyatt SourceLocation Loc; 897fe43adaSDoug Wyatt const Decl *Callee = 907fe43adaSDoug Wyatt nullptr; // Only valid for ViolationIDs Calls{Decl,Expr}WithoutEffect. 917fe43adaSDoug Wyatt 927fe43adaSDoug Wyatt Violation(FunctionEffect Effect, ViolationID ID, ViolationSite VS, 937fe43adaSDoug Wyatt SourceLocation Loc, const Decl *Callee = nullptr, 947fe43adaSDoug Wyatt std::optional<FunctionEffect> CalleeEffect = std::nullopt) 957fe43adaSDoug Wyatt : Effect(Effect), CalleeEffectPreventingInference(CalleeEffect), ID(ID), 967fe43adaSDoug Wyatt Site(VS), Loc(Loc), Callee(Callee) {} 977fe43adaSDoug Wyatt 987fe43adaSDoug Wyatt unsigned diagnosticSelectIndex() const { 997fe43adaSDoug Wyatt return unsigned(ID) - unsigned(ViolationID::BaseDiagnosticIndex); 1007fe43adaSDoug Wyatt } 1017fe43adaSDoug Wyatt }; 1027fe43adaSDoug Wyatt 1037fe43adaSDoug Wyatt enum class SpecialFuncType : uint8_t { None, OperatorNew, OperatorDelete }; 1047fe43adaSDoug Wyatt enum class CallableType : uint8_t { 1057fe43adaSDoug Wyatt // Unknown: probably function pointer. 1067fe43adaSDoug Wyatt Unknown, 1077fe43adaSDoug Wyatt Function, 1087fe43adaSDoug Wyatt Virtual, 1097fe43adaSDoug Wyatt Block 1107fe43adaSDoug Wyatt }; 1117fe43adaSDoug Wyatt 1127fe43adaSDoug Wyatt // Return whether a function's effects CAN be verified. 1137fe43adaSDoug Wyatt // The question of whether it SHOULD be verified is independent. 1147fe43adaSDoug Wyatt static bool functionIsVerifiable(const FunctionDecl *FD) { 1157fe43adaSDoug Wyatt if (FD->isTrivial()) { 1167fe43adaSDoug Wyatt // Otherwise `struct x { int a; };` would have an unverifiable default 1177fe43adaSDoug Wyatt // constructor. 1187fe43adaSDoug Wyatt return true; 1197fe43adaSDoug Wyatt } 1207fe43adaSDoug Wyatt return FD->hasBody(); 1217fe43adaSDoug Wyatt } 1227fe43adaSDoug Wyatt 1237fe43adaSDoug Wyatt static bool isNoexcept(const FunctionDecl *FD) { 1247fe43adaSDoug Wyatt const auto *FPT = FD->getType()->getAs<FunctionProtoType>(); 1257fe43adaSDoug Wyatt return FPT && (FPT->isNothrow() || FD->hasAttr<NoThrowAttr>()); 1267fe43adaSDoug Wyatt } 1277fe43adaSDoug Wyatt 1287fe43adaSDoug Wyatt // This list is probably incomplete. 1297fe43adaSDoug Wyatt // FIXME: Investigate: 1307fe43adaSDoug Wyatt // __builtin_eh_return? 1317fe43adaSDoug Wyatt // __builtin_allow_runtime_check? 1327fe43adaSDoug Wyatt // __builtin_unwind_init and other similar things that sound exception-related. 1337fe43adaSDoug Wyatt // va_copy? 1347fe43adaSDoug Wyatt // coroutines? 1357fe43adaSDoug Wyatt static FunctionEffectKindSet getBuiltinFunctionEffects(unsigned BuiltinID) { 1367fe43adaSDoug Wyatt FunctionEffectKindSet Result; 1377fe43adaSDoug Wyatt 1387fe43adaSDoug Wyatt switch (BuiltinID) { 1397fe43adaSDoug Wyatt case 0: // Not builtin. 1407fe43adaSDoug Wyatt default: // By default, builtins have no known effects. 1417fe43adaSDoug Wyatt break; 1427fe43adaSDoug Wyatt 1437fe43adaSDoug Wyatt // These allocate/deallocate heap memory. 1447fe43adaSDoug Wyatt case Builtin::ID::BI__builtin_calloc: 1457fe43adaSDoug Wyatt case Builtin::ID::BI__builtin_malloc: 1467fe43adaSDoug Wyatt case Builtin::ID::BI__builtin_realloc: 1477fe43adaSDoug Wyatt case Builtin::ID::BI__builtin_free: 1487fe43adaSDoug Wyatt case Builtin::ID::BI__builtin_operator_delete: 1497fe43adaSDoug Wyatt case Builtin::ID::BI__builtin_operator_new: 1507fe43adaSDoug Wyatt case Builtin::ID::BIaligned_alloc: 1517fe43adaSDoug Wyatt case Builtin::ID::BIcalloc: 1527fe43adaSDoug Wyatt case Builtin::ID::BImalloc: 1537fe43adaSDoug Wyatt case Builtin::ID::BImemalign: 1547fe43adaSDoug Wyatt case Builtin::ID::BIrealloc: 1557fe43adaSDoug Wyatt case Builtin::ID::BIfree: 1567fe43adaSDoug Wyatt 1577fe43adaSDoug Wyatt case Builtin::ID::BIfopen: 1587fe43adaSDoug Wyatt case Builtin::ID::BIpthread_create: 1597fe43adaSDoug Wyatt case Builtin::ID::BI_Block_object_dispose: 1607fe43adaSDoug Wyatt Result.insert(FunctionEffect(FunctionEffect::Kind::Allocating)); 1617fe43adaSDoug Wyatt break; 1627fe43adaSDoug Wyatt 1637fe43adaSDoug Wyatt // These block in some other way than allocating memory. 1647fe43adaSDoug Wyatt // longjmp() and friends are presumed unsafe because they are the moral 1657fe43adaSDoug Wyatt // equivalent of throwing a C++ exception, which is unsafe. 1667fe43adaSDoug Wyatt case Builtin::ID::BIlongjmp: 1677fe43adaSDoug Wyatt case Builtin::ID::BI_longjmp: 1687fe43adaSDoug Wyatt case Builtin::ID::BIsiglongjmp: 1697fe43adaSDoug Wyatt case Builtin::ID::BI__builtin_longjmp: 1707fe43adaSDoug Wyatt case Builtin::ID::BIobjc_exception_throw: 1717fe43adaSDoug Wyatt 1727fe43adaSDoug Wyatt // Objective-C runtime. 1737fe43adaSDoug Wyatt case Builtin::ID::BIobjc_msgSend: 1747fe43adaSDoug Wyatt case Builtin::ID::BIobjc_msgSend_fpret: 1757fe43adaSDoug Wyatt case Builtin::ID::BIobjc_msgSend_fp2ret: 1767fe43adaSDoug Wyatt case Builtin::ID::BIobjc_msgSend_stret: 1777fe43adaSDoug Wyatt case Builtin::ID::BIobjc_msgSendSuper: 1787fe43adaSDoug Wyatt case Builtin::ID::BIobjc_getClass: 1797fe43adaSDoug Wyatt case Builtin::ID::BIobjc_getMetaClass: 1807fe43adaSDoug Wyatt case Builtin::ID::BIobjc_enumerationMutation: 1817fe43adaSDoug Wyatt case Builtin::ID::BIobjc_assign_ivar: 1827fe43adaSDoug Wyatt case Builtin::ID::BIobjc_assign_global: 1837fe43adaSDoug Wyatt case Builtin::ID::BIobjc_sync_enter: 1847fe43adaSDoug Wyatt case Builtin::ID::BIobjc_sync_exit: 1857fe43adaSDoug Wyatt case Builtin::ID::BINSLog: 1867fe43adaSDoug Wyatt case Builtin::ID::BINSLogv: 1877fe43adaSDoug Wyatt 1887fe43adaSDoug Wyatt // stdio.h 1897fe43adaSDoug Wyatt case Builtin::ID::BIfread: 1907fe43adaSDoug Wyatt case Builtin::ID::BIfwrite: 1917fe43adaSDoug Wyatt 1927fe43adaSDoug Wyatt // stdio.h: printf family. 1937fe43adaSDoug Wyatt case Builtin::ID::BIprintf: 1947fe43adaSDoug Wyatt case Builtin::ID::BI__builtin_printf: 1957fe43adaSDoug Wyatt case Builtin::ID::BIfprintf: 1967fe43adaSDoug Wyatt case Builtin::ID::BIsnprintf: 1977fe43adaSDoug Wyatt case Builtin::ID::BIsprintf: 1987fe43adaSDoug Wyatt case Builtin::ID::BIvprintf: 1997fe43adaSDoug Wyatt case Builtin::ID::BIvfprintf: 2007fe43adaSDoug Wyatt case Builtin::ID::BIvsnprintf: 2017fe43adaSDoug Wyatt case Builtin::ID::BIvsprintf: 2027fe43adaSDoug Wyatt 2037fe43adaSDoug Wyatt // stdio.h: scanf family. 2047fe43adaSDoug Wyatt case Builtin::ID::BIscanf: 2057fe43adaSDoug Wyatt case Builtin::ID::BIfscanf: 2067fe43adaSDoug Wyatt case Builtin::ID::BIsscanf: 2077fe43adaSDoug Wyatt case Builtin::ID::BIvscanf: 2087fe43adaSDoug Wyatt case Builtin::ID::BIvfscanf: 2097fe43adaSDoug Wyatt case Builtin::ID::BIvsscanf: 2107fe43adaSDoug Wyatt Result.insert(FunctionEffect(FunctionEffect::Kind::Blocking)); 2117fe43adaSDoug Wyatt break; 2127fe43adaSDoug Wyatt } 2137fe43adaSDoug Wyatt 2147fe43adaSDoug Wyatt return Result; 2157fe43adaSDoug Wyatt } 2167fe43adaSDoug Wyatt 2177fe43adaSDoug Wyatt // Transitory, more extended information about a callable, which can be a 2187fe43adaSDoug Wyatt // function, block, or function pointer. 2197fe43adaSDoug Wyatt struct CallableInfo { 2207fe43adaSDoug Wyatt // CDecl holds the function's definition, if any. 2217fe43adaSDoug Wyatt // FunctionDecl if CallableType::Function or Virtual 2227fe43adaSDoug Wyatt // BlockDecl if CallableType::Block 2237fe43adaSDoug Wyatt const Decl *CDecl; 2247fe43adaSDoug Wyatt 2257fe43adaSDoug Wyatt // Remember whether the callable is a function, block, virtual method, 2267fe43adaSDoug Wyatt // or (presumed) function pointer. 2277fe43adaSDoug Wyatt CallableType CType = CallableType::Unknown; 2287fe43adaSDoug Wyatt 2297fe43adaSDoug Wyatt // Remember whether the callable is an operator new or delete function, 2307fe43adaSDoug Wyatt // so that calls to them are reported more meaningfully, as memory 2317fe43adaSDoug Wyatt // allocations. 2327fe43adaSDoug Wyatt SpecialFuncType FuncType = SpecialFuncType::None; 2337fe43adaSDoug Wyatt 2347fe43adaSDoug Wyatt // We inevitably want to know the callable's declared effects, so cache them. 2357fe43adaSDoug Wyatt FunctionEffectKindSet Effects; 2367fe43adaSDoug Wyatt 2377fe43adaSDoug Wyatt CallableInfo(const Decl &CD, SpecialFuncType FT = SpecialFuncType::None) 2387fe43adaSDoug Wyatt : CDecl(&CD), FuncType(FT) { 2397fe43adaSDoug Wyatt FunctionEffectsRef DeclEffects; 2407fe43adaSDoug Wyatt if (auto *FD = dyn_cast<FunctionDecl>(CDecl)) { 2417fe43adaSDoug Wyatt // Use the function's definition, if any. 2427fe43adaSDoug Wyatt if (const FunctionDecl *Def = FD->getDefinition()) 2437fe43adaSDoug Wyatt CDecl = FD = Def; 2447fe43adaSDoug Wyatt CType = CallableType::Function; 2457fe43adaSDoug Wyatt if (auto *Method = dyn_cast<CXXMethodDecl>(FD); 2467fe43adaSDoug Wyatt Method && Method->isVirtual()) 2477fe43adaSDoug Wyatt CType = CallableType::Virtual; 2487fe43adaSDoug Wyatt DeclEffects = FD->getFunctionEffects(); 2497fe43adaSDoug Wyatt } else if (auto *BD = dyn_cast<BlockDecl>(CDecl)) { 2507fe43adaSDoug Wyatt CType = CallableType::Block; 2517fe43adaSDoug Wyatt DeclEffects = BD->getFunctionEffects(); 2527fe43adaSDoug Wyatt } else if (auto *VD = dyn_cast<ValueDecl>(CDecl)) { 2537fe43adaSDoug Wyatt // ValueDecl is function, enum, or variable, so just look at its type. 2547fe43adaSDoug Wyatt DeclEffects = FunctionEffectsRef::get(VD->getType()); 2557fe43adaSDoug Wyatt } 2567fe43adaSDoug Wyatt Effects = FunctionEffectKindSet(DeclEffects); 2577fe43adaSDoug Wyatt } 2587fe43adaSDoug Wyatt 2597fe43adaSDoug Wyatt CallableType type() const { return CType; } 2607fe43adaSDoug Wyatt 2617fe43adaSDoug Wyatt bool isCalledDirectly() const { 2627fe43adaSDoug Wyatt return CType == CallableType::Function || CType == CallableType::Block; 2637fe43adaSDoug Wyatt } 2647fe43adaSDoug Wyatt 2657fe43adaSDoug Wyatt bool isVerifiable() const { 2667fe43adaSDoug Wyatt switch (CType) { 2677fe43adaSDoug Wyatt case CallableType::Unknown: 2687fe43adaSDoug Wyatt case CallableType::Virtual: 2697fe43adaSDoug Wyatt return false; 2707fe43adaSDoug Wyatt case CallableType::Block: 2717fe43adaSDoug Wyatt return true; 2727fe43adaSDoug Wyatt case CallableType::Function: 2737fe43adaSDoug Wyatt return functionIsVerifiable(dyn_cast<FunctionDecl>(CDecl)); 2747fe43adaSDoug Wyatt } 2757fe43adaSDoug Wyatt llvm_unreachable("undefined CallableType"); 2767fe43adaSDoug Wyatt } 2777fe43adaSDoug Wyatt 2787fe43adaSDoug Wyatt /// Generate a name for logging and diagnostics. 2797fe43adaSDoug Wyatt std::string getNameForDiagnostic(Sema &S) const { 2807fe43adaSDoug Wyatt std::string Name; 2817fe43adaSDoug Wyatt llvm::raw_string_ostream OS(Name); 2827fe43adaSDoug Wyatt 2837fe43adaSDoug Wyatt if (auto *FD = dyn_cast<FunctionDecl>(CDecl)) 2847fe43adaSDoug Wyatt FD->getNameForDiagnostic(OS, S.getPrintingPolicy(), 2857fe43adaSDoug Wyatt /*Qualified=*/true); 2867fe43adaSDoug Wyatt else if (auto *BD = dyn_cast<BlockDecl>(CDecl)) 2877fe43adaSDoug Wyatt OS << "(block " << BD->getBlockManglingNumber() << ")"; 2887fe43adaSDoug Wyatt else if (auto *VD = dyn_cast<NamedDecl>(CDecl)) 2897fe43adaSDoug Wyatt VD->printQualifiedName(OS); 2907fe43adaSDoug Wyatt return Name; 2917fe43adaSDoug Wyatt } 2927fe43adaSDoug Wyatt }; 2937fe43adaSDoug Wyatt 2947fe43adaSDoug Wyatt // ---------- 2957fe43adaSDoug Wyatt // Map effects to single Violations, to hold the first (of potentially many) 2967fe43adaSDoug Wyatt // violations pertaining to an effect, per function. 2977fe43adaSDoug Wyatt class EffectToViolationMap { 2987fe43adaSDoug Wyatt // Since we currently only have a tiny number of effects (typically no more 2997fe43adaSDoug Wyatt // than 1), use a SmallVector with an inline capacity of 1. Since it 3007fe43adaSDoug Wyatt // is often empty, use a unique_ptr to the SmallVector. 3017fe43adaSDoug Wyatt // Note that Violation itself contains a FunctionEffect which is the key. 3027fe43adaSDoug Wyatt // FIXME: Is there a way to simplify this using existing data structures? 3037fe43adaSDoug Wyatt using ImplVec = llvm::SmallVector<Violation, 1>; 3047fe43adaSDoug Wyatt std::unique_ptr<ImplVec> Impl; 3057fe43adaSDoug Wyatt 3067fe43adaSDoug Wyatt public: 3077fe43adaSDoug Wyatt // Insert a new Violation if we do not already have one for its effect. 3087fe43adaSDoug Wyatt void maybeInsert(const Violation &Viol) { 3097fe43adaSDoug Wyatt if (Impl == nullptr) 3107fe43adaSDoug Wyatt Impl = std::make_unique<ImplVec>(); 3117fe43adaSDoug Wyatt else if (lookup(Viol.Effect) != nullptr) 3127fe43adaSDoug Wyatt return; 3137fe43adaSDoug Wyatt 3147fe43adaSDoug Wyatt Impl->push_back(Viol); 3157fe43adaSDoug Wyatt } 3167fe43adaSDoug Wyatt 3177fe43adaSDoug Wyatt const Violation *lookup(FunctionEffect Key) { 3187fe43adaSDoug Wyatt if (Impl == nullptr) 3197fe43adaSDoug Wyatt return nullptr; 3207fe43adaSDoug Wyatt 3217fe43adaSDoug Wyatt auto *Iter = llvm::find_if( 3227fe43adaSDoug Wyatt *Impl, [&](const auto &Item) { return Item.Effect == Key; }); 3237fe43adaSDoug Wyatt return Iter != Impl->end() ? &*Iter : nullptr; 3247fe43adaSDoug Wyatt } 3257fe43adaSDoug Wyatt 3267fe43adaSDoug Wyatt size_t size() const { return Impl ? Impl->size() : 0; } 3277fe43adaSDoug Wyatt }; 3287fe43adaSDoug Wyatt 3297fe43adaSDoug Wyatt // ---------- 3307fe43adaSDoug Wyatt // State pertaining to a function whose AST is walked and whose effect analysis 3317fe43adaSDoug Wyatt // is dependent on a subsequent analysis of other functions. 3327fe43adaSDoug Wyatt class PendingFunctionAnalysis { 3337fe43adaSDoug Wyatt friend class CompleteFunctionAnalysis; 3347fe43adaSDoug Wyatt 3357fe43adaSDoug Wyatt public: 3367fe43adaSDoug Wyatt struct DirectCall { 3377fe43adaSDoug Wyatt const Decl *Callee; 3387fe43adaSDoug Wyatt SourceLocation CallLoc; 3397fe43adaSDoug Wyatt // Not all recursive calls are detected, just enough 3407fe43adaSDoug Wyatt // to break cycles. 3417fe43adaSDoug Wyatt bool Recursed = false; 3427fe43adaSDoug Wyatt ViolationSite VSite; 3437fe43adaSDoug Wyatt 3447fe43adaSDoug Wyatt DirectCall(const Decl *D, SourceLocation CallLoc, ViolationSite VSite) 3457fe43adaSDoug Wyatt : Callee(D), CallLoc(CallLoc), VSite(VSite) {} 3467fe43adaSDoug Wyatt }; 3477fe43adaSDoug Wyatt 3487fe43adaSDoug Wyatt // We always have two disjoint sets of effects to verify: 3497fe43adaSDoug Wyatt // 1. Effects declared explicitly by this function. 3507fe43adaSDoug Wyatt // 2. All other inferrable effects needing verification. 3517fe43adaSDoug Wyatt FunctionEffectKindSet DeclaredVerifiableEffects; 3527fe43adaSDoug Wyatt FunctionEffectKindSet EffectsToInfer; 3537fe43adaSDoug Wyatt 3547fe43adaSDoug Wyatt private: 3557fe43adaSDoug Wyatt // Violations pertaining to the function's explicit effects. 3567fe43adaSDoug Wyatt SmallVector<Violation, 0> ViolationsForExplicitEffects; 3577fe43adaSDoug Wyatt 3587fe43adaSDoug Wyatt // Violations pertaining to other, non-explicit, inferrable effects. 3597fe43adaSDoug Wyatt EffectToViolationMap InferrableEffectToFirstViolation; 3607fe43adaSDoug Wyatt 3617fe43adaSDoug Wyatt // These unverified direct calls are what keeps the analysis "pending", 3627fe43adaSDoug Wyatt // until the callees can be verified. 3637fe43adaSDoug Wyatt SmallVector<DirectCall, 0> UnverifiedDirectCalls; 3647fe43adaSDoug Wyatt 3657fe43adaSDoug Wyatt public: 3667fe43adaSDoug Wyatt PendingFunctionAnalysis(Sema &S, const CallableInfo &CInfo, 3677fe43adaSDoug Wyatt FunctionEffectKindSet AllInferrableEffectsToVerify) 3687fe43adaSDoug Wyatt : DeclaredVerifiableEffects(CInfo.Effects) { 3697fe43adaSDoug Wyatt // Check for effects we are not allowed to infer. 3707fe43adaSDoug Wyatt FunctionEffectKindSet InferrableEffects; 3717fe43adaSDoug Wyatt 3727fe43adaSDoug Wyatt for (FunctionEffect effect : AllInferrableEffectsToVerify) { 3737fe43adaSDoug Wyatt std::optional<FunctionEffect> ProblemCalleeEffect = 3747fe43adaSDoug Wyatt effect.effectProhibitingInference(*CInfo.CDecl, CInfo.Effects); 3757fe43adaSDoug Wyatt if (!ProblemCalleeEffect) 3767fe43adaSDoug Wyatt InferrableEffects.insert(effect); 3777fe43adaSDoug Wyatt else { 3787fe43adaSDoug Wyatt // Add a Violation for this effect if a caller were to 3797fe43adaSDoug Wyatt // try to infer it. 3807fe43adaSDoug Wyatt InferrableEffectToFirstViolation.maybeInsert(Violation( 3817fe43adaSDoug Wyatt effect, ViolationID::DeclDisallowsInference, ViolationSite{}, 3827fe43adaSDoug Wyatt CInfo.CDecl->getLocation(), nullptr, ProblemCalleeEffect)); 3837fe43adaSDoug Wyatt } 3847fe43adaSDoug Wyatt } 3857fe43adaSDoug Wyatt // InferrableEffects is now the set of inferrable effects which are not 3867fe43adaSDoug Wyatt // prohibited. 3877fe43adaSDoug Wyatt EffectsToInfer = FunctionEffectKindSet::difference( 3887fe43adaSDoug Wyatt InferrableEffects, DeclaredVerifiableEffects); 3897fe43adaSDoug Wyatt } 3907fe43adaSDoug Wyatt 3917fe43adaSDoug Wyatt // Hide the way that Violations for explicitly required effects vs. inferred 3927fe43adaSDoug Wyatt // ones are handled differently. 3937fe43adaSDoug Wyatt void checkAddViolation(bool Inferring, const Violation &NewViol) { 3947fe43adaSDoug Wyatt if (!Inferring) 3957fe43adaSDoug Wyatt ViolationsForExplicitEffects.push_back(NewViol); 3967fe43adaSDoug Wyatt else 3977fe43adaSDoug Wyatt InferrableEffectToFirstViolation.maybeInsert(NewViol); 3987fe43adaSDoug Wyatt } 3997fe43adaSDoug Wyatt 4007fe43adaSDoug Wyatt void addUnverifiedDirectCall(const Decl *D, SourceLocation CallLoc, 4017fe43adaSDoug Wyatt ViolationSite VSite) { 4027fe43adaSDoug Wyatt UnverifiedDirectCalls.emplace_back(D, CallLoc, VSite); 4037fe43adaSDoug Wyatt } 4047fe43adaSDoug Wyatt 4057fe43adaSDoug Wyatt // Analysis is complete when there are no unverified direct calls. 4067fe43adaSDoug Wyatt bool isComplete() const { return UnverifiedDirectCalls.empty(); } 4077fe43adaSDoug Wyatt 4087fe43adaSDoug Wyatt const Violation *violationForInferrableEffect(FunctionEffect effect) { 4097fe43adaSDoug Wyatt return InferrableEffectToFirstViolation.lookup(effect); 4107fe43adaSDoug Wyatt } 4117fe43adaSDoug Wyatt 4127fe43adaSDoug Wyatt // Mutable because caller may need to set a DirectCall's Recursing flag. 4137fe43adaSDoug Wyatt MutableArrayRef<DirectCall> unverifiedCalls() { 4147fe43adaSDoug Wyatt assert(!isComplete()); 4157fe43adaSDoug Wyatt return UnverifiedDirectCalls; 4167fe43adaSDoug Wyatt } 4177fe43adaSDoug Wyatt 4187fe43adaSDoug Wyatt ArrayRef<Violation> getSortedViolationsForExplicitEffects(SourceManager &SM) { 4197fe43adaSDoug Wyatt if (!ViolationsForExplicitEffects.empty()) 4207fe43adaSDoug Wyatt llvm::sort(ViolationsForExplicitEffects, 4217fe43adaSDoug Wyatt [&SM](const Violation &LHS, const Violation &RHS) { 4227fe43adaSDoug Wyatt return SM.isBeforeInTranslationUnit(LHS.Loc, RHS.Loc); 4237fe43adaSDoug Wyatt }); 4247fe43adaSDoug Wyatt return ViolationsForExplicitEffects; 4257fe43adaSDoug Wyatt } 4267fe43adaSDoug Wyatt 4277fe43adaSDoug Wyatt void dump(Sema &SemaRef, llvm::raw_ostream &OS) const { 4287fe43adaSDoug Wyatt OS << "Pending: Declared "; 4297fe43adaSDoug Wyatt DeclaredVerifiableEffects.dump(OS); 4307fe43adaSDoug Wyatt OS << ", " << ViolationsForExplicitEffects.size() << " violations; "; 4317fe43adaSDoug Wyatt OS << " Infer "; 4327fe43adaSDoug Wyatt EffectsToInfer.dump(OS); 4337fe43adaSDoug Wyatt OS << ", " << InferrableEffectToFirstViolation.size() << " violations"; 4347fe43adaSDoug Wyatt if (!UnverifiedDirectCalls.empty()) { 4357fe43adaSDoug Wyatt OS << "; Calls: "; 4367fe43adaSDoug Wyatt for (const DirectCall &Call : UnverifiedDirectCalls) { 4377fe43adaSDoug Wyatt CallableInfo CI(*Call.Callee); 4387fe43adaSDoug Wyatt OS << " " << CI.getNameForDiagnostic(SemaRef); 4397fe43adaSDoug Wyatt } 4407fe43adaSDoug Wyatt } 4417fe43adaSDoug Wyatt OS << "\n"; 4427fe43adaSDoug Wyatt } 4437fe43adaSDoug Wyatt }; 4447fe43adaSDoug Wyatt 4457fe43adaSDoug Wyatt // ---------- 4467fe43adaSDoug Wyatt class CompleteFunctionAnalysis { 4477fe43adaSDoug Wyatt // Current size: 2 pointers 4487fe43adaSDoug Wyatt public: 4497fe43adaSDoug Wyatt // Has effects which are both the declared ones -- not to be inferred -- plus 4507fe43adaSDoug Wyatt // ones which have been successfully inferred. These are all considered 4517fe43adaSDoug Wyatt // "verified" for the purposes of callers; any issue with verifying declared 4527fe43adaSDoug Wyatt // effects has already been reported and is not the problem of any caller. 4537fe43adaSDoug Wyatt FunctionEffectKindSet VerifiedEffects; 4547fe43adaSDoug Wyatt 4557fe43adaSDoug Wyatt private: 4567fe43adaSDoug Wyatt // This is used to generate notes about failed inference. 4577fe43adaSDoug Wyatt EffectToViolationMap InferrableEffectToFirstViolation; 4587fe43adaSDoug Wyatt 4597fe43adaSDoug Wyatt public: 4607fe43adaSDoug Wyatt // The incoming Pending analysis is consumed (member(s) are moved-from). 4617fe43adaSDoug Wyatt CompleteFunctionAnalysis(ASTContext &Ctx, PendingFunctionAnalysis &&Pending, 4627fe43adaSDoug Wyatt FunctionEffectKindSet DeclaredEffects, 4637fe43adaSDoug Wyatt FunctionEffectKindSet AllInferrableEffectsToVerify) 4647fe43adaSDoug Wyatt : VerifiedEffects(DeclaredEffects) { 4657fe43adaSDoug Wyatt for (FunctionEffect effect : AllInferrableEffectsToVerify) 4667fe43adaSDoug Wyatt if (Pending.violationForInferrableEffect(effect) == nullptr) 4677fe43adaSDoug Wyatt VerifiedEffects.insert(effect); 4687fe43adaSDoug Wyatt 4697fe43adaSDoug Wyatt InferrableEffectToFirstViolation = 4707fe43adaSDoug Wyatt std::move(Pending.InferrableEffectToFirstViolation); 4717fe43adaSDoug Wyatt } 4727fe43adaSDoug Wyatt 4737fe43adaSDoug Wyatt const Violation *firstViolationForEffect(FunctionEffect Effect) { 4747fe43adaSDoug Wyatt return InferrableEffectToFirstViolation.lookup(Effect); 4757fe43adaSDoug Wyatt } 4767fe43adaSDoug Wyatt 4777fe43adaSDoug Wyatt void dump(llvm::raw_ostream &OS) const { 4787fe43adaSDoug Wyatt OS << "Complete: Verified "; 4797fe43adaSDoug Wyatt VerifiedEffects.dump(OS); 4807fe43adaSDoug Wyatt OS << "; Infer "; 4817fe43adaSDoug Wyatt OS << InferrableEffectToFirstViolation.size() << " violations\n"; 4827fe43adaSDoug Wyatt } 4837fe43adaSDoug Wyatt }; 4847fe43adaSDoug Wyatt 4857fe43adaSDoug Wyatt // ========== 4867fe43adaSDoug Wyatt class Analyzer { 4877fe43adaSDoug Wyatt Sema &S; 4887fe43adaSDoug Wyatt 4897fe43adaSDoug Wyatt // Subset of Sema.AllEffectsToVerify 4907fe43adaSDoug Wyatt FunctionEffectKindSet AllInferrableEffectsToVerify; 4917fe43adaSDoug Wyatt 4927fe43adaSDoug Wyatt using FuncAnalysisPtr = 4937fe43adaSDoug Wyatt llvm::PointerUnion<PendingFunctionAnalysis *, CompleteFunctionAnalysis *>; 4947fe43adaSDoug Wyatt 4957fe43adaSDoug Wyatt // Map all Decls analyzed to FuncAnalysisPtr. Pending state is larger 4967fe43adaSDoug Wyatt // than complete state, so use different objects to represent them. 4977fe43adaSDoug Wyatt // The state pointers are owned by the container. 4987fe43adaSDoug Wyatt class AnalysisMap : llvm::DenseMap<const Decl *, FuncAnalysisPtr> { 4997fe43adaSDoug Wyatt using Base = llvm::DenseMap<const Decl *, FuncAnalysisPtr>; 5007fe43adaSDoug Wyatt 5017fe43adaSDoug Wyatt public: 5027fe43adaSDoug Wyatt ~AnalysisMap(); 5037fe43adaSDoug Wyatt 5047fe43adaSDoug Wyatt // Use non-public inheritance in order to maintain the invariant 5057fe43adaSDoug Wyatt // that lookups and insertions are via the canonical Decls. 5067fe43adaSDoug Wyatt 5077fe43adaSDoug Wyatt FuncAnalysisPtr lookup(const Decl *Key) const { 5087fe43adaSDoug Wyatt return Base::lookup(Key->getCanonicalDecl()); 5097fe43adaSDoug Wyatt } 5107fe43adaSDoug Wyatt 5117fe43adaSDoug Wyatt FuncAnalysisPtr &operator[](const Decl *Key) { 5127fe43adaSDoug Wyatt return Base::operator[](Key->getCanonicalDecl()); 5137fe43adaSDoug Wyatt } 5147fe43adaSDoug Wyatt 5157fe43adaSDoug Wyatt /// Shortcut for the case where we only care about completed analysis. 5167fe43adaSDoug Wyatt CompleteFunctionAnalysis *completedAnalysisForDecl(const Decl *D) const { 5177fe43adaSDoug Wyatt if (FuncAnalysisPtr AP = lookup(D); 5187fe43adaSDoug Wyatt isa_and_nonnull<CompleteFunctionAnalysis *>(AP)) 5191e3e199eSKazu Hirata return cast<CompleteFunctionAnalysis *>(AP); 5207fe43adaSDoug Wyatt return nullptr; 5217fe43adaSDoug Wyatt } 5227fe43adaSDoug Wyatt 5237fe43adaSDoug Wyatt void dump(Sema &SemaRef, llvm::raw_ostream &OS) { 5247fe43adaSDoug Wyatt OS << "\nAnalysisMap:\n"; 5257fe43adaSDoug Wyatt for (const auto &item : *this) { 5267fe43adaSDoug Wyatt CallableInfo CI(*item.first); 5277fe43adaSDoug Wyatt const auto AP = item.second; 5287fe43adaSDoug Wyatt OS << item.first << " " << CI.getNameForDiagnostic(SemaRef) << " : "; 5297fe43adaSDoug Wyatt if (AP.isNull()) { 5307fe43adaSDoug Wyatt OS << "null\n"; 5311e3e199eSKazu Hirata } else if (auto *CFA = dyn_cast<CompleteFunctionAnalysis *>(AP)) { 5327fe43adaSDoug Wyatt OS << CFA << " "; 5337fe43adaSDoug Wyatt CFA->dump(OS); 5341e3e199eSKazu Hirata } else if (auto *PFA = dyn_cast<PendingFunctionAnalysis *>(AP)) { 5357fe43adaSDoug Wyatt OS << PFA << " "; 5367fe43adaSDoug Wyatt PFA->dump(SemaRef, OS); 5377fe43adaSDoug Wyatt } else 5387fe43adaSDoug Wyatt llvm_unreachable("never"); 5397fe43adaSDoug Wyatt } 5407fe43adaSDoug Wyatt OS << "---\n"; 5417fe43adaSDoug Wyatt } 5427fe43adaSDoug Wyatt }; 5437fe43adaSDoug Wyatt AnalysisMap DeclAnalysis; 5447fe43adaSDoug Wyatt 5457fe43adaSDoug Wyatt public: 5467fe43adaSDoug Wyatt Analyzer(Sema &S) : S(S) {} 5477fe43adaSDoug Wyatt 5487fe43adaSDoug Wyatt void run(const TranslationUnitDecl &TU) { 5497fe43adaSDoug Wyatt // Gather all of the effects to be verified to see what operations need to 5507fe43adaSDoug Wyatt // be checked, and to see which ones are inferrable. 5517fe43adaSDoug Wyatt for (FunctionEffect Effect : S.AllEffectsToVerify) { 5527fe43adaSDoug Wyatt const FunctionEffect::Flags Flags = Effect.flags(); 5537fe43adaSDoug Wyatt if (Flags & FunctionEffect::FE_InferrableOnCallees) 5547fe43adaSDoug Wyatt AllInferrableEffectsToVerify.insert(Effect); 5557fe43adaSDoug Wyatt } 5567fe43adaSDoug Wyatt LLVM_DEBUG(llvm::dbgs() << "AllInferrableEffectsToVerify: "; 5577fe43adaSDoug Wyatt AllInferrableEffectsToVerify.dump(llvm::dbgs()); 5587fe43adaSDoug Wyatt llvm::dbgs() << "\n";); 5597fe43adaSDoug Wyatt 5607fe43adaSDoug Wyatt // We can use DeclsWithEffectsToVerify as a stack for a 5617fe43adaSDoug Wyatt // depth-first traversal; there's no need for a second container. But first, 5627fe43adaSDoug Wyatt // reverse it, so when working from the end, Decls are verified in the order 5637fe43adaSDoug Wyatt // they are declared. 5647fe43adaSDoug Wyatt SmallVector<const Decl *> &VerificationQueue = S.DeclsWithEffectsToVerify; 5657fe43adaSDoug Wyatt std::reverse(VerificationQueue.begin(), VerificationQueue.end()); 5667fe43adaSDoug Wyatt 5677fe43adaSDoug Wyatt while (!VerificationQueue.empty()) { 5687fe43adaSDoug Wyatt const Decl *D = VerificationQueue.back(); 5697fe43adaSDoug Wyatt if (FuncAnalysisPtr AP = DeclAnalysis.lookup(D)) { 570*286f8423SKazu Hirata if (auto *Pending = dyn_cast<PendingFunctionAnalysis *>(AP)) { 5717fe43adaSDoug Wyatt // All children have been traversed; finish analysis. 5727fe43adaSDoug Wyatt finishPendingAnalysis(D, Pending); 5737fe43adaSDoug Wyatt } 5747fe43adaSDoug Wyatt VerificationQueue.pop_back(); 5757fe43adaSDoug Wyatt continue; 5767fe43adaSDoug Wyatt } 5777fe43adaSDoug Wyatt 5787fe43adaSDoug Wyatt // Not previously visited; begin a new analysis for this Decl. 5797fe43adaSDoug Wyatt PendingFunctionAnalysis *Pending = verifyDecl(D); 5807fe43adaSDoug Wyatt if (Pending == nullptr) { 5817fe43adaSDoug Wyatt // Completed now. 5827fe43adaSDoug Wyatt VerificationQueue.pop_back(); 5837fe43adaSDoug Wyatt continue; 5847fe43adaSDoug Wyatt } 5857fe43adaSDoug Wyatt 5867fe43adaSDoug Wyatt // Analysis remains pending because there are direct callees to be 5877fe43adaSDoug Wyatt // verified first. Push them onto the queue. 5887fe43adaSDoug Wyatt for (PendingFunctionAnalysis::DirectCall &Call : 5897fe43adaSDoug Wyatt Pending->unverifiedCalls()) { 5907fe43adaSDoug Wyatt FuncAnalysisPtr AP = DeclAnalysis.lookup(Call.Callee); 5917fe43adaSDoug Wyatt if (AP.isNull()) { 5927fe43adaSDoug Wyatt VerificationQueue.push_back(Call.Callee); 5937fe43adaSDoug Wyatt continue; 5947fe43adaSDoug Wyatt } 5957fe43adaSDoug Wyatt 5967fe43adaSDoug Wyatt // This indicates recursion (not necessarily direct). For the 5977fe43adaSDoug Wyatt // purposes of effect analysis, we can just ignore it since 5987fe43adaSDoug Wyatt // no effects forbid recursion. 5997fe43adaSDoug Wyatt assert(isa<PendingFunctionAnalysis *>(AP)); 6007fe43adaSDoug Wyatt Call.Recursed = true; 6017fe43adaSDoug Wyatt } 6027fe43adaSDoug Wyatt } 6037fe43adaSDoug Wyatt } 6047fe43adaSDoug Wyatt 6057fe43adaSDoug Wyatt private: 6067fe43adaSDoug Wyatt // Verify a single Decl. Return the pending structure if that was the result, 6077fe43adaSDoug Wyatt // else null. This method must not recurse. 6087fe43adaSDoug Wyatt PendingFunctionAnalysis *verifyDecl(const Decl *D) { 6097fe43adaSDoug Wyatt CallableInfo CInfo(*D); 6107fe43adaSDoug Wyatt bool isExternC = false; 6117fe43adaSDoug Wyatt 6127fe43adaSDoug Wyatt if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) 6137fe43adaSDoug Wyatt isExternC = FD->getCanonicalDecl()->isExternCContext(); 6147fe43adaSDoug Wyatt 6157fe43adaSDoug Wyatt // For C++, with non-extern "C" linkage only - if any of the Decl's declared 6167fe43adaSDoug Wyatt // effects forbid throwing (e.g. nonblocking) then the function should also 6177fe43adaSDoug Wyatt // be declared noexcept. 6187fe43adaSDoug Wyatt if (S.getLangOpts().CPlusPlus && !isExternC) { 6197fe43adaSDoug Wyatt for (FunctionEffect Effect : CInfo.Effects) { 6207fe43adaSDoug Wyatt if (!(Effect.flags() & FunctionEffect::FE_ExcludeThrow)) 6217fe43adaSDoug Wyatt continue; 6227fe43adaSDoug Wyatt 6237fe43adaSDoug Wyatt bool IsNoexcept = false; 6247fe43adaSDoug Wyatt if (auto *FD = D->getAsFunction()) { 6257fe43adaSDoug Wyatt IsNoexcept = isNoexcept(FD); 6267fe43adaSDoug Wyatt } else if (auto *BD = dyn_cast<BlockDecl>(D)) { 6277fe43adaSDoug Wyatt if (auto *TSI = BD->getSignatureAsWritten()) { 62843892205Ssmanna12 auto *FPT = TSI->getType()->castAs<FunctionProtoType>(); 6297fe43adaSDoug Wyatt IsNoexcept = FPT->isNothrow() || BD->hasAttr<NoThrowAttr>(); 6307fe43adaSDoug Wyatt } 6317fe43adaSDoug Wyatt } 6327fe43adaSDoug Wyatt if (!IsNoexcept) 6337fe43adaSDoug Wyatt S.Diag(D->getBeginLoc(), diag::warn_perf_constraint_implies_noexcept) 6347fe43adaSDoug Wyatt << GetCallableDeclKind(D, nullptr) << Effect.name(); 6357fe43adaSDoug Wyatt break; 6367fe43adaSDoug Wyatt } 6377fe43adaSDoug Wyatt } 6387fe43adaSDoug Wyatt 6397fe43adaSDoug Wyatt // Build a PendingFunctionAnalysis on the stack. If it turns out to be 6407fe43adaSDoug Wyatt // complete, we'll have avoided a heap allocation; if it's incomplete, it's 6417fe43adaSDoug Wyatt // a fairly trivial move to a heap-allocated object. 6427fe43adaSDoug Wyatt PendingFunctionAnalysis FAnalysis(S, CInfo, AllInferrableEffectsToVerify); 6437fe43adaSDoug Wyatt 6447fe43adaSDoug Wyatt LLVM_DEBUG(llvm::dbgs() 6457fe43adaSDoug Wyatt << "\nVerifying " << CInfo.getNameForDiagnostic(S) << " "; 6467fe43adaSDoug Wyatt FAnalysis.dump(S, llvm::dbgs());); 6477fe43adaSDoug Wyatt 6487fe43adaSDoug Wyatt FunctionBodyASTVisitor Visitor(*this, FAnalysis, CInfo); 6497fe43adaSDoug Wyatt 6507fe43adaSDoug Wyatt Visitor.run(); 6517fe43adaSDoug Wyatt if (FAnalysis.isComplete()) { 6527fe43adaSDoug Wyatt completeAnalysis(CInfo, std::move(FAnalysis)); 6537fe43adaSDoug Wyatt return nullptr; 6547fe43adaSDoug Wyatt } 6557fe43adaSDoug Wyatt // Move the pending analysis to the heap and save it in the map. 6567fe43adaSDoug Wyatt PendingFunctionAnalysis *PendingPtr = 6577fe43adaSDoug Wyatt new PendingFunctionAnalysis(std::move(FAnalysis)); 6587fe43adaSDoug Wyatt DeclAnalysis[D] = PendingPtr; 6597fe43adaSDoug Wyatt LLVM_DEBUG(llvm::dbgs() << "inserted pending " << PendingPtr << "\n"; 6607fe43adaSDoug Wyatt DeclAnalysis.dump(S, llvm::dbgs());); 6617fe43adaSDoug Wyatt return PendingPtr; 6627fe43adaSDoug Wyatt } 6637fe43adaSDoug Wyatt 6647fe43adaSDoug Wyatt // Consume PendingFunctionAnalysis, create with it a CompleteFunctionAnalysis, 6657fe43adaSDoug Wyatt // inserted in the container. 6667fe43adaSDoug Wyatt void completeAnalysis(const CallableInfo &CInfo, 6677fe43adaSDoug Wyatt PendingFunctionAnalysis &&Pending) { 6687fe43adaSDoug Wyatt if (ArrayRef<Violation> Viols = 6697fe43adaSDoug Wyatt Pending.getSortedViolationsForExplicitEffects(S.getSourceManager()); 6707fe43adaSDoug Wyatt !Viols.empty()) 6717fe43adaSDoug Wyatt emitDiagnostics(Viols, CInfo); 6727fe43adaSDoug Wyatt 6737fe43adaSDoug Wyatt CompleteFunctionAnalysis *CompletePtr = new CompleteFunctionAnalysis( 6747fe43adaSDoug Wyatt S.getASTContext(), std::move(Pending), CInfo.Effects, 6757fe43adaSDoug Wyatt AllInferrableEffectsToVerify); 6767fe43adaSDoug Wyatt DeclAnalysis[CInfo.CDecl] = CompletePtr; 6777fe43adaSDoug Wyatt LLVM_DEBUG(llvm::dbgs() << "inserted complete " << CompletePtr << "\n"; 6787fe43adaSDoug Wyatt DeclAnalysis.dump(S, llvm::dbgs());); 6797fe43adaSDoug Wyatt } 6807fe43adaSDoug Wyatt 6817fe43adaSDoug Wyatt // Called after all direct calls requiring inference have been found -- or 6827fe43adaSDoug Wyatt // not. Repeats calls to FunctionBodyASTVisitor::followCall() but without 6837fe43adaSDoug Wyatt // the possibility of inference. Deletes Pending. 6847fe43adaSDoug Wyatt void finishPendingAnalysis(const Decl *D, PendingFunctionAnalysis *Pending) { 6857fe43adaSDoug Wyatt CallableInfo Caller(*D); 6867fe43adaSDoug Wyatt LLVM_DEBUG(llvm::dbgs() << "finishPendingAnalysis for " 6877fe43adaSDoug Wyatt << Caller.getNameForDiagnostic(S) << " : "; 6887fe43adaSDoug Wyatt Pending->dump(S, llvm::dbgs()); llvm::dbgs() << "\n";); 6897fe43adaSDoug Wyatt for (const PendingFunctionAnalysis::DirectCall &Call : 6907fe43adaSDoug Wyatt Pending->unverifiedCalls()) { 6917fe43adaSDoug Wyatt if (Call.Recursed) 6927fe43adaSDoug Wyatt continue; 6937fe43adaSDoug Wyatt 6947fe43adaSDoug Wyatt CallableInfo Callee(*Call.Callee); 6957fe43adaSDoug Wyatt followCall(Caller, *Pending, Callee, Call.CallLoc, 6967fe43adaSDoug Wyatt /*AssertNoFurtherInference=*/true, Call.VSite); 6977fe43adaSDoug Wyatt } 6987fe43adaSDoug Wyatt completeAnalysis(Caller, std::move(*Pending)); 6997fe43adaSDoug Wyatt delete Pending; 7007fe43adaSDoug Wyatt } 7017fe43adaSDoug Wyatt 7027fe43adaSDoug Wyatt // Here we have a call to a Decl, either explicitly via a CallExpr or some 7037fe43adaSDoug Wyatt // other AST construct. PFA pertains to the caller. 7047fe43adaSDoug Wyatt void followCall(const CallableInfo &Caller, PendingFunctionAnalysis &PFA, 7057fe43adaSDoug Wyatt const CallableInfo &Callee, SourceLocation CallLoc, 7067fe43adaSDoug Wyatt bool AssertNoFurtherInference, ViolationSite VSite) { 7077fe43adaSDoug Wyatt const bool DirectCall = Callee.isCalledDirectly(); 7087fe43adaSDoug Wyatt 7097fe43adaSDoug Wyatt // Initially, the declared effects; inferred effects will be added. 7107fe43adaSDoug Wyatt FunctionEffectKindSet CalleeEffects = Callee.Effects; 7117fe43adaSDoug Wyatt 7127fe43adaSDoug Wyatt bool IsInferencePossible = DirectCall; 7137fe43adaSDoug Wyatt 7147fe43adaSDoug Wyatt if (DirectCall) 7157fe43adaSDoug Wyatt if (CompleteFunctionAnalysis *CFA = 7167fe43adaSDoug Wyatt DeclAnalysis.completedAnalysisForDecl(Callee.CDecl)) { 7177fe43adaSDoug Wyatt // Combine declared effects with those which may have been inferred. 7187fe43adaSDoug Wyatt CalleeEffects.insert(CFA->VerifiedEffects); 7197fe43adaSDoug Wyatt IsInferencePossible = false; // We've already traversed it. 7207fe43adaSDoug Wyatt } 7217fe43adaSDoug Wyatt 7227fe43adaSDoug Wyatt if (AssertNoFurtherInference) { 7237fe43adaSDoug Wyatt assert(!IsInferencePossible); 7247fe43adaSDoug Wyatt } 7257fe43adaSDoug Wyatt 7267fe43adaSDoug Wyatt if (!Callee.isVerifiable()) 7277fe43adaSDoug Wyatt IsInferencePossible = false; 7287fe43adaSDoug Wyatt 7297fe43adaSDoug Wyatt LLVM_DEBUG(llvm::dbgs() 7307fe43adaSDoug Wyatt << "followCall from " << Caller.getNameForDiagnostic(S) 7317fe43adaSDoug Wyatt << " to " << Callee.getNameForDiagnostic(S) 7327fe43adaSDoug Wyatt << "; verifiable: " << Callee.isVerifiable() << "; callee "; 7337fe43adaSDoug Wyatt CalleeEffects.dump(llvm::dbgs()); llvm::dbgs() << "\n"; 7347fe43adaSDoug Wyatt llvm::dbgs() << " callee " << Callee.CDecl << " canonical " 7357fe43adaSDoug Wyatt << Callee.CDecl->getCanonicalDecl() << "\n";); 7367fe43adaSDoug Wyatt 7377fe43adaSDoug Wyatt auto Check1Effect = [&](FunctionEffect Effect, bool Inferring) { 7387fe43adaSDoug Wyatt if (!Effect.shouldDiagnoseFunctionCall(DirectCall, CalleeEffects)) 7397fe43adaSDoug Wyatt return; 7407fe43adaSDoug Wyatt 7417fe43adaSDoug Wyatt // If inference is not allowed, or the target is indirect (virtual 7427fe43adaSDoug Wyatt // method/function ptr?), generate a Violation now. 7437fe43adaSDoug Wyatt if (!IsInferencePossible || 7447fe43adaSDoug Wyatt !(Effect.flags() & FunctionEffect::FE_InferrableOnCallees)) { 7457fe43adaSDoug Wyatt if (Callee.FuncType == SpecialFuncType::None) 7467fe43adaSDoug Wyatt PFA.checkAddViolation(Inferring, 7477fe43adaSDoug Wyatt {Effect, ViolationID::CallsDeclWithoutEffect, 7487fe43adaSDoug Wyatt VSite, CallLoc, Callee.CDecl}); 7497fe43adaSDoug Wyatt else 7507fe43adaSDoug Wyatt PFA.checkAddViolation( 7517fe43adaSDoug Wyatt Inferring, 7527fe43adaSDoug Wyatt {Effect, ViolationID::AllocatesMemory, VSite, CallLoc}); 7537fe43adaSDoug Wyatt } else { 7547fe43adaSDoug Wyatt // Inference is allowed and necessary; defer it. 7557fe43adaSDoug Wyatt PFA.addUnverifiedDirectCall(Callee.CDecl, CallLoc, VSite); 7567fe43adaSDoug Wyatt } 7577fe43adaSDoug Wyatt }; 7587fe43adaSDoug Wyatt 7597fe43adaSDoug Wyatt for (FunctionEffect Effect : PFA.DeclaredVerifiableEffects) 7607fe43adaSDoug Wyatt Check1Effect(Effect, false); 7617fe43adaSDoug Wyatt 7627fe43adaSDoug Wyatt for (FunctionEffect Effect : PFA.EffectsToInfer) 7637fe43adaSDoug Wyatt Check1Effect(Effect, true); 7647fe43adaSDoug Wyatt } 7657fe43adaSDoug Wyatt 7667fe43adaSDoug Wyatt // Describe a callable Decl for a diagnostic. 7677fe43adaSDoug Wyatt // (Not an enum class because the value is always converted to an integer for 7687fe43adaSDoug Wyatt // use in a diagnostic.) 7697fe43adaSDoug Wyatt enum CallableDeclKind { 7707fe43adaSDoug Wyatt CDK_Function, 7717fe43adaSDoug Wyatt CDK_Constructor, 7727fe43adaSDoug Wyatt CDK_Destructor, 7737fe43adaSDoug Wyatt CDK_Lambda, 7747fe43adaSDoug Wyatt CDK_Block, 7757fe43adaSDoug Wyatt CDK_MemberInitializer, 7767fe43adaSDoug Wyatt }; 7777fe43adaSDoug Wyatt 7787fe43adaSDoug Wyatt // Describe a call site or target using an enum mapping to a %select{} 7797fe43adaSDoug Wyatt // in a diagnostic, e.g. warn_func_effect_violation, 7807fe43adaSDoug Wyatt // warn_perf_constraint_implies_noexcept, and others. 7817fe43adaSDoug Wyatt static CallableDeclKind GetCallableDeclKind(const Decl *D, 7827fe43adaSDoug Wyatt const Violation *V) { 7837fe43adaSDoug Wyatt if (V != nullptr && 7847fe43adaSDoug Wyatt V->Site.kind() == ViolationSite::Kind::MemberInitializer) 7857fe43adaSDoug Wyatt return CDK_MemberInitializer; 7867fe43adaSDoug Wyatt if (isa<BlockDecl>(D)) 7877fe43adaSDoug Wyatt return CDK_Block; 7887fe43adaSDoug Wyatt if (auto *Method = dyn_cast<CXXMethodDecl>(D)) { 7897fe43adaSDoug Wyatt if (isa<CXXConstructorDecl>(D)) 7907fe43adaSDoug Wyatt return CDK_Constructor; 7917fe43adaSDoug Wyatt if (isa<CXXDestructorDecl>(D)) 7927fe43adaSDoug Wyatt return CDK_Destructor; 7937fe43adaSDoug Wyatt const CXXRecordDecl *Rec = Method->getParent(); 7947fe43adaSDoug Wyatt if (Rec->isLambda()) 7957fe43adaSDoug Wyatt return CDK_Lambda; 7967fe43adaSDoug Wyatt } 7977fe43adaSDoug Wyatt return CDK_Function; 7987fe43adaSDoug Wyatt }; 7997fe43adaSDoug Wyatt 8007fe43adaSDoug Wyatt // Should only be called when function's analysis is determined to be 8017fe43adaSDoug Wyatt // complete. 8027fe43adaSDoug Wyatt void emitDiagnostics(ArrayRef<Violation> Viols, const CallableInfo &CInfo) { 8037fe43adaSDoug Wyatt if (Viols.empty()) 8047fe43adaSDoug Wyatt return; 8057fe43adaSDoug Wyatt 8067fe43adaSDoug Wyatt auto MaybeAddTemplateNote = [&](const Decl *D) { 8077fe43adaSDoug Wyatt if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { 80839bdf7a9SDoug Wyatt while (FD != nullptr && FD->isTemplateInstantiation() && 80939bdf7a9SDoug Wyatt FD->getPointOfInstantiation().isValid()) { 8107fe43adaSDoug Wyatt S.Diag(FD->getPointOfInstantiation(), 8117fe43adaSDoug Wyatt diag::note_func_effect_from_template); 8127fe43adaSDoug Wyatt FD = FD->getTemplateInstantiationPattern(); 8137fe43adaSDoug Wyatt } 8147fe43adaSDoug Wyatt } 8157fe43adaSDoug Wyatt }; 8167fe43adaSDoug Wyatt 8177fe43adaSDoug Wyatt // For note_func_effect_call_indirect. 8187fe43adaSDoug Wyatt enum { Indirect_VirtualMethod, Indirect_FunctionPtr }; 8197fe43adaSDoug Wyatt 8207fe43adaSDoug Wyatt auto MaybeAddSiteContext = [&](const Decl *D, const Violation &V) { 8217fe43adaSDoug Wyatt // If a violation site is a member initializer, add a note pointing to 8227fe43adaSDoug Wyatt // the constructor which invoked it. 8237fe43adaSDoug Wyatt if (V.Site.kind() == ViolationSite::Kind::MemberInitializer) { 8247fe43adaSDoug Wyatt unsigned ImplicitCtor = 0; 8257fe43adaSDoug Wyatt if (auto *Ctor = dyn_cast<CXXConstructorDecl>(D); 8267fe43adaSDoug Wyatt Ctor && Ctor->isImplicit()) 8277fe43adaSDoug Wyatt ImplicitCtor = 1; 8287fe43adaSDoug Wyatt S.Diag(D->getLocation(), diag::note_func_effect_in_constructor) 8297fe43adaSDoug Wyatt << ImplicitCtor; 8307fe43adaSDoug Wyatt } 8317fe43adaSDoug Wyatt 8327fe43adaSDoug Wyatt // If a violation site is a default argument expression, add a note 8337fe43adaSDoug Wyatt // pointing to the call site using the default argument. 8347fe43adaSDoug Wyatt else if (V.Site.kind() == ViolationSite::Kind::DefaultArgExpr) 8357fe43adaSDoug Wyatt S.Diag(V.Site.defaultArgExpr()->getUsedLocation(), 8367fe43adaSDoug Wyatt diag::note_in_evaluating_default_argument); 8377fe43adaSDoug Wyatt }; 8387fe43adaSDoug Wyatt 8397fe43adaSDoug Wyatt // Top-level violations are warnings. 8407fe43adaSDoug Wyatt for (const Violation &Viol1 : Viols) { 8417fe43adaSDoug Wyatt StringRef effectName = Viol1.Effect.name(); 8427fe43adaSDoug Wyatt switch (Viol1.ID) { 8437fe43adaSDoug Wyatt case ViolationID::None: 8447fe43adaSDoug Wyatt case ViolationID::DeclDisallowsInference: // Shouldn't happen 8457fe43adaSDoug Wyatt // here. 8467fe43adaSDoug Wyatt llvm_unreachable("Unexpected violation kind"); 8477fe43adaSDoug Wyatt break; 8487fe43adaSDoug Wyatt case ViolationID::AllocatesMemory: 8497fe43adaSDoug Wyatt case ViolationID::ThrowsOrCatchesExceptions: 8507fe43adaSDoug Wyatt case ViolationID::HasStaticLocalVariable: 8517fe43adaSDoug Wyatt case ViolationID::AccessesThreadLocalVariable: 8527fe43adaSDoug Wyatt case ViolationID::AccessesObjCMethodOrProperty: 8537fe43adaSDoug Wyatt S.Diag(Viol1.Loc, diag::warn_func_effect_violation) 8547fe43adaSDoug Wyatt << GetCallableDeclKind(CInfo.CDecl, &Viol1) << effectName 8557fe43adaSDoug Wyatt << Viol1.diagnosticSelectIndex(); 8567fe43adaSDoug Wyatt MaybeAddSiteContext(CInfo.CDecl, Viol1); 8577fe43adaSDoug Wyatt MaybeAddTemplateNote(CInfo.CDecl); 8587fe43adaSDoug Wyatt break; 8597fe43adaSDoug Wyatt case ViolationID::CallsExprWithoutEffect: 8607fe43adaSDoug Wyatt S.Diag(Viol1.Loc, diag::warn_func_effect_calls_expr_without_effect) 8617fe43adaSDoug Wyatt << GetCallableDeclKind(CInfo.CDecl, &Viol1) << effectName; 8627fe43adaSDoug Wyatt MaybeAddSiteContext(CInfo.CDecl, Viol1); 8637fe43adaSDoug Wyatt MaybeAddTemplateNote(CInfo.CDecl); 8647fe43adaSDoug Wyatt break; 8657fe43adaSDoug Wyatt 8667fe43adaSDoug Wyatt case ViolationID::CallsDeclWithoutEffect: { 8677fe43adaSDoug Wyatt CallableInfo CalleeInfo(*Viol1.Callee); 8687fe43adaSDoug Wyatt std::string CalleeName = CalleeInfo.getNameForDiagnostic(S); 8697fe43adaSDoug Wyatt 8707fe43adaSDoug Wyatt S.Diag(Viol1.Loc, diag::warn_func_effect_calls_func_without_effect) 8717fe43adaSDoug Wyatt << GetCallableDeclKind(CInfo.CDecl, &Viol1) << effectName 8727fe43adaSDoug Wyatt << GetCallableDeclKind(CalleeInfo.CDecl, nullptr) << CalleeName; 8737fe43adaSDoug Wyatt MaybeAddSiteContext(CInfo.CDecl, Viol1); 8747fe43adaSDoug Wyatt MaybeAddTemplateNote(CInfo.CDecl); 8757fe43adaSDoug Wyatt 8767fe43adaSDoug Wyatt // Emit notes explaining the transitive chain of inferences: Why isn't 8777fe43adaSDoug Wyatt // the callee safe? 8787fe43adaSDoug Wyatt for (const Decl *Callee = Viol1.Callee; Callee != nullptr;) { 8797fe43adaSDoug Wyatt std::optional<CallableInfo> MaybeNextCallee; 8807fe43adaSDoug Wyatt CompleteFunctionAnalysis *Completed = 8817fe43adaSDoug Wyatt DeclAnalysis.completedAnalysisForDecl(CalleeInfo.CDecl); 8827fe43adaSDoug Wyatt if (Completed == nullptr) { 8837fe43adaSDoug Wyatt // No result - could be 8847fe43adaSDoug Wyatt // - non-inline and extern 8857fe43adaSDoug Wyatt // - indirect (virtual or through function pointer) 8867fe43adaSDoug Wyatt // - effect has been explicitly disclaimed (e.g. "blocking") 8877fe43adaSDoug Wyatt 8887fe43adaSDoug Wyatt CallableType CType = CalleeInfo.type(); 8897fe43adaSDoug Wyatt if (CType == CallableType::Virtual) 8907fe43adaSDoug Wyatt S.Diag(Callee->getLocation(), 8917fe43adaSDoug Wyatt diag::note_func_effect_call_indirect) 8927fe43adaSDoug Wyatt << Indirect_VirtualMethod << effectName; 8937fe43adaSDoug Wyatt else if (CType == CallableType::Unknown) 8947fe43adaSDoug Wyatt S.Diag(Callee->getLocation(), 8957fe43adaSDoug Wyatt diag::note_func_effect_call_indirect) 8967fe43adaSDoug Wyatt << Indirect_FunctionPtr << effectName; 8977fe43adaSDoug Wyatt else if (CalleeInfo.Effects.contains(Viol1.Effect.oppositeKind())) 8987fe43adaSDoug Wyatt S.Diag(Callee->getLocation(), 8997fe43adaSDoug Wyatt diag::note_func_effect_call_disallows_inference) 9007fe43adaSDoug Wyatt << GetCallableDeclKind(CInfo.CDecl, nullptr) << effectName 9017fe43adaSDoug Wyatt << FunctionEffect(Viol1.Effect.oppositeKind()).name(); 9027fe43adaSDoug Wyatt else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(Callee); 9037fe43adaSDoug Wyatt FD == nullptr || FD->getBuiltinID() == 0) { 9047fe43adaSDoug Wyatt // A builtin callee generally doesn't have a useful source 9057fe43adaSDoug Wyatt // location at which to insert a note. 9067fe43adaSDoug Wyatt S.Diag(Callee->getLocation(), diag::note_func_effect_call_extern) 9077fe43adaSDoug Wyatt << effectName; 9087fe43adaSDoug Wyatt } 9097fe43adaSDoug Wyatt break; 9107fe43adaSDoug Wyatt } 9117fe43adaSDoug Wyatt const Violation *PtrViol2 = 9127fe43adaSDoug Wyatt Completed->firstViolationForEffect(Viol1.Effect); 9137fe43adaSDoug Wyatt if (PtrViol2 == nullptr) 9147fe43adaSDoug Wyatt break; 9157fe43adaSDoug Wyatt 9167fe43adaSDoug Wyatt const Violation &Viol2 = *PtrViol2; 9177fe43adaSDoug Wyatt switch (Viol2.ID) { 9187fe43adaSDoug Wyatt case ViolationID::None: 9197fe43adaSDoug Wyatt llvm_unreachable("Unexpected violation kind"); 9207fe43adaSDoug Wyatt break; 9217fe43adaSDoug Wyatt case ViolationID::DeclDisallowsInference: 9227fe43adaSDoug Wyatt S.Diag(Viol2.Loc, diag::note_func_effect_call_disallows_inference) 9237fe43adaSDoug Wyatt << GetCallableDeclKind(CalleeInfo.CDecl, nullptr) << effectName 9247fe43adaSDoug Wyatt << Viol2.CalleeEffectPreventingInference->name(); 9257fe43adaSDoug Wyatt break; 9267fe43adaSDoug Wyatt case ViolationID::CallsExprWithoutEffect: 9277fe43adaSDoug Wyatt S.Diag(Viol2.Loc, diag::note_func_effect_call_indirect) 9287fe43adaSDoug Wyatt << Indirect_FunctionPtr << effectName; 9297fe43adaSDoug Wyatt break; 9307fe43adaSDoug Wyatt case ViolationID::AllocatesMemory: 9317fe43adaSDoug Wyatt case ViolationID::ThrowsOrCatchesExceptions: 9327fe43adaSDoug Wyatt case ViolationID::HasStaticLocalVariable: 9337fe43adaSDoug Wyatt case ViolationID::AccessesThreadLocalVariable: 9347fe43adaSDoug Wyatt case ViolationID::AccessesObjCMethodOrProperty: 9357fe43adaSDoug Wyatt S.Diag(Viol2.Loc, diag::note_func_effect_violation) 9367fe43adaSDoug Wyatt << GetCallableDeclKind(CalleeInfo.CDecl, &Viol2) << effectName 9377fe43adaSDoug Wyatt << Viol2.diagnosticSelectIndex(); 9387fe43adaSDoug Wyatt MaybeAddSiteContext(CalleeInfo.CDecl, Viol2); 9397fe43adaSDoug Wyatt break; 9407fe43adaSDoug Wyatt case ViolationID::CallsDeclWithoutEffect: 9417fe43adaSDoug Wyatt MaybeNextCallee.emplace(*Viol2.Callee); 9427fe43adaSDoug Wyatt S.Diag(Viol2.Loc, diag::note_func_effect_calls_func_without_effect) 9437fe43adaSDoug Wyatt << GetCallableDeclKind(CalleeInfo.CDecl, &Viol2) << effectName 9447fe43adaSDoug Wyatt << GetCallableDeclKind(Viol2.Callee, nullptr) 9457fe43adaSDoug Wyatt << MaybeNextCallee->getNameForDiagnostic(S); 9467fe43adaSDoug Wyatt break; 9477fe43adaSDoug Wyatt } 9487fe43adaSDoug Wyatt MaybeAddTemplateNote(Callee); 9497fe43adaSDoug Wyatt Callee = Viol2.Callee; 9507fe43adaSDoug Wyatt if (MaybeNextCallee) { 9517fe43adaSDoug Wyatt CalleeInfo = *MaybeNextCallee; 9527fe43adaSDoug Wyatt CalleeName = CalleeInfo.getNameForDiagnostic(S); 9537fe43adaSDoug Wyatt } 9547fe43adaSDoug Wyatt } 9557fe43adaSDoug Wyatt } break; 9567fe43adaSDoug Wyatt } 9577fe43adaSDoug Wyatt } 9587fe43adaSDoug Wyatt } 9597fe43adaSDoug Wyatt 9607fe43adaSDoug Wyatt // ---------- 9617fe43adaSDoug Wyatt // This AST visitor is used to traverse the body of a function during effect 9627fe43adaSDoug Wyatt // verification. This happens in 2 situations: 9637fe43adaSDoug Wyatt // [1] The function has declared effects which need to be validated. 9647fe43adaSDoug Wyatt // [2] The function has not explicitly declared an effect in question, and is 9657fe43adaSDoug Wyatt // being checked for implicit conformance. 9667fe43adaSDoug Wyatt // 9677fe43adaSDoug Wyatt // Violations are always routed to a PendingFunctionAnalysis. 968dde802b1SSirraide struct FunctionBodyASTVisitor : DynamicRecursiveASTVisitor { 9697fe43adaSDoug Wyatt Analyzer &Outer; 9707fe43adaSDoug Wyatt PendingFunctionAnalysis &CurrentFunction; 9717fe43adaSDoug Wyatt CallableInfo &CurrentCaller; 9727fe43adaSDoug Wyatt ViolationSite VSite; 9737f9d348eSDoug Wyatt const Expr *TrailingRequiresClause = nullptr; 9743e30b365SDoug Wyatt const Expr *NoexceptExpr = nullptr; 9757fe43adaSDoug Wyatt 9767fe43adaSDoug Wyatt FunctionBodyASTVisitor(Analyzer &Outer, 9777fe43adaSDoug Wyatt PendingFunctionAnalysis &CurrentFunction, 9787fe43adaSDoug Wyatt CallableInfo &CurrentCaller) 9797fe43adaSDoug Wyatt : Outer(Outer), CurrentFunction(CurrentFunction), 980dde802b1SSirraide CurrentCaller(CurrentCaller) { 981dde802b1SSirraide ShouldVisitImplicitCode = true; 982dde802b1SSirraide ShouldWalkTypesOfTypeLocs = false; 983dde802b1SSirraide } 9847fe43adaSDoug Wyatt 9857fe43adaSDoug Wyatt // -- Entry point -- 9867fe43adaSDoug Wyatt void run() { 9877fe43adaSDoug Wyatt // The target function may have implicit code paths beyond the 9887fe43adaSDoug Wyatt // body: member and base destructors. Visit these first. 9897fe43adaSDoug Wyatt if (auto *Dtor = dyn_cast<CXXDestructorDecl>(CurrentCaller.CDecl)) 9907fe43adaSDoug Wyatt followDestructor(dyn_cast<CXXRecordDecl>(Dtor->getParent()), Dtor); 9917fe43adaSDoug Wyatt 9923e30b365SDoug Wyatt if (auto *FD = dyn_cast<FunctionDecl>(CurrentCaller.CDecl)) { 9937f9d348eSDoug Wyatt TrailingRequiresClause = FD->getTrailingRequiresClause(); 9947f9d348eSDoug Wyatt 9953e30b365SDoug Wyatt // Note that FD->getType->getAs<FunctionProtoType>() can yield a 9963e30b365SDoug Wyatt // noexcept Expr which has been boiled down to a constant expression. 9973e30b365SDoug Wyatt // Going through the TypeSourceInfo obtains the actual expression which 9983e30b365SDoug Wyatt // will be traversed as part of the function -- unless we capture it 9993e30b365SDoug Wyatt // here and have TraverseStmt skip it. 10003e30b365SDoug Wyatt if (TypeSourceInfo *TSI = FD->getTypeSourceInfo()) { 10013e30b365SDoug Wyatt if (FunctionProtoTypeLoc TL = 10023e30b365SDoug Wyatt TSI->getTypeLoc().getAs<FunctionProtoTypeLoc>()) 10033e30b365SDoug Wyatt if (const FunctionProtoType *FPT = TL.getTypePtr()) 10043e30b365SDoug Wyatt NoexceptExpr = FPT->getNoexceptExpr(); 10053e30b365SDoug Wyatt } 10063e30b365SDoug Wyatt } 10073e30b365SDoug Wyatt 10087fe43adaSDoug Wyatt // Do an AST traversal of the function/block body 10097fe43adaSDoug Wyatt TraverseDecl(const_cast<Decl *>(CurrentCaller.CDecl)); 10107fe43adaSDoug Wyatt } 10117fe43adaSDoug Wyatt 10127fe43adaSDoug Wyatt // -- Methods implementing common logic -- 10137fe43adaSDoug Wyatt 10147fe43adaSDoug Wyatt // Handle a language construct forbidden by some effects. Only effects whose 10157fe43adaSDoug Wyatt // flags include the specified flag receive a violation. \p Flag describes 10167fe43adaSDoug Wyatt // the construct. 10177fe43adaSDoug Wyatt void diagnoseLanguageConstruct(FunctionEffect::FlagBit Flag, 10187fe43adaSDoug Wyatt ViolationID VID, SourceLocation Loc, 10197fe43adaSDoug Wyatt const Decl *Callee = nullptr) { 10207fe43adaSDoug Wyatt // If there are any declared verifiable effects which forbid the construct 10217fe43adaSDoug Wyatt // represented by the flag, store just one violation. 10227fe43adaSDoug Wyatt for (FunctionEffect Effect : CurrentFunction.DeclaredVerifiableEffects) { 10237fe43adaSDoug Wyatt if (Effect.flags() & Flag) { 10247fe43adaSDoug Wyatt addViolation(/*inferring=*/false, Effect, VID, Loc, Callee); 10257fe43adaSDoug Wyatt break; 10267fe43adaSDoug Wyatt } 10277fe43adaSDoug Wyatt } 10287fe43adaSDoug Wyatt // For each inferred effect which forbids the construct, store a 10297fe43adaSDoug Wyatt // violation, if we don't already have a violation for that effect. 10307fe43adaSDoug Wyatt for (FunctionEffect Effect : CurrentFunction.EffectsToInfer) 10317fe43adaSDoug Wyatt if (Effect.flags() & Flag) 10327fe43adaSDoug Wyatt addViolation(/*inferring=*/true, Effect, VID, Loc, Callee); 10337fe43adaSDoug Wyatt } 10347fe43adaSDoug Wyatt 10357fe43adaSDoug Wyatt void addViolation(bool Inferring, FunctionEffect Effect, ViolationID VID, 10367fe43adaSDoug Wyatt SourceLocation Loc, const Decl *Callee = nullptr) { 10377fe43adaSDoug Wyatt CurrentFunction.checkAddViolation( 10387fe43adaSDoug Wyatt Inferring, Violation(Effect, VID, VSite, Loc, Callee)); 10397fe43adaSDoug Wyatt } 10407fe43adaSDoug Wyatt 10417fe43adaSDoug Wyatt // Here we have a call to a Decl, either explicitly via a CallExpr or some 10427fe43adaSDoug Wyatt // other AST construct. CallableInfo pertains to the callee. 10437fe43adaSDoug Wyatt void followCall(CallableInfo &CI, SourceLocation CallLoc) { 10447fe43adaSDoug Wyatt // Check for a call to a builtin function, whose effects are 10457fe43adaSDoug Wyatt // handled specially. 10467fe43adaSDoug Wyatt if (const auto *FD = dyn_cast<FunctionDecl>(CI.CDecl)) { 10477fe43adaSDoug Wyatt if (unsigned BuiltinID = FD->getBuiltinID()) { 10487fe43adaSDoug Wyatt CI.Effects = getBuiltinFunctionEffects(BuiltinID); 10497fe43adaSDoug Wyatt if (CI.Effects.empty()) { 10507fe43adaSDoug Wyatt // A builtin with no known effects is assumed safe. 10517fe43adaSDoug Wyatt return; 10527fe43adaSDoug Wyatt } 10537fe43adaSDoug Wyatt // A builtin WITH effects doesn't get any special treatment for 10547fe43adaSDoug Wyatt // being noreturn/noexcept, e.g. longjmp(), so we skip the check 10557fe43adaSDoug Wyatt // below. 10567fe43adaSDoug Wyatt } else { 10577fe43adaSDoug Wyatt // If the callee is both `noreturn` and `noexcept`, it presumably 10587fe43adaSDoug Wyatt // terminates. Ignore it for the purposes of effect analysis. 10597fe43adaSDoug Wyatt // If not C++, `noreturn` alone is sufficient. 10607fe43adaSDoug Wyatt if (FD->isNoReturn() && 10617fe43adaSDoug Wyatt (!Outer.S.getLangOpts().CPlusPlus || isNoexcept(FD))) 10627fe43adaSDoug Wyatt return; 10637fe43adaSDoug Wyatt } 10647fe43adaSDoug Wyatt } 10657fe43adaSDoug Wyatt 10667fe43adaSDoug Wyatt Outer.followCall(CurrentCaller, CurrentFunction, CI, CallLoc, 10677fe43adaSDoug Wyatt /*AssertNoFurtherInference=*/false, VSite); 10687fe43adaSDoug Wyatt } 10697fe43adaSDoug Wyatt 10707fe43adaSDoug Wyatt void checkIndirectCall(CallExpr *Call, QualType CalleeType) { 10717fe43adaSDoug Wyatt FunctionEffectKindSet CalleeEffects; 10724d218caaSDoug Wyatt if (FunctionEffectsRef Effects = FunctionEffectsRef::get(CalleeType); 10734d218caaSDoug Wyatt !Effects.empty()) 10744d218caaSDoug Wyatt CalleeEffects.insert(Effects); 10757fe43adaSDoug Wyatt 10767fe43adaSDoug Wyatt auto Check1Effect = [&](FunctionEffect Effect, bool Inferring) { 10774d218caaSDoug Wyatt if (Effect.shouldDiagnoseFunctionCall( 10787fe43adaSDoug Wyatt /*direct=*/false, CalleeEffects)) 10797fe43adaSDoug Wyatt addViolation(Inferring, Effect, ViolationID::CallsExprWithoutEffect, 10807fe43adaSDoug Wyatt Call->getBeginLoc()); 10817fe43adaSDoug Wyatt }; 10827fe43adaSDoug Wyatt 10837fe43adaSDoug Wyatt for (FunctionEffect Effect : CurrentFunction.DeclaredVerifiableEffects) 10847fe43adaSDoug Wyatt Check1Effect(Effect, false); 10857fe43adaSDoug Wyatt 10867fe43adaSDoug Wyatt for (FunctionEffect Effect : CurrentFunction.EffectsToInfer) 10877fe43adaSDoug Wyatt Check1Effect(Effect, true); 10887fe43adaSDoug Wyatt } 10897fe43adaSDoug Wyatt 10907fe43adaSDoug Wyatt // This destructor's body should be followed by the caller, but here we 10917fe43adaSDoug Wyatt // follow the field and base destructors. 10927fe43adaSDoug Wyatt void followDestructor(const CXXRecordDecl *Rec, 10937fe43adaSDoug Wyatt const CXXDestructorDecl *Dtor) { 10947fe43adaSDoug Wyatt SourceLocation DtorLoc = Dtor->getLocation(); 10957fe43adaSDoug Wyatt for (const FieldDecl *Field : Rec->fields()) 10967fe43adaSDoug Wyatt followTypeDtor(Field->getType(), DtorLoc); 10977fe43adaSDoug Wyatt 10987fe43adaSDoug Wyatt if (const auto *Class = dyn_cast<CXXRecordDecl>(Rec)) 10997fe43adaSDoug Wyatt for (const CXXBaseSpecifier &Base : Class->bases()) 11007fe43adaSDoug Wyatt followTypeDtor(Base.getType(), DtorLoc); 11017fe43adaSDoug Wyatt } 11027fe43adaSDoug Wyatt 11037fe43adaSDoug Wyatt void followTypeDtor(QualType QT, SourceLocation CallSite) { 11047fe43adaSDoug Wyatt const Type *Ty = QT.getTypePtr(); 11057fe43adaSDoug Wyatt while (Ty->isArrayType()) { 11067fe43adaSDoug Wyatt const ArrayType *Arr = Ty->getAsArrayTypeUnsafe(); 11077fe43adaSDoug Wyatt QT = Arr->getElementType(); 11087fe43adaSDoug Wyatt Ty = QT.getTypePtr(); 11097fe43adaSDoug Wyatt } 11107fe43adaSDoug Wyatt 11117fe43adaSDoug Wyatt if (Ty->isRecordType()) { 11127fe43adaSDoug Wyatt if (const CXXRecordDecl *Class = Ty->getAsCXXRecordDecl()) { 11137fe43adaSDoug Wyatt if (CXXDestructorDecl *Dtor = Class->getDestructor(); 11147fe43adaSDoug Wyatt Dtor && !Dtor->isDeleted()) { 11157fe43adaSDoug Wyatt CallableInfo CI(*Dtor); 11167fe43adaSDoug Wyatt followCall(CI, CallSite); 11177fe43adaSDoug Wyatt } 11187fe43adaSDoug Wyatt } 11197fe43adaSDoug Wyatt } 11207fe43adaSDoug Wyatt } 11217fe43adaSDoug Wyatt 11227fe43adaSDoug Wyatt // -- Methods for use of RecursiveASTVisitor -- 11237fe43adaSDoug Wyatt 1124dde802b1SSirraide bool VisitCXXThrowExpr(CXXThrowExpr *Throw) override { 11257fe43adaSDoug Wyatt diagnoseLanguageConstruct(FunctionEffect::FE_ExcludeThrow, 11267fe43adaSDoug Wyatt ViolationID::ThrowsOrCatchesExceptions, 11277fe43adaSDoug Wyatt Throw->getThrowLoc()); 11287fe43adaSDoug Wyatt return true; 11297fe43adaSDoug Wyatt } 11307fe43adaSDoug Wyatt 1131dde802b1SSirraide bool VisitCXXCatchStmt(CXXCatchStmt *Catch) override { 11327fe43adaSDoug Wyatt diagnoseLanguageConstruct(FunctionEffect::FE_ExcludeCatch, 11337fe43adaSDoug Wyatt ViolationID::ThrowsOrCatchesExceptions, 11347fe43adaSDoug Wyatt Catch->getCatchLoc()); 11357fe43adaSDoug Wyatt return true; 11367fe43adaSDoug Wyatt } 11377fe43adaSDoug Wyatt 1138dde802b1SSirraide bool VisitObjCAtThrowStmt(ObjCAtThrowStmt *Throw) override { 11397fe43adaSDoug Wyatt diagnoseLanguageConstruct(FunctionEffect::FE_ExcludeThrow, 11407fe43adaSDoug Wyatt ViolationID::ThrowsOrCatchesExceptions, 11417fe43adaSDoug Wyatt Throw->getThrowLoc()); 11427fe43adaSDoug Wyatt return true; 11437fe43adaSDoug Wyatt } 11447fe43adaSDoug Wyatt 1145dde802b1SSirraide bool VisitObjCAtCatchStmt(ObjCAtCatchStmt *Catch) override { 11467fe43adaSDoug Wyatt diagnoseLanguageConstruct(FunctionEffect::FE_ExcludeCatch, 11477fe43adaSDoug Wyatt ViolationID::ThrowsOrCatchesExceptions, 11487fe43adaSDoug Wyatt Catch->getAtCatchLoc()); 11497fe43adaSDoug Wyatt return true; 11507fe43adaSDoug Wyatt } 11517fe43adaSDoug Wyatt 1152dde802b1SSirraide bool VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *Finally) override { 1153cef66aa0SDoug Wyatt diagnoseLanguageConstruct(FunctionEffect::FE_ExcludeCatch, 1154cef66aa0SDoug Wyatt ViolationID::ThrowsOrCatchesExceptions, 1155cef66aa0SDoug Wyatt Finally->getAtFinallyLoc()); 1156cef66aa0SDoug Wyatt return true; 1157cef66aa0SDoug Wyatt } 1158cef66aa0SDoug Wyatt 1159dde802b1SSirraide bool VisitObjCMessageExpr(ObjCMessageExpr *Msg) override { 11607fe43adaSDoug Wyatt diagnoseLanguageConstruct(FunctionEffect::FE_ExcludeObjCMessageSend, 11617fe43adaSDoug Wyatt ViolationID::AccessesObjCMethodOrProperty, 11627fe43adaSDoug Wyatt Msg->getBeginLoc()); 11637fe43adaSDoug Wyatt return true; 11647fe43adaSDoug Wyatt } 11657fe43adaSDoug Wyatt 1166dde802b1SSirraide bool VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *ARP) override { 1167cef66aa0SDoug Wyatt // Under the hood, @autorelease (potentially?) allocates memory and 1168cef66aa0SDoug Wyatt // invokes ObjC methods. We don't currently have memory allocation as 1169cef66aa0SDoug Wyatt // a "language construct" but we do have ObjC messaging, so diagnose that. 1170cef66aa0SDoug Wyatt diagnoseLanguageConstruct(FunctionEffect::FE_ExcludeObjCMessageSend, 1171cef66aa0SDoug Wyatt ViolationID::AccessesObjCMethodOrProperty, 1172cef66aa0SDoug Wyatt ARP->getBeginLoc()); 1173cef66aa0SDoug Wyatt return true; 1174cef66aa0SDoug Wyatt } 1175cef66aa0SDoug Wyatt 1176dde802b1SSirraide bool VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *Sync) override { 1177cef66aa0SDoug Wyatt // Under the hood, this calls objc_sync_enter and objc_sync_exit, wrapped 1178cef66aa0SDoug Wyatt // in a @try/@finally block. Diagnose this generically as "ObjC 1179cef66aa0SDoug Wyatt // messaging". 1180cef66aa0SDoug Wyatt diagnoseLanguageConstruct(FunctionEffect::FE_ExcludeObjCMessageSend, 1181cef66aa0SDoug Wyatt ViolationID::AccessesObjCMethodOrProperty, 1182cef66aa0SDoug Wyatt Sync->getBeginLoc()); 1183cef66aa0SDoug Wyatt return true; 1184cef66aa0SDoug Wyatt } 1185cef66aa0SDoug Wyatt 1186dde802b1SSirraide bool VisitSEHExceptStmt(SEHExceptStmt *Exc) override { 11877fe43adaSDoug Wyatt diagnoseLanguageConstruct(FunctionEffect::FE_ExcludeCatch, 11887fe43adaSDoug Wyatt ViolationID::ThrowsOrCatchesExceptions, 11897fe43adaSDoug Wyatt Exc->getExceptLoc()); 11907fe43adaSDoug Wyatt return true; 11917fe43adaSDoug Wyatt } 11927fe43adaSDoug Wyatt 1193dde802b1SSirraide bool VisitCallExpr(CallExpr *Call) override { 11947fe43adaSDoug Wyatt LLVM_DEBUG(llvm::dbgs() 11957fe43adaSDoug Wyatt << "VisitCallExpr : " 11967fe43adaSDoug Wyatt << Call->getBeginLoc().printToString(Outer.S.SourceMgr) 11977fe43adaSDoug Wyatt << "\n";); 11987fe43adaSDoug Wyatt 11997fe43adaSDoug Wyatt Expr *CalleeExpr = Call->getCallee(); 12007fe43adaSDoug Wyatt if (const Decl *Callee = CalleeExpr->getReferencedDeclOfCallee()) { 12017fe43adaSDoug Wyatt CallableInfo CI(*Callee); 12027fe43adaSDoug Wyatt followCall(CI, Call->getBeginLoc()); 12037fe43adaSDoug Wyatt return true; 12047fe43adaSDoug Wyatt } 12057fe43adaSDoug Wyatt 12067fe43adaSDoug Wyatt if (isa<CXXPseudoDestructorExpr>(CalleeExpr)) { 12077fe43adaSDoug Wyatt // Just destroying a scalar, fine. 12087fe43adaSDoug Wyatt return true; 12097fe43adaSDoug Wyatt } 12107fe43adaSDoug Wyatt 12117fe43adaSDoug Wyatt // No Decl, just an Expr. Just check based on its type. 12127fe43adaSDoug Wyatt checkIndirectCall(Call, CalleeExpr->getType()); 12137fe43adaSDoug Wyatt 12147fe43adaSDoug Wyatt return true; 12157fe43adaSDoug Wyatt } 12167fe43adaSDoug Wyatt 1217dde802b1SSirraide bool VisitVarDecl(VarDecl *Var) override { 12187fe43adaSDoug Wyatt LLVM_DEBUG(llvm::dbgs() 12197fe43adaSDoug Wyatt << "VisitVarDecl : " 12207fe43adaSDoug Wyatt << Var->getBeginLoc().printToString(Outer.S.SourceMgr) 12217fe43adaSDoug Wyatt << "\n";); 12227fe43adaSDoug Wyatt 12237fe43adaSDoug Wyatt if (Var->isStaticLocal()) 12247fe43adaSDoug Wyatt diagnoseLanguageConstruct(FunctionEffect::FE_ExcludeStaticLocalVars, 12257fe43adaSDoug Wyatt ViolationID::HasStaticLocalVariable, 12267fe43adaSDoug Wyatt Var->getLocation()); 12277fe43adaSDoug Wyatt 12287fe43adaSDoug Wyatt const QualType::DestructionKind DK = 12297fe43adaSDoug Wyatt Var->needsDestruction(Outer.S.getASTContext()); 12307fe43adaSDoug Wyatt if (DK == QualType::DK_cxx_destructor) 12317fe43adaSDoug Wyatt followTypeDtor(Var->getType(), Var->getLocation()); 12327fe43adaSDoug Wyatt return true; 12337fe43adaSDoug Wyatt } 12347fe43adaSDoug Wyatt 1235dde802b1SSirraide bool VisitCXXNewExpr(CXXNewExpr *New) override { 12367fe43adaSDoug Wyatt // RecursiveASTVisitor does not visit the implicit call to operator new. 12377fe43adaSDoug Wyatt if (FunctionDecl *FD = New->getOperatorNew()) { 12387fe43adaSDoug Wyatt CallableInfo CI(*FD, SpecialFuncType::OperatorNew); 12397fe43adaSDoug Wyatt followCall(CI, New->getBeginLoc()); 12407fe43adaSDoug Wyatt } 12417fe43adaSDoug Wyatt 12427fe43adaSDoug Wyatt // It's a bit excessive to check operator delete here, since it's 12437fe43adaSDoug Wyatt // just a fallback for operator new followed by a failed constructor. 12447fe43adaSDoug Wyatt // We could check it via New->getOperatorDelete(). 12457fe43adaSDoug Wyatt 12467fe43adaSDoug Wyatt // It DOES however visit the called constructor 12477fe43adaSDoug Wyatt return true; 12487fe43adaSDoug Wyatt } 12497fe43adaSDoug Wyatt 1250dde802b1SSirraide bool VisitCXXDeleteExpr(CXXDeleteExpr *Delete) override { 12517fe43adaSDoug Wyatt // RecursiveASTVisitor does not visit the implicit call to operator 12527fe43adaSDoug Wyatt // delete. 12537fe43adaSDoug Wyatt if (FunctionDecl *FD = Delete->getOperatorDelete()) { 12547fe43adaSDoug Wyatt CallableInfo CI(*FD, SpecialFuncType::OperatorDelete); 12557fe43adaSDoug Wyatt followCall(CI, Delete->getBeginLoc()); 12567fe43adaSDoug Wyatt } 12577fe43adaSDoug Wyatt 12587fe43adaSDoug Wyatt // It DOES however visit the called destructor 12597fe43adaSDoug Wyatt 12607fe43adaSDoug Wyatt return true; 12617fe43adaSDoug Wyatt } 12627fe43adaSDoug Wyatt 1263dde802b1SSirraide bool VisitCXXConstructExpr(CXXConstructExpr *Construct) override { 12647fe43adaSDoug Wyatt LLVM_DEBUG(llvm::dbgs() << "VisitCXXConstructExpr : " 12657fe43adaSDoug Wyatt << Construct->getBeginLoc().printToString( 12667fe43adaSDoug Wyatt Outer.S.SourceMgr) 12677fe43adaSDoug Wyatt << "\n";); 12687fe43adaSDoug Wyatt 12697fe43adaSDoug Wyatt // RecursiveASTVisitor does not visit the implicit call to the 12707fe43adaSDoug Wyatt // constructor. 12717fe43adaSDoug Wyatt const CXXConstructorDecl *Ctor = Construct->getConstructor(); 12727fe43adaSDoug Wyatt CallableInfo CI(*Ctor); 12737fe43adaSDoug Wyatt followCall(CI, Construct->getLocation()); 12747fe43adaSDoug Wyatt 12757fe43adaSDoug Wyatt return true; 12767fe43adaSDoug Wyatt } 12777fe43adaSDoug Wyatt 1278dde802b1SSirraide bool TraverseStmt(Stmt *Statement) override { 12797f9d348eSDoug Wyatt // If this statement is a `requires` clause from the top-level function 12807f9d348eSDoug Wyatt // being traversed, ignore it, since it's not generating runtime code. 12817f9d348eSDoug Wyatt // We skip the traversal of lambdas (beyond their captures, see 12827f9d348eSDoug Wyatt // TraverseLambdaExpr below), so just caching this from our constructor 12837f9d348eSDoug Wyatt // should suffice. 12843e30b365SDoug Wyatt if (Statement != TrailingRequiresClause && Statement != NoexceptExpr) 1285dde802b1SSirraide return DynamicRecursiveASTVisitor::TraverseStmt(Statement); 12867f9d348eSDoug Wyatt return true; 12877f9d348eSDoug Wyatt } 12887f9d348eSDoug Wyatt 1289dde802b1SSirraide bool TraverseConstructorInitializer(CXXCtorInitializer *Init) override { 12907fe43adaSDoug Wyatt ViolationSite PrevVS = VSite; 12917fe43adaSDoug Wyatt if (Init->isAnyMemberInitializer()) 12927fe43adaSDoug Wyatt VSite.setKind(ViolationSite::Kind::MemberInitializer); 1293dde802b1SSirraide bool Result = 1294dde802b1SSirraide DynamicRecursiveASTVisitor::TraverseConstructorInitializer(Init); 12957fe43adaSDoug Wyatt VSite = PrevVS; 12967fe43adaSDoug Wyatt return Result; 12977fe43adaSDoug Wyatt } 12987fe43adaSDoug Wyatt 1299dde802b1SSirraide bool TraverseCXXDefaultArgExpr(CXXDefaultArgExpr *E) override { 13007fe43adaSDoug Wyatt LLVM_DEBUG(llvm::dbgs() 13017fe43adaSDoug Wyatt << "TraverseCXXDefaultArgExpr : " 13027fe43adaSDoug Wyatt << E->getUsedLocation().printToString(Outer.S.SourceMgr) 13037fe43adaSDoug Wyatt << "\n";); 13047fe43adaSDoug Wyatt 13057fe43adaSDoug Wyatt ViolationSite PrevVS = VSite; 13067fe43adaSDoug Wyatt if (VSite.kind() == ViolationSite::Kind::Default) 13077fe43adaSDoug Wyatt VSite = ViolationSite{E}; 13087fe43adaSDoug Wyatt 1309dde802b1SSirraide bool Result = DynamicRecursiveASTVisitor::TraverseCXXDefaultArgExpr(E); 13107fe43adaSDoug Wyatt VSite = PrevVS; 13117fe43adaSDoug Wyatt return Result; 13127fe43adaSDoug Wyatt } 13137fe43adaSDoug Wyatt 1314dde802b1SSirraide bool TraverseLambdaExpr(LambdaExpr *Lambda) override { 13157fe43adaSDoug Wyatt // We override this so as to be able to skip traversal of the lambda's 13167fe43adaSDoug Wyatt // body. We have to explicitly traverse the captures. Why not return 13177fe43adaSDoug Wyatt // false from shouldVisitLambdaBody()? Because we need to visit a lambda's 13187fe43adaSDoug Wyatt // body when we are verifying the lambda itself; we only want to skip it 13197fe43adaSDoug Wyatt // in the context of the outer function. 13207fe43adaSDoug Wyatt for (unsigned I = 0, N = Lambda->capture_size(); I < N; ++I) 13217fe43adaSDoug Wyatt TraverseLambdaCapture(Lambda, Lambda->capture_begin() + I, 13227fe43adaSDoug Wyatt Lambda->capture_init_begin()[I]); 13237fe43adaSDoug Wyatt 13247fe43adaSDoug Wyatt return true; 13257fe43adaSDoug Wyatt } 13267fe43adaSDoug Wyatt 1327dde802b1SSirraide bool TraverseBlockExpr(BlockExpr * /*unused*/) override { 13287f9d348eSDoug Wyatt // As with lambdas, don't traverse the block's body. 13297fe43adaSDoug Wyatt // TODO: are the capture expressions (ctor call?) safe? 13307fe43adaSDoug Wyatt return true; 13317fe43adaSDoug Wyatt } 13327fe43adaSDoug Wyatt 1333dde802b1SSirraide bool VisitDeclRefExpr(DeclRefExpr *E) override { 13347fe43adaSDoug Wyatt const ValueDecl *Val = E->getDecl(); 13357fe43adaSDoug Wyatt if (const auto *Var = dyn_cast<VarDecl>(Val)) { 13367fe43adaSDoug Wyatt if (Var->getTLSKind() != VarDecl::TLS_None) { 13377fe43adaSDoug Wyatt // At least on macOS, thread-local variables are initialized on 13387fe43adaSDoug Wyatt // first access, including a heap allocation. 13397fe43adaSDoug Wyatt diagnoseLanguageConstruct(FunctionEffect::FE_ExcludeThreadLocalVars, 13407fe43adaSDoug Wyatt ViolationID::AccessesThreadLocalVariable, 13417fe43adaSDoug Wyatt E->getLocation()); 13427fe43adaSDoug Wyatt } 13437fe43adaSDoug Wyatt } 13447fe43adaSDoug Wyatt return true; 13457fe43adaSDoug Wyatt } 13467fe43adaSDoug Wyatt 1347dde802b1SSirraide bool TraverseGenericSelectionExpr(GenericSelectionExpr *Node) override { 13487fe43adaSDoug Wyatt return TraverseStmt(Node->getResultExpr()); 13497fe43adaSDoug Wyatt } 1350dde802b1SSirraide bool 1351dde802b1SSirraide TraverseUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *Node) override { 13527fe43adaSDoug Wyatt return true; 13537fe43adaSDoug Wyatt } 13547fe43adaSDoug Wyatt 1355dde802b1SSirraide bool TraverseTypeOfExprTypeLoc(TypeOfExprTypeLoc Node) override { 1356dde802b1SSirraide return true; 1357dde802b1SSirraide } 13587fe43adaSDoug Wyatt 1359dde802b1SSirraide bool TraverseDecltypeTypeLoc(DecltypeTypeLoc Node) override { return true; } 13607fe43adaSDoug Wyatt 1361dde802b1SSirraide bool TraverseCXXNoexceptExpr(CXXNoexceptExpr *Node) override { 1362dde802b1SSirraide return true; 1363dde802b1SSirraide } 13647fe43adaSDoug Wyatt 1365dde802b1SSirraide bool TraverseCXXTypeidExpr(CXXTypeidExpr *Node) override { return true; } 13667fe43adaSDoug Wyatt 13677fe43adaSDoug Wyatt // Skip concept requirements since they don't generate code. 1368dde802b1SSirraide bool TraverseConceptRequirement(concepts::Requirement *R) override { 1369dde802b1SSirraide return true; 1370dde802b1SSirraide } 13717fe43adaSDoug Wyatt }; 13727fe43adaSDoug Wyatt }; 13737fe43adaSDoug Wyatt 13747fe43adaSDoug Wyatt Analyzer::AnalysisMap::~AnalysisMap() { 13757fe43adaSDoug Wyatt for (const auto &Item : *this) { 13767fe43adaSDoug Wyatt FuncAnalysisPtr AP = Item.second; 13771e3e199eSKazu Hirata if (auto *PFA = dyn_cast<PendingFunctionAnalysis *>(AP)) 13781e3e199eSKazu Hirata delete PFA; 13797fe43adaSDoug Wyatt else 13801e3e199eSKazu Hirata delete cast<CompleteFunctionAnalysis *>(AP); 13817fe43adaSDoug Wyatt } 13827fe43adaSDoug Wyatt } 13837fe43adaSDoug Wyatt 13847fe43adaSDoug Wyatt } // anonymous namespace 13857fe43adaSDoug Wyatt 13867fe43adaSDoug Wyatt namespace clang { 13877fe43adaSDoug Wyatt 13887fe43adaSDoug Wyatt bool Sema::diagnoseConflictingFunctionEffect( 13897fe43adaSDoug Wyatt const FunctionEffectsRef &FX, const FunctionEffectWithCondition &NewEC, 13907fe43adaSDoug Wyatt SourceLocation NewAttrLoc) { 13917fe43adaSDoug Wyatt // If the new effect has a condition, we can't detect conflicts until the 13927fe43adaSDoug Wyatt // condition is resolved. 13937fe43adaSDoug Wyatt if (NewEC.Cond.getCondition() != nullptr) 13947fe43adaSDoug Wyatt return false; 13957fe43adaSDoug Wyatt 13967fe43adaSDoug Wyatt // Diagnose the new attribute as incompatible with a previous one. 13977fe43adaSDoug Wyatt auto Incompatible = [&](const FunctionEffectWithCondition &PrevEC) { 13987fe43adaSDoug Wyatt Diag(NewAttrLoc, diag::err_attributes_are_not_compatible) 13997fe43adaSDoug Wyatt << ("'" + NewEC.description() + "'") 14007fe43adaSDoug Wyatt << ("'" + PrevEC.description() + "'") << false; 14017fe43adaSDoug Wyatt // We don't necessarily have the location of the previous attribute, 14027fe43adaSDoug Wyatt // so no note. 14037fe43adaSDoug Wyatt return true; 14047fe43adaSDoug Wyatt }; 14057fe43adaSDoug Wyatt 14067fe43adaSDoug Wyatt // Compare against previous attributes. 14077fe43adaSDoug Wyatt FunctionEffect::Kind NewKind = NewEC.Effect.kind(); 14087fe43adaSDoug Wyatt 14097fe43adaSDoug Wyatt for (const FunctionEffectWithCondition &PrevEC : FX) { 14107fe43adaSDoug Wyatt // Again, can't check yet when the effect is conditional. 14117fe43adaSDoug Wyatt if (PrevEC.Cond.getCondition() != nullptr) 14127fe43adaSDoug Wyatt continue; 14137fe43adaSDoug Wyatt 14147fe43adaSDoug Wyatt FunctionEffect::Kind PrevKind = PrevEC.Effect.kind(); 14157fe43adaSDoug Wyatt // Note that we allow PrevKind == NewKind; it's redundant and ignored. 14167fe43adaSDoug Wyatt 14177fe43adaSDoug Wyatt if (PrevEC.Effect.oppositeKind() == NewKind) 14187fe43adaSDoug Wyatt return Incompatible(PrevEC); 14197fe43adaSDoug Wyatt 14207fe43adaSDoug Wyatt // A new allocating is incompatible with a previous nonblocking. 14217fe43adaSDoug Wyatt if (PrevKind == FunctionEffect::Kind::NonBlocking && 14227fe43adaSDoug Wyatt NewKind == FunctionEffect::Kind::Allocating) 14237fe43adaSDoug Wyatt return Incompatible(PrevEC); 14247fe43adaSDoug Wyatt 14257fe43adaSDoug Wyatt // A new nonblocking is incompatible with a previous allocating. 14267fe43adaSDoug Wyatt if (PrevKind == FunctionEffect::Kind::Allocating && 14277fe43adaSDoug Wyatt NewKind == FunctionEffect::Kind::NonBlocking) 14287fe43adaSDoug Wyatt return Incompatible(PrevEC); 14297fe43adaSDoug Wyatt } 14307fe43adaSDoug Wyatt 14317fe43adaSDoug Wyatt return false; 14327fe43adaSDoug Wyatt } 14337fe43adaSDoug Wyatt 14347fe43adaSDoug Wyatt void Sema::diagnoseFunctionEffectMergeConflicts( 14357fe43adaSDoug Wyatt const FunctionEffectSet::Conflicts &Errs, SourceLocation NewLoc, 14367fe43adaSDoug Wyatt SourceLocation OldLoc) { 14377fe43adaSDoug Wyatt for (const FunctionEffectSet::Conflict &Conflict : Errs) { 14387fe43adaSDoug Wyatt Diag(NewLoc, diag::warn_conflicting_func_effects) 14397fe43adaSDoug Wyatt << Conflict.Kept.description() << Conflict.Rejected.description(); 14407fe43adaSDoug Wyatt Diag(OldLoc, diag::note_previous_declaration); 14417fe43adaSDoug Wyatt } 14427fe43adaSDoug Wyatt } 14437fe43adaSDoug Wyatt 14447fe43adaSDoug Wyatt // Decl should be a FunctionDecl or BlockDecl. 14457fe43adaSDoug Wyatt void Sema::maybeAddDeclWithEffects(const Decl *D, 14467fe43adaSDoug Wyatt const FunctionEffectsRef &FX) { 14477fe43adaSDoug Wyatt if (!D->hasBody()) { 14487fe43adaSDoug Wyatt if (const auto *FD = D->getAsFunction(); FD && !FD->willHaveBody()) 14497fe43adaSDoug Wyatt return; 14507fe43adaSDoug Wyatt } 14517fe43adaSDoug Wyatt 14527fe43adaSDoug Wyatt if (Diags.getIgnoreAllWarnings() || 14537fe43adaSDoug Wyatt (Diags.getSuppressSystemWarnings() && 14547fe43adaSDoug Wyatt SourceMgr.isInSystemHeader(D->getLocation()))) 14557fe43adaSDoug Wyatt return; 14567fe43adaSDoug Wyatt 14577fe43adaSDoug Wyatt if (hasUncompilableErrorOccurred()) 14587fe43adaSDoug Wyatt return; 14597fe43adaSDoug Wyatt 14607fe43adaSDoug Wyatt // For code in dependent contexts, we'll do this at instantiation time. 14617fe43adaSDoug Wyatt // Without this check, we would analyze the function based on placeholder 14627fe43adaSDoug Wyatt // template parameters, and potentially generate spurious diagnostics. 14637fe43adaSDoug Wyatt if (cast<DeclContext>(D)->isDependentContext()) 14647fe43adaSDoug Wyatt return; 14657fe43adaSDoug Wyatt 14667fe43adaSDoug Wyatt addDeclWithEffects(D, FX); 14677fe43adaSDoug Wyatt } 14687fe43adaSDoug Wyatt 14697fe43adaSDoug Wyatt void Sema::addDeclWithEffects(const Decl *D, const FunctionEffectsRef &FX) { 14707fe43adaSDoug Wyatt // To avoid the possibility of conflict, don't add effects which are 14717fe43adaSDoug Wyatt // not FE_InferrableOnCallees and therefore not verified; this removes 14727fe43adaSDoug Wyatt // blocking/allocating but keeps nonblocking/nonallocating. 14737fe43adaSDoug Wyatt // Also, ignore any conditions when building the list of effects. 14747fe43adaSDoug Wyatt bool AnyVerifiable = false; 14757fe43adaSDoug Wyatt for (const FunctionEffectWithCondition &EC : FX) 14767fe43adaSDoug Wyatt if (EC.Effect.flags() & FunctionEffect::FE_InferrableOnCallees) { 14777fe43adaSDoug Wyatt AllEffectsToVerify.insert(EC.Effect); 14787fe43adaSDoug Wyatt AnyVerifiable = true; 14797fe43adaSDoug Wyatt } 14807fe43adaSDoug Wyatt 14817fe43adaSDoug Wyatt // Record the declaration for later analysis. 14827fe43adaSDoug Wyatt if (AnyVerifiable) 14837fe43adaSDoug Wyatt DeclsWithEffectsToVerify.push_back(D); 14847fe43adaSDoug Wyatt } 14857fe43adaSDoug Wyatt 14867fe43adaSDoug Wyatt void Sema::performFunctionEffectAnalysis(TranslationUnitDecl *TU) { 14877fe43adaSDoug Wyatt if (hasUncompilableErrorOccurred() || Diags.getIgnoreAllWarnings()) 14887fe43adaSDoug Wyatt return; 14897fe43adaSDoug Wyatt if (TU == nullptr) 14907fe43adaSDoug Wyatt return; 14917fe43adaSDoug Wyatt Analyzer{*this}.run(*TU); 14927fe43adaSDoug Wyatt } 14937fe43adaSDoug Wyatt 14947fe43adaSDoug Wyatt Sema::FunctionEffectDiffVector::FunctionEffectDiffVector( 14957fe43adaSDoug Wyatt const FunctionEffectsRef &Old, const FunctionEffectsRef &New) { 14967fe43adaSDoug Wyatt 14977fe43adaSDoug Wyatt FunctionEffectsRef::iterator POld = Old.begin(); 14987fe43adaSDoug Wyatt FunctionEffectsRef::iterator OldEnd = Old.end(); 14997fe43adaSDoug Wyatt FunctionEffectsRef::iterator PNew = New.begin(); 15007fe43adaSDoug Wyatt FunctionEffectsRef::iterator NewEnd = New.end(); 15017fe43adaSDoug Wyatt 15027fe43adaSDoug Wyatt while (true) { 15037fe43adaSDoug Wyatt int cmp = 0; 15047fe43adaSDoug Wyatt if (POld == OldEnd) { 15057fe43adaSDoug Wyatt if (PNew == NewEnd) 15067fe43adaSDoug Wyatt break; 15077fe43adaSDoug Wyatt cmp = 1; 15087fe43adaSDoug Wyatt } else if (PNew == NewEnd) 15097fe43adaSDoug Wyatt cmp = -1; 15107fe43adaSDoug Wyatt else { 15117fe43adaSDoug Wyatt FunctionEffectWithCondition Old = *POld; 15127fe43adaSDoug Wyatt FunctionEffectWithCondition New = *PNew; 15137fe43adaSDoug Wyatt if (Old.Effect.kind() < New.Effect.kind()) 15147fe43adaSDoug Wyatt cmp = -1; 15157fe43adaSDoug Wyatt else if (New.Effect.kind() < Old.Effect.kind()) 15167fe43adaSDoug Wyatt cmp = 1; 15177fe43adaSDoug Wyatt else { 15187fe43adaSDoug Wyatt cmp = 0; 15197fe43adaSDoug Wyatt if (Old.Cond.getCondition() != New.Cond.getCondition()) { 15207fe43adaSDoug Wyatt // FIXME: Cases where the expressions are equivalent but 15217fe43adaSDoug Wyatt // don't have the same identity. 15227fe43adaSDoug Wyatt push_back(FunctionEffectDiff{ 15237fe43adaSDoug Wyatt Old.Effect.kind(), FunctionEffectDiff::Kind::ConditionMismatch, 15247fe43adaSDoug Wyatt Old, New}); 15257fe43adaSDoug Wyatt } 15267fe43adaSDoug Wyatt } 15277fe43adaSDoug Wyatt } 15287fe43adaSDoug Wyatt 15297fe43adaSDoug Wyatt if (cmp < 0) { 15307fe43adaSDoug Wyatt // removal 15317fe43adaSDoug Wyatt FunctionEffectWithCondition Old = *POld; 15327fe43adaSDoug Wyatt push_back(FunctionEffectDiff{Old.Effect.kind(), 15337fe43adaSDoug Wyatt FunctionEffectDiff::Kind::Removed, Old, 15347fe43adaSDoug Wyatt std::nullopt}); 15357fe43adaSDoug Wyatt ++POld; 15367fe43adaSDoug Wyatt } else if (cmp > 0) { 15377fe43adaSDoug Wyatt // addition 15387fe43adaSDoug Wyatt FunctionEffectWithCondition New = *PNew; 15397fe43adaSDoug Wyatt push_back(FunctionEffectDiff{New.Effect.kind(), 15407fe43adaSDoug Wyatt FunctionEffectDiff::Kind::Added, 15417fe43adaSDoug Wyatt std::nullopt, New}); 15427fe43adaSDoug Wyatt ++PNew; 15437fe43adaSDoug Wyatt } else { 15447fe43adaSDoug Wyatt ++POld; 15457fe43adaSDoug Wyatt ++PNew; 15467fe43adaSDoug Wyatt } 15477fe43adaSDoug Wyatt } 15487fe43adaSDoug Wyatt } 15497fe43adaSDoug Wyatt 15507fe43adaSDoug Wyatt bool Sema::FunctionEffectDiff::shouldDiagnoseConversion( 15517fe43adaSDoug Wyatt QualType SrcType, const FunctionEffectsRef &SrcFX, QualType DstType, 15527fe43adaSDoug Wyatt const FunctionEffectsRef &DstFX) const { 15537fe43adaSDoug Wyatt 15547fe43adaSDoug Wyatt switch (EffectKind) { 15557fe43adaSDoug Wyatt case FunctionEffect::Kind::NonAllocating: 15567fe43adaSDoug Wyatt // nonallocating can't be added (spoofed) during a conversion, unless we 15577fe43adaSDoug Wyatt // have nonblocking. 15587fe43adaSDoug Wyatt if (DiffKind == Kind::Added) { 15597fe43adaSDoug Wyatt for (const auto &CFE : SrcFX) { 15607fe43adaSDoug Wyatt if (CFE.Effect.kind() == FunctionEffect::Kind::NonBlocking) 15617fe43adaSDoug Wyatt return false; 15627fe43adaSDoug Wyatt } 15637fe43adaSDoug Wyatt } 15647fe43adaSDoug Wyatt [[fallthrough]]; 15657fe43adaSDoug Wyatt case FunctionEffect::Kind::NonBlocking: 15667fe43adaSDoug Wyatt // nonblocking can't be added (spoofed) during a conversion. 15677fe43adaSDoug Wyatt switch (DiffKind) { 15687fe43adaSDoug Wyatt case Kind::Added: 15697fe43adaSDoug Wyatt return true; 15707fe43adaSDoug Wyatt case Kind::Removed: 15717fe43adaSDoug Wyatt return false; 15727fe43adaSDoug Wyatt case Kind::ConditionMismatch: 15737fe43adaSDoug Wyatt // FIXME: Condition mismatches are too coarse right now -- expressions 15747fe43adaSDoug Wyatt // which are equivalent but don't have the same identity are detected as 15757fe43adaSDoug Wyatt // mismatches. We're going to diagnose those anyhow until expression 15767fe43adaSDoug Wyatt // matching is better. 15777fe43adaSDoug Wyatt return true; 15787fe43adaSDoug Wyatt } 157919aa4c85SJinsong Ji break; 15807fe43adaSDoug Wyatt case FunctionEffect::Kind::Blocking: 15817fe43adaSDoug Wyatt case FunctionEffect::Kind::Allocating: 15827fe43adaSDoug Wyatt return false; 15837fe43adaSDoug Wyatt } 15847fe43adaSDoug Wyatt llvm_unreachable("unknown effect kind"); 15857fe43adaSDoug Wyatt } 15867fe43adaSDoug Wyatt 15877fe43adaSDoug Wyatt bool Sema::FunctionEffectDiff::shouldDiagnoseRedeclaration( 15887fe43adaSDoug Wyatt const FunctionDecl &OldFunction, const FunctionEffectsRef &OldFX, 15897fe43adaSDoug Wyatt const FunctionDecl &NewFunction, const FunctionEffectsRef &NewFX) const { 15907fe43adaSDoug Wyatt switch (EffectKind) { 15917fe43adaSDoug Wyatt case FunctionEffect::Kind::NonAllocating: 15927fe43adaSDoug Wyatt case FunctionEffect::Kind::NonBlocking: 15937fe43adaSDoug Wyatt // nonblocking/nonallocating can't be removed in a redeclaration. 15947fe43adaSDoug Wyatt switch (DiffKind) { 15957fe43adaSDoug Wyatt case Kind::Added: 15967fe43adaSDoug Wyatt return false; // No diagnostic. 15977fe43adaSDoug Wyatt case Kind::Removed: 15987fe43adaSDoug Wyatt return true; // Issue diagnostic. 15997fe43adaSDoug Wyatt case Kind::ConditionMismatch: 16007fe43adaSDoug Wyatt // All these forms of mismatches are diagnosed. 16017fe43adaSDoug Wyatt return true; 16027fe43adaSDoug Wyatt } 160319aa4c85SJinsong Ji break; 16047fe43adaSDoug Wyatt case FunctionEffect::Kind::Blocking: 16057fe43adaSDoug Wyatt case FunctionEffect::Kind::Allocating: 16067fe43adaSDoug Wyatt return false; 16077fe43adaSDoug Wyatt } 16087fe43adaSDoug Wyatt llvm_unreachable("unknown effect kind"); 16097fe43adaSDoug Wyatt } 16107fe43adaSDoug Wyatt 16117fe43adaSDoug Wyatt Sema::FunctionEffectDiff::OverrideResult 16127fe43adaSDoug Wyatt Sema::FunctionEffectDiff::shouldDiagnoseMethodOverride( 16137fe43adaSDoug Wyatt const CXXMethodDecl &OldMethod, const FunctionEffectsRef &OldFX, 16147fe43adaSDoug Wyatt const CXXMethodDecl &NewMethod, const FunctionEffectsRef &NewFX) const { 16157fe43adaSDoug Wyatt switch (EffectKind) { 16167fe43adaSDoug Wyatt case FunctionEffect::Kind::NonAllocating: 16177fe43adaSDoug Wyatt case FunctionEffect::Kind::NonBlocking: 16187fe43adaSDoug Wyatt switch (DiffKind) { 16197fe43adaSDoug Wyatt 16207fe43adaSDoug Wyatt // If added on an override, that's fine and not diagnosed. 16217fe43adaSDoug Wyatt case Kind::Added: 16227fe43adaSDoug Wyatt return OverrideResult::NoAction; 16237fe43adaSDoug Wyatt 16247fe43adaSDoug Wyatt // If missing from an override (removed), propagate from base to derived. 16257fe43adaSDoug Wyatt case Kind::Removed: 16267fe43adaSDoug Wyatt return OverrideResult::Merge; 16277fe43adaSDoug Wyatt 16287fe43adaSDoug Wyatt // If there's a mismatch involving the effect's polarity or condition, 16297fe43adaSDoug Wyatt // issue a warning. 16307fe43adaSDoug Wyatt case Kind::ConditionMismatch: 16317fe43adaSDoug Wyatt return OverrideResult::Warn; 16327fe43adaSDoug Wyatt } 163319aa4c85SJinsong Ji break; 16347fe43adaSDoug Wyatt case FunctionEffect::Kind::Blocking: 16357fe43adaSDoug Wyatt case FunctionEffect::Kind::Allocating: 16367fe43adaSDoug Wyatt return OverrideResult::NoAction; 16377fe43adaSDoug Wyatt } 16387fe43adaSDoug Wyatt llvm_unreachable("unknown effect kind"); 16397fe43adaSDoug Wyatt } 16407fe43adaSDoug Wyatt 16417fe43adaSDoug Wyatt } // namespace clang 1642