xref: /llvm-project/clang/lib/Sema/SemaFunctionEffects.cpp (revision 286f8423c5e26df0743e47931d840b6226ae6a8c)
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