1*700637cbSDimitry Andric //=== SemaFunctionEffects.cpp - Sema handling of function effects ---------===//
2*700637cbSDimitry Andric //
3*700637cbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*700637cbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*700637cbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*700637cbSDimitry Andric //
7*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
8*700637cbSDimitry Andric //
9*700637cbSDimitry Andric // This file implements Sema handling of function effects.
10*700637cbSDimitry Andric //
11*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
12*700637cbSDimitry Andric
13*700637cbSDimitry Andric #include "clang/AST/Decl.h"
14*700637cbSDimitry Andric #include "clang/AST/DeclCXX.h"
15*700637cbSDimitry Andric #include "clang/AST/DynamicRecursiveASTVisitor.h"
16*700637cbSDimitry Andric #include "clang/AST/ExprObjC.h"
17*700637cbSDimitry Andric #include "clang/AST/Stmt.h"
18*700637cbSDimitry Andric #include "clang/AST/StmtObjC.h"
19*700637cbSDimitry Andric #include "clang/AST/Type.h"
20*700637cbSDimitry Andric #include "clang/Basic/SourceManager.h"
21*700637cbSDimitry Andric #include "clang/Sema/SemaInternal.h"
22*700637cbSDimitry Andric
23*700637cbSDimitry Andric #define DEBUG_TYPE "effectanalysis"
24*700637cbSDimitry Andric
25*700637cbSDimitry Andric using namespace clang;
26*700637cbSDimitry Andric
27*700637cbSDimitry Andric namespace {
28*700637cbSDimitry Andric
29*700637cbSDimitry Andric enum class ViolationID : uint8_t {
30*700637cbSDimitry Andric None = 0, // Sentinel for an empty Violation.
31*700637cbSDimitry Andric // These first 5 map to a %select{} in one of several FunctionEffects
32*700637cbSDimitry Andric // diagnostics, e.g. warn_func_effect_violation.
33*700637cbSDimitry Andric BaseDiagnosticIndex,
34*700637cbSDimitry Andric AllocatesMemory = BaseDiagnosticIndex,
35*700637cbSDimitry Andric ThrowsOrCatchesExceptions,
36*700637cbSDimitry Andric HasStaticLocalVariable,
37*700637cbSDimitry Andric AccessesThreadLocalVariable,
38*700637cbSDimitry Andric AccessesObjCMethodOrProperty,
39*700637cbSDimitry Andric
40*700637cbSDimitry Andric // These only apply to callees, where the analysis stops at the Decl.
41*700637cbSDimitry Andric DeclDisallowsInference,
42*700637cbSDimitry Andric
43*700637cbSDimitry Andric // These both apply to indirect calls. The difference is that sometimes
44*700637cbSDimitry Andric // we have an actual Decl (generally a variable) which is the function
45*700637cbSDimitry Andric // pointer being called, and sometimes, typically due to a cast, we only
46*700637cbSDimitry Andric // have an expression.
47*700637cbSDimitry Andric CallsDeclWithoutEffect,
48*700637cbSDimitry Andric CallsExprWithoutEffect,
49*700637cbSDimitry Andric };
50*700637cbSDimitry Andric
51*700637cbSDimitry Andric // Information about the AST context in which a violation was found, so
52*700637cbSDimitry Andric // that diagnostics can point to the correct source.
53*700637cbSDimitry Andric class ViolationSite {
54*700637cbSDimitry Andric public:
55*700637cbSDimitry Andric enum class Kind : uint8_t {
56*700637cbSDimitry Andric Default, // Function body.
57*700637cbSDimitry Andric MemberInitializer,
58*700637cbSDimitry Andric DefaultArgExpr
59*700637cbSDimitry Andric };
60*700637cbSDimitry Andric
61*700637cbSDimitry Andric private:
62*700637cbSDimitry Andric llvm::PointerIntPair<CXXDefaultArgExpr *, 2, Kind> Impl;
63*700637cbSDimitry Andric
64*700637cbSDimitry Andric public:
65*700637cbSDimitry Andric ViolationSite() = default;
66*700637cbSDimitry Andric
ViolationSite(CXXDefaultArgExpr * E)67*700637cbSDimitry Andric explicit ViolationSite(CXXDefaultArgExpr *E)
68*700637cbSDimitry Andric : Impl(E, Kind::DefaultArgExpr) {}
69*700637cbSDimitry Andric
kind() const70*700637cbSDimitry Andric Kind kind() const { return static_cast<Kind>(Impl.getInt()); }
defaultArgExpr() const71*700637cbSDimitry Andric CXXDefaultArgExpr *defaultArgExpr() const { return Impl.getPointer(); }
72*700637cbSDimitry Andric
setKind(Kind K)73*700637cbSDimitry Andric void setKind(Kind K) { Impl.setPointerAndInt(nullptr, K); }
74*700637cbSDimitry Andric };
75*700637cbSDimitry Andric
76*700637cbSDimitry Andric // Represents a violation of the rules, potentially for the entire duration of
77*700637cbSDimitry Andric // the analysis phase, in order to refer to it when explaining why a caller has
78*700637cbSDimitry Andric // been made unsafe by a callee. Can be transformed into either a Diagnostic
79*700637cbSDimitry Andric // (warning or a note), depending on whether the violation pertains to a
80*700637cbSDimitry Andric // function failing to be verifed as holding an effect vs. a function failing to
81*700637cbSDimitry Andric // be inferred as holding that effect.
82*700637cbSDimitry Andric struct Violation {
83*700637cbSDimitry Andric FunctionEffect Effect;
84*700637cbSDimitry Andric std::optional<FunctionEffect>
85*700637cbSDimitry Andric CalleeEffectPreventingInference; // Only for certain IDs; can be nullopt.
86*700637cbSDimitry Andric ViolationID ID = ViolationID::None;
87*700637cbSDimitry Andric ViolationSite Site;
88*700637cbSDimitry Andric SourceLocation Loc;
89*700637cbSDimitry Andric const Decl *Callee =
90*700637cbSDimitry Andric nullptr; // Only valid for ViolationIDs Calls{Decl,Expr}WithoutEffect.
91*700637cbSDimitry Andric
Violation__anon1adc617b0111::Violation92*700637cbSDimitry Andric Violation(FunctionEffect Effect, ViolationID ID, ViolationSite VS,
93*700637cbSDimitry Andric SourceLocation Loc, const Decl *Callee = nullptr,
94*700637cbSDimitry Andric std::optional<FunctionEffect> CalleeEffect = std::nullopt)
95*700637cbSDimitry Andric : Effect(Effect), CalleeEffectPreventingInference(CalleeEffect), ID(ID),
96*700637cbSDimitry Andric Site(VS), Loc(Loc), Callee(Callee) {}
97*700637cbSDimitry Andric
diagnosticSelectIndex__anon1adc617b0111::Violation98*700637cbSDimitry Andric unsigned diagnosticSelectIndex() const {
99*700637cbSDimitry Andric return unsigned(ID) - unsigned(ViolationID::BaseDiagnosticIndex);
100*700637cbSDimitry Andric }
101*700637cbSDimitry Andric };
102*700637cbSDimitry Andric
103*700637cbSDimitry Andric enum class SpecialFuncType : uint8_t { None, OperatorNew, OperatorDelete };
104*700637cbSDimitry Andric enum class CallableType : uint8_t {
105*700637cbSDimitry Andric // Unknown: probably function pointer.
106*700637cbSDimitry Andric Unknown,
107*700637cbSDimitry Andric Function,
108*700637cbSDimitry Andric Virtual,
109*700637cbSDimitry Andric Block
110*700637cbSDimitry Andric };
111*700637cbSDimitry Andric
112*700637cbSDimitry Andric // Return whether a function's effects CAN be verified.
113*700637cbSDimitry Andric // The question of whether it SHOULD be verified is independent.
functionIsVerifiable(const FunctionDecl * FD)114*700637cbSDimitry Andric static bool functionIsVerifiable(const FunctionDecl *FD) {
115*700637cbSDimitry Andric if (FD->isTrivial()) {
116*700637cbSDimitry Andric // Otherwise `struct x { int a; };` would have an unverifiable default
117*700637cbSDimitry Andric // constructor.
118*700637cbSDimitry Andric return true;
119*700637cbSDimitry Andric }
120*700637cbSDimitry Andric return FD->hasBody();
121*700637cbSDimitry Andric }
122*700637cbSDimitry Andric
isNoexcept(const FunctionDecl * FD)123*700637cbSDimitry Andric static bool isNoexcept(const FunctionDecl *FD) {
124*700637cbSDimitry Andric const auto *FPT = FD->getType()->getAs<FunctionProtoType>();
125*700637cbSDimitry Andric return FPT && (FPT->isNothrow() || FD->hasAttr<NoThrowAttr>());
126*700637cbSDimitry Andric }
127*700637cbSDimitry Andric
128*700637cbSDimitry Andric // This list is probably incomplete.
129*700637cbSDimitry Andric // FIXME: Investigate:
130*700637cbSDimitry Andric // __builtin_eh_return?
131*700637cbSDimitry Andric // __builtin_allow_runtime_check?
132*700637cbSDimitry Andric // __builtin_unwind_init and other similar things that sound exception-related.
133*700637cbSDimitry Andric // va_copy?
134*700637cbSDimitry Andric // coroutines?
getBuiltinFunctionEffects(unsigned BuiltinID)135*700637cbSDimitry Andric static FunctionEffectKindSet getBuiltinFunctionEffects(unsigned BuiltinID) {
136*700637cbSDimitry Andric FunctionEffectKindSet Result;
137*700637cbSDimitry Andric
138*700637cbSDimitry Andric switch (BuiltinID) {
139*700637cbSDimitry Andric case 0: // Not builtin.
140*700637cbSDimitry Andric default: // By default, builtins have no known effects.
141*700637cbSDimitry Andric break;
142*700637cbSDimitry Andric
143*700637cbSDimitry Andric // These allocate/deallocate heap memory.
144*700637cbSDimitry Andric case Builtin::ID::BI__builtin_calloc:
145*700637cbSDimitry Andric case Builtin::ID::BI__builtin_malloc:
146*700637cbSDimitry Andric case Builtin::ID::BI__builtin_realloc:
147*700637cbSDimitry Andric case Builtin::ID::BI__builtin_free:
148*700637cbSDimitry Andric case Builtin::ID::BI__builtin_operator_delete:
149*700637cbSDimitry Andric case Builtin::ID::BI__builtin_operator_new:
150*700637cbSDimitry Andric case Builtin::ID::BIaligned_alloc:
151*700637cbSDimitry Andric case Builtin::ID::BIcalloc:
152*700637cbSDimitry Andric case Builtin::ID::BImalloc:
153*700637cbSDimitry Andric case Builtin::ID::BImemalign:
154*700637cbSDimitry Andric case Builtin::ID::BIrealloc:
155*700637cbSDimitry Andric case Builtin::ID::BIfree:
156*700637cbSDimitry Andric
157*700637cbSDimitry Andric case Builtin::ID::BIfopen:
158*700637cbSDimitry Andric case Builtin::ID::BIpthread_create:
159*700637cbSDimitry Andric case Builtin::ID::BI_Block_object_dispose:
160*700637cbSDimitry Andric Result.insert(FunctionEffect(FunctionEffect::Kind::Allocating));
161*700637cbSDimitry Andric break;
162*700637cbSDimitry Andric
163*700637cbSDimitry Andric // These block in some other way than allocating memory.
164*700637cbSDimitry Andric // longjmp() and friends are presumed unsafe because they are the moral
165*700637cbSDimitry Andric // equivalent of throwing a C++ exception, which is unsafe.
166*700637cbSDimitry Andric case Builtin::ID::BIlongjmp:
167*700637cbSDimitry Andric case Builtin::ID::BI_longjmp:
168*700637cbSDimitry Andric case Builtin::ID::BIsiglongjmp:
169*700637cbSDimitry Andric case Builtin::ID::BI__builtin_longjmp:
170*700637cbSDimitry Andric case Builtin::ID::BIobjc_exception_throw:
171*700637cbSDimitry Andric
172*700637cbSDimitry Andric // Objective-C runtime.
173*700637cbSDimitry Andric case Builtin::ID::BIobjc_msgSend:
174*700637cbSDimitry Andric case Builtin::ID::BIobjc_msgSend_fpret:
175*700637cbSDimitry Andric case Builtin::ID::BIobjc_msgSend_fp2ret:
176*700637cbSDimitry Andric case Builtin::ID::BIobjc_msgSend_stret:
177*700637cbSDimitry Andric case Builtin::ID::BIobjc_msgSendSuper:
178*700637cbSDimitry Andric case Builtin::ID::BIobjc_getClass:
179*700637cbSDimitry Andric case Builtin::ID::BIobjc_getMetaClass:
180*700637cbSDimitry Andric case Builtin::ID::BIobjc_enumerationMutation:
181*700637cbSDimitry Andric case Builtin::ID::BIobjc_assign_ivar:
182*700637cbSDimitry Andric case Builtin::ID::BIobjc_assign_global:
183*700637cbSDimitry Andric case Builtin::ID::BIobjc_sync_enter:
184*700637cbSDimitry Andric case Builtin::ID::BIobjc_sync_exit:
185*700637cbSDimitry Andric case Builtin::ID::BINSLog:
186*700637cbSDimitry Andric case Builtin::ID::BINSLogv:
187*700637cbSDimitry Andric
188*700637cbSDimitry Andric // stdio.h
189*700637cbSDimitry Andric case Builtin::ID::BIfread:
190*700637cbSDimitry Andric case Builtin::ID::BIfwrite:
191*700637cbSDimitry Andric
192*700637cbSDimitry Andric // stdio.h: printf family.
193*700637cbSDimitry Andric case Builtin::ID::BIprintf:
194*700637cbSDimitry Andric case Builtin::ID::BI__builtin_printf:
195*700637cbSDimitry Andric case Builtin::ID::BIfprintf:
196*700637cbSDimitry Andric case Builtin::ID::BIsnprintf:
197*700637cbSDimitry Andric case Builtin::ID::BIsprintf:
198*700637cbSDimitry Andric case Builtin::ID::BIvprintf:
199*700637cbSDimitry Andric case Builtin::ID::BIvfprintf:
200*700637cbSDimitry Andric case Builtin::ID::BIvsnprintf:
201*700637cbSDimitry Andric case Builtin::ID::BIvsprintf:
202*700637cbSDimitry Andric
203*700637cbSDimitry Andric // stdio.h: scanf family.
204*700637cbSDimitry Andric case Builtin::ID::BIscanf:
205*700637cbSDimitry Andric case Builtin::ID::BIfscanf:
206*700637cbSDimitry Andric case Builtin::ID::BIsscanf:
207*700637cbSDimitry Andric case Builtin::ID::BIvscanf:
208*700637cbSDimitry Andric case Builtin::ID::BIvfscanf:
209*700637cbSDimitry Andric case Builtin::ID::BIvsscanf:
210*700637cbSDimitry Andric Result.insert(FunctionEffect(FunctionEffect::Kind::Blocking));
211*700637cbSDimitry Andric break;
212*700637cbSDimitry Andric }
213*700637cbSDimitry Andric
214*700637cbSDimitry Andric return Result;
215*700637cbSDimitry Andric }
216*700637cbSDimitry Andric
217*700637cbSDimitry Andric // Transitory, more extended information about a callable, which can be a
218*700637cbSDimitry Andric // function, block, or function pointer.
219*700637cbSDimitry Andric struct CallableInfo {
220*700637cbSDimitry Andric // CDecl holds the function's definition, if any.
221*700637cbSDimitry Andric // FunctionDecl if CallableType::Function or Virtual
222*700637cbSDimitry Andric // BlockDecl if CallableType::Block
223*700637cbSDimitry Andric const Decl *CDecl;
224*700637cbSDimitry Andric
225*700637cbSDimitry Andric // Remember whether the callable is a function, block, virtual method,
226*700637cbSDimitry Andric // or (presumed) function pointer.
227*700637cbSDimitry Andric CallableType CType = CallableType::Unknown;
228*700637cbSDimitry Andric
229*700637cbSDimitry Andric // Remember whether the callable is an operator new or delete function,
230*700637cbSDimitry Andric // so that calls to them are reported more meaningfully, as memory
231*700637cbSDimitry Andric // allocations.
232*700637cbSDimitry Andric SpecialFuncType FuncType = SpecialFuncType::None;
233*700637cbSDimitry Andric
234*700637cbSDimitry Andric // We inevitably want to know the callable's declared effects, so cache them.
235*700637cbSDimitry Andric FunctionEffectKindSet Effects;
236*700637cbSDimitry Andric
CallableInfo__anon1adc617b0111::CallableInfo237*700637cbSDimitry Andric CallableInfo(const Decl &CD, SpecialFuncType FT = SpecialFuncType::None)
238*700637cbSDimitry Andric : CDecl(&CD), FuncType(FT) {
239*700637cbSDimitry Andric FunctionEffectsRef DeclEffects;
240*700637cbSDimitry Andric if (auto *FD = dyn_cast<FunctionDecl>(CDecl)) {
241*700637cbSDimitry Andric // Use the function's definition, if any.
242*700637cbSDimitry Andric if (const FunctionDecl *Def = FD->getDefinition())
243*700637cbSDimitry Andric CDecl = FD = Def;
244*700637cbSDimitry Andric CType = CallableType::Function;
245*700637cbSDimitry Andric if (auto *Method = dyn_cast<CXXMethodDecl>(FD);
246*700637cbSDimitry Andric Method && Method->isVirtual())
247*700637cbSDimitry Andric CType = CallableType::Virtual;
248*700637cbSDimitry Andric DeclEffects = FD->getFunctionEffects();
249*700637cbSDimitry Andric } else if (auto *BD = dyn_cast<BlockDecl>(CDecl)) {
250*700637cbSDimitry Andric CType = CallableType::Block;
251*700637cbSDimitry Andric DeclEffects = BD->getFunctionEffects();
252*700637cbSDimitry Andric } else if (auto *VD = dyn_cast<ValueDecl>(CDecl)) {
253*700637cbSDimitry Andric // ValueDecl is function, enum, or variable, so just look at its type.
254*700637cbSDimitry Andric DeclEffects = FunctionEffectsRef::get(VD->getType());
255*700637cbSDimitry Andric }
256*700637cbSDimitry Andric Effects = FunctionEffectKindSet(DeclEffects);
257*700637cbSDimitry Andric }
258*700637cbSDimitry Andric
type__anon1adc617b0111::CallableInfo259*700637cbSDimitry Andric CallableType type() const { return CType; }
260*700637cbSDimitry Andric
isCalledDirectly__anon1adc617b0111::CallableInfo261*700637cbSDimitry Andric bool isCalledDirectly() const {
262*700637cbSDimitry Andric return CType == CallableType::Function || CType == CallableType::Block;
263*700637cbSDimitry Andric }
264*700637cbSDimitry Andric
isVerifiable__anon1adc617b0111::CallableInfo265*700637cbSDimitry Andric bool isVerifiable() const {
266*700637cbSDimitry Andric switch (CType) {
267*700637cbSDimitry Andric case CallableType::Unknown:
268*700637cbSDimitry Andric case CallableType::Virtual:
269*700637cbSDimitry Andric return false;
270*700637cbSDimitry Andric case CallableType::Block:
271*700637cbSDimitry Andric return true;
272*700637cbSDimitry Andric case CallableType::Function:
273*700637cbSDimitry Andric return functionIsVerifiable(dyn_cast<FunctionDecl>(CDecl));
274*700637cbSDimitry Andric }
275*700637cbSDimitry Andric llvm_unreachable("undefined CallableType");
276*700637cbSDimitry Andric }
277*700637cbSDimitry Andric
278*700637cbSDimitry Andric /// Generate a name for logging and diagnostics.
getNameForDiagnostic__anon1adc617b0111::CallableInfo279*700637cbSDimitry Andric std::string getNameForDiagnostic(Sema &S) const {
280*700637cbSDimitry Andric std::string Name;
281*700637cbSDimitry Andric llvm::raw_string_ostream OS(Name);
282*700637cbSDimitry Andric
283*700637cbSDimitry Andric if (auto *FD = dyn_cast<FunctionDecl>(CDecl))
284*700637cbSDimitry Andric FD->getNameForDiagnostic(OS, S.getPrintingPolicy(),
285*700637cbSDimitry Andric /*Qualified=*/true);
286*700637cbSDimitry Andric else if (auto *BD = dyn_cast<BlockDecl>(CDecl))
287*700637cbSDimitry Andric OS << "(block " << BD->getBlockManglingNumber() << ")";
288*700637cbSDimitry Andric else if (auto *VD = dyn_cast<NamedDecl>(CDecl))
289*700637cbSDimitry Andric VD->printQualifiedName(OS);
290*700637cbSDimitry Andric return Name;
291*700637cbSDimitry Andric }
292*700637cbSDimitry Andric };
293*700637cbSDimitry Andric
294*700637cbSDimitry Andric // ----------
295*700637cbSDimitry Andric // Map effects to single Violations, to hold the first (of potentially many)
296*700637cbSDimitry Andric // violations pertaining to an effect, per function.
297*700637cbSDimitry Andric class EffectToViolationMap {
298*700637cbSDimitry Andric // Since we currently only have a tiny number of effects (typically no more
299*700637cbSDimitry Andric // than 1), use a SmallVector with an inline capacity of 1. Since it
300*700637cbSDimitry Andric // is often empty, use a unique_ptr to the SmallVector.
301*700637cbSDimitry Andric // Note that Violation itself contains a FunctionEffect which is the key.
302*700637cbSDimitry Andric // FIXME: Is there a way to simplify this using existing data structures?
303*700637cbSDimitry Andric using ImplVec = llvm::SmallVector<Violation, 1>;
304*700637cbSDimitry Andric std::unique_ptr<ImplVec> Impl;
305*700637cbSDimitry Andric
306*700637cbSDimitry Andric public:
307*700637cbSDimitry Andric // Insert a new Violation if we do not already have one for its effect.
maybeInsert(const Violation & Viol)308*700637cbSDimitry Andric void maybeInsert(const Violation &Viol) {
309*700637cbSDimitry Andric if (Impl == nullptr)
310*700637cbSDimitry Andric Impl = std::make_unique<ImplVec>();
311*700637cbSDimitry Andric else if (lookup(Viol.Effect) != nullptr)
312*700637cbSDimitry Andric return;
313*700637cbSDimitry Andric
314*700637cbSDimitry Andric Impl->push_back(Viol);
315*700637cbSDimitry Andric }
316*700637cbSDimitry Andric
lookup(FunctionEffect Key)317*700637cbSDimitry Andric const Violation *lookup(FunctionEffect Key) {
318*700637cbSDimitry Andric if (Impl == nullptr)
319*700637cbSDimitry Andric return nullptr;
320*700637cbSDimitry Andric
321*700637cbSDimitry Andric auto *Iter = llvm::find_if(
322*700637cbSDimitry Andric *Impl, [&](const auto &Item) { return Item.Effect == Key; });
323*700637cbSDimitry Andric return Iter != Impl->end() ? &*Iter : nullptr;
324*700637cbSDimitry Andric }
325*700637cbSDimitry Andric
size() const326*700637cbSDimitry Andric size_t size() const { return Impl ? Impl->size() : 0; }
327*700637cbSDimitry Andric };
328*700637cbSDimitry Andric
329*700637cbSDimitry Andric // ----------
330*700637cbSDimitry Andric // State pertaining to a function whose AST is walked and whose effect analysis
331*700637cbSDimitry Andric // is dependent on a subsequent analysis of other functions.
332*700637cbSDimitry Andric class PendingFunctionAnalysis {
333*700637cbSDimitry Andric friend class CompleteFunctionAnalysis;
334*700637cbSDimitry Andric
335*700637cbSDimitry Andric public:
336*700637cbSDimitry Andric struct DirectCall {
337*700637cbSDimitry Andric const Decl *Callee;
338*700637cbSDimitry Andric SourceLocation CallLoc;
339*700637cbSDimitry Andric // Not all recursive calls are detected, just enough
340*700637cbSDimitry Andric // to break cycles.
341*700637cbSDimitry Andric bool Recursed = false;
342*700637cbSDimitry Andric ViolationSite VSite;
343*700637cbSDimitry Andric
DirectCall__anon1adc617b0111::PendingFunctionAnalysis::DirectCall344*700637cbSDimitry Andric DirectCall(const Decl *D, SourceLocation CallLoc, ViolationSite VSite)
345*700637cbSDimitry Andric : Callee(D), CallLoc(CallLoc), VSite(VSite) {}
346*700637cbSDimitry Andric };
347*700637cbSDimitry Andric
348*700637cbSDimitry Andric // We always have two disjoint sets of effects to verify:
349*700637cbSDimitry Andric // 1. Effects declared explicitly by this function.
350*700637cbSDimitry Andric // 2. All other inferrable effects needing verification.
351*700637cbSDimitry Andric FunctionEffectKindSet DeclaredVerifiableEffects;
352*700637cbSDimitry Andric FunctionEffectKindSet EffectsToInfer;
353*700637cbSDimitry Andric
354*700637cbSDimitry Andric private:
355*700637cbSDimitry Andric // Violations pertaining to the function's explicit effects.
356*700637cbSDimitry Andric SmallVector<Violation, 0> ViolationsForExplicitEffects;
357*700637cbSDimitry Andric
358*700637cbSDimitry Andric // Violations pertaining to other, non-explicit, inferrable effects.
359*700637cbSDimitry Andric EffectToViolationMap InferrableEffectToFirstViolation;
360*700637cbSDimitry Andric
361*700637cbSDimitry Andric // These unverified direct calls are what keeps the analysis "pending",
362*700637cbSDimitry Andric // until the callees can be verified.
363*700637cbSDimitry Andric SmallVector<DirectCall, 0> UnverifiedDirectCalls;
364*700637cbSDimitry Andric
365*700637cbSDimitry Andric public:
PendingFunctionAnalysis(Sema & S,const CallableInfo & CInfo,FunctionEffectKindSet AllInferrableEffectsToVerify)366*700637cbSDimitry Andric PendingFunctionAnalysis(Sema &S, const CallableInfo &CInfo,
367*700637cbSDimitry Andric FunctionEffectKindSet AllInferrableEffectsToVerify)
368*700637cbSDimitry Andric : DeclaredVerifiableEffects(CInfo.Effects) {
369*700637cbSDimitry Andric // Check for effects we are not allowed to infer.
370*700637cbSDimitry Andric FunctionEffectKindSet InferrableEffects;
371*700637cbSDimitry Andric
372*700637cbSDimitry Andric for (FunctionEffect effect : AllInferrableEffectsToVerify) {
373*700637cbSDimitry Andric std::optional<FunctionEffect> ProblemCalleeEffect =
374*700637cbSDimitry Andric effect.effectProhibitingInference(*CInfo.CDecl, CInfo.Effects);
375*700637cbSDimitry Andric if (!ProblemCalleeEffect)
376*700637cbSDimitry Andric InferrableEffects.insert(effect);
377*700637cbSDimitry Andric else {
378*700637cbSDimitry Andric // Add a Violation for this effect if a caller were to
379*700637cbSDimitry Andric // try to infer it.
380*700637cbSDimitry Andric InferrableEffectToFirstViolation.maybeInsert(Violation(
381*700637cbSDimitry Andric effect, ViolationID::DeclDisallowsInference, ViolationSite{},
382*700637cbSDimitry Andric CInfo.CDecl->getLocation(), nullptr, ProblemCalleeEffect));
383*700637cbSDimitry Andric }
384*700637cbSDimitry Andric }
385*700637cbSDimitry Andric // InferrableEffects is now the set of inferrable effects which are not
386*700637cbSDimitry Andric // prohibited.
387*700637cbSDimitry Andric EffectsToInfer = FunctionEffectKindSet::difference(
388*700637cbSDimitry Andric InferrableEffects, DeclaredVerifiableEffects);
389*700637cbSDimitry Andric }
390*700637cbSDimitry Andric
391*700637cbSDimitry Andric // Hide the way that Violations for explicitly required effects vs. inferred
392*700637cbSDimitry Andric // ones are handled differently.
checkAddViolation(bool Inferring,const Violation & NewViol)393*700637cbSDimitry Andric void checkAddViolation(bool Inferring, const Violation &NewViol) {
394*700637cbSDimitry Andric if (!Inferring)
395*700637cbSDimitry Andric ViolationsForExplicitEffects.push_back(NewViol);
396*700637cbSDimitry Andric else
397*700637cbSDimitry Andric InferrableEffectToFirstViolation.maybeInsert(NewViol);
398*700637cbSDimitry Andric }
399*700637cbSDimitry Andric
addUnverifiedDirectCall(const Decl * D,SourceLocation CallLoc,ViolationSite VSite)400*700637cbSDimitry Andric void addUnverifiedDirectCall(const Decl *D, SourceLocation CallLoc,
401*700637cbSDimitry Andric ViolationSite VSite) {
402*700637cbSDimitry Andric UnverifiedDirectCalls.emplace_back(D, CallLoc, VSite);
403*700637cbSDimitry Andric }
404*700637cbSDimitry Andric
405*700637cbSDimitry Andric // Analysis is complete when there are no unverified direct calls.
isComplete() const406*700637cbSDimitry Andric bool isComplete() const { return UnverifiedDirectCalls.empty(); }
407*700637cbSDimitry Andric
violationForInferrableEffect(FunctionEffect effect)408*700637cbSDimitry Andric const Violation *violationForInferrableEffect(FunctionEffect effect) {
409*700637cbSDimitry Andric return InferrableEffectToFirstViolation.lookup(effect);
410*700637cbSDimitry Andric }
411*700637cbSDimitry Andric
412*700637cbSDimitry Andric // Mutable because caller may need to set a DirectCall's Recursing flag.
unverifiedCalls()413*700637cbSDimitry Andric MutableArrayRef<DirectCall> unverifiedCalls() {
414*700637cbSDimitry Andric assert(!isComplete());
415*700637cbSDimitry Andric return UnverifiedDirectCalls;
416*700637cbSDimitry Andric }
417*700637cbSDimitry Andric
getSortedViolationsForExplicitEffects(SourceManager & SM)418*700637cbSDimitry Andric ArrayRef<Violation> getSortedViolationsForExplicitEffects(SourceManager &SM) {
419*700637cbSDimitry Andric if (!ViolationsForExplicitEffects.empty())
420*700637cbSDimitry Andric llvm::sort(ViolationsForExplicitEffects,
421*700637cbSDimitry Andric [&SM](const Violation &LHS, const Violation &RHS) {
422*700637cbSDimitry Andric return SM.isBeforeInTranslationUnit(LHS.Loc, RHS.Loc);
423*700637cbSDimitry Andric });
424*700637cbSDimitry Andric return ViolationsForExplicitEffects;
425*700637cbSDimitry Andric }
426*700637cbSDimitry Andric
dump(Sema & SemaRef,llvm::raw_ostream & OS) const427*700637cbSDimitry Andric void dump(Sema &SemaRef, llvm::raw_ostream &OS) const {
428*700637cbSDimitry Andric OS << "Pending: Declared ";
429*700637cbSDimitry Andric DeclaredVerifiableEffects.dump(OS);
430*700637cbSDimitry Andric OS << ", " << ViolationsForExplicitEffects.size() << " violations; ";
431*700637cbSDimitry Andric OS << " Infer ";
432*700637cbSDimitry Andric EffectsToInfer.dump(OS);
433*700637cbSDimitry Andric OS << ", " << InferrableEffectToFirstViolation.size() << " violations";
434*700637cbSDimitry Andric if (!UnverifiedDirectCalls.empty()) {
435*700637cbSDimitry Andric OS << "; Calls: ";
436*700637cbSDimitry Andric for (const DirectCall &Call : UnverifiedDirectCalls) {
437*700637cbSDimitry Andric CallableInfo CI(*Call.Callee);
438*700637cbSDimitry Andric OS << " " << CI.getNameForDiagnostic(SemaRef);
439*700637cbSDimitry Andric }
440*700637cbSDimitry Andric }
441*700637cbSDimitry Andric OS << "\n";
442*700637cbSDimitry Andric }
443*700637cbSDimitry Andric };
444*700637cbSDimitry Andric
445*700637cbSDimitry Andric // ----------
446*700637cbSDimitry Andric class CompleteFunctionAnalysis {
447*700637cbSDimitry Andric // Current size: 2 pointers
448*700637cbSDimitry Andric public:
449*700637cbSDimitry Andric // Has effects which are both the declared ones -- not to be inferred -- plus
450*700637cbSDimitry Andric // ones which have been successfully inferred. These are all considered
451*700637cbSDimitry Andric // "verified" for the purposes of callers; any issue with verifying declared
452*700637cbSDimitry Andric // effects has already been reported and is not the problem of any caller.
453*700637cbSDimitry Andric FunctionEffectKindSet VerifiedEffects;
454*700637cbSDimitry Andric
455*700637cbSDimitry Andric private:
456*700637cbSDimitry Andric // This is used to generate notes about failed inference.
457*700637cbSDimitry Andric EffectToViolationMap InferrableEffectToFirstViolation;
458*700637cbSDimitry Andric
459*700637cbSDimitry Andric public:
460*700637cbSDimitry Andric // The incoming Pending analysis is consumed (member(s) are moved-from).
CompleteFunctionAnalysis(ASTContext & Ctx,PendingFunctionAnalysis && Pending,FunctionEffectKindSet DeclaredEffects,FunctionEffectKindSet AllInferrableEffectsToVerify)461*700637cbSDimitry Andric CompleteFunctionAnalysis(ASTContext &Ctx, PendingFunctionAnalysis &&Pending,
462*700637cbSDimitry Andric FunctionEffectKindSet DeclaredEffects,
463*700637cbSDimitry Andric FunctionEffectKindSet AllInferrableEffectsToVerify)
464*700637cbSDimitry Andric : VerifiedEffects(DeclaredEffects) {
465*700637cbSDimitry Andric for (FunctionEffect effect : AllInferrableEffectsToVerify)
466*700637cbSDimitry Andric if (Pending.violationForInferrableEffect(effect) == nullptr)
467*700637cbSDimitry Andric VerifiedEffects.insert(effect);
468*700637cbSDimitry Andric
469*700637cbSDimitry Andric InferrableEffectToFirstViolation =
470*700637cbSDimitry Andric std::move(Pending.InferrableEffectToFirstViolation);
471*700637cbSDimitry Andric }
472*700637cbSDimitry Andric
firstViolationForEffect(FunctionEffect Effect)473*700637cbSDimitry Andric const Violation *firstViolationForEffect(FunctionEffect Effect) {
474*700637cbSDimitry Andric return InferrableEffectToFirstViolation.lookup(Effect);
475*700637cbSDimitry Andric }
476*700637cbSDimitry Andric
dump(llvm::raw_ostream & OS) const477*700637cbSDimitry Andric void dump(llvm::raw_ostream &OS) const {
478*700637cbSDimitry Andric OS << "Complete: Verified ";
479*700637cbSDimitry Andric VerifiedEffects.dump(OS);
480*700637cbSDimitry Andric OS << "; Infer ";
481*700637cbSDimitry Andric OS << InferrableEffectToFirstViolation.size() << " violations\n";
482*700637cbSDimitry Andric }
483*700637cbSDimitry Andric };
484*700637cbSDimitry Andric
485*700637cbSDimitry Andric // ==========
486*700637cbSDimitry Andric class Analyzer {
487*700637cbSDimitry Andric Sema &S;
488*700637cbSDimitry Andric
489*700637cbSDimitry Andric // Subset of Sema.AllEffectsToVerify
490*700637cbSDimitry Andric FunctionEffectKindSet AllInferrableEffectsToVerify;
491*700637cbSDimitry Andric
492*700637cbSDimitry Andric using FuncAnalysisPtr =
493*700637cbSDimitry Andric llvm::PointerUnion<PendingFunctionAnalysis *, CompleteFunctionAnalysis *>;
494*700637cbSDimitry Andric
495*700637cbSDimitry Andric // Map all Decls analyzed to FuncAnalysisPtr. Pending state is larger
496*700637cbSDimitry Andric // than complete state, so use different objects to represent them.
497*700637cbSDimitry Andric // The state pointers are owned by the container.
498*700637cbSDimitry Andric class AnalysisMap : llvm::DenseMap<const Decl *, FuncAnalysisPtr> {
499*700637cbSDimitry Andric using Base = llvm::DenseMap<const Decl *, FuncAnalysisPtr>;
500*700637cbSDimitry Andric
501*700637cbSDimitry Andric public:
502*700637cbSDimitry Andric ~AnalysisMap();
503*700637cbSDimitry Andric
504*700637cbSDimitry Andric // Use non-public inheritance in order to maintain the invariant
505*700637cbSDimitry Andric // that lookups and insertions are via the canonical Decls.
506*700637cbSDimitry Andric
lookup(const Decl * Key) const507*700637cbSDimitry Andric FuncAnalysisPtr lookup(const Decl *Key) const {
508*700637cbSDimitry Andric return Base::lookup(Key->getCanonicalDecl());
509*700637cbSDimitry Andric }
510*700637cbSDimitry Andric
operator [](const Decl * Key)511*700637cbSDimitry Andric FuncAnalysisPtr &operator[](const Decl *Key) {
512*700637cbSDimitry Andric return Base::operator[](Key->getCanonicalDecl());
513*700637cbSDimitry Andric }
514*700637cbSDimitry Andric
515*700637cbSDimitry Andric /// Shortcut for the case where we only care about completed analysis.
completedAnalysisForDecl(const Decl * D) const516*700637cbSDimitry Andric CompleteFunctionAnalysis *completedAnalysisForDecl(const Decl *D) const {
517*700637cbSDimitry Andric if (FuncAnalysisPtr AP = lookup(D);
518*700637cbSDimitry Andric isa_and_nonnull<CompleteFunctionAnalysis *>(AP))
519*700637cbSDimitry Andric return cast<CompleteFunctionAnalysis *>(AP);
520*700637cbSDimitry Andric return nullptr;
521*700637cbSDimitry Andric }
522*700637cbSDimitry Andric
dump(Sema & SemaRef,llvm::raw_ostream & OS)523*700637cbSDimitry Andric void dump(Sema &SemaRef, llvm::raw_ostream &OS) {
524*700637cbSDimitry Andric OS << "\nAnalysisMap:\n";
525*700637cbSDimitry Andric for (const auto &item : *this) {
526*700637cbSDimitry Andric CallableInfo CI(*item.first);
527*700637cbSDimitry Andric const auto AP = item.second;
528*700637cbSDimitry Andric OS << item.first << " " << CI.getNameForDiagnostic(SemaRef) << " : ";
529*700637cbSDimitry Andric if (AP.isNull()) {
530*700637cbSDimitry Andric OS << "null\n";
531*700637cbSDimitry Andric } else if (auto *CFA = dyn_cast<CompleteFunctionAnalysis *>(AP)) {
532*700637cbSDimitry Andric OS << CFA << " ";
533*700637cbSDimitry Andric CFA->dump(OS);
534*700637cbSDimitry Andric } else if (auto *PFA = dyn_cast<PendingFunctionAnalysis *>(AP)) {
535*700637cbSDimitry Andric OS << PFA << " ";
536*700637cbSDimitry Andric PFA->dump(SemaRef, OS);
537*700637cbSDimitry Andric } else
538*700637cbSDimitry Andric llvm_unreachable("never");
539*700637cbSDimitry Andric }
540*700637cbSDimitry Andric OS << "---\n";
541*700637cbSDimitry Andric }
542*700637cbSDimitry Andric };
543*700637cbSDimitry Andric AnalysisMap DeclAnalysis;
544*700637cbSDimitry Andric
545*700637cbSDimitry Andric public:
Analyzer(Sema & S)546*700637cbSDimitry Andric Analyzer(Sema &S) : S(S) {}
547*700637cbSDimitry Andric
run(const TranslationUnitDecl & TU)548*700637cbSDimitry Andric void run(const TranslationUnitDecl &TU) {
549*700637cbSDimitry Andric // Gather all of the effects to be verified to see what operations need to
550*700637cbSDimitry Andric // be checked, and to see which ones are inferrable.
551*700637cbSDimitry Andric for (FunctionEffect Effect : S.AllEffectsToVerify) {
552*700637cbSDimitry Andric const FunctionEffect::Flags Flags = Effect.flags();
553*700637cbSDimitry Andric if (Flags & FunctionEffect::FE_InferrableOnCallees)
554*700637cbSDimitry Andric AllInferrableEffectsToVerify.insert(Effect);
555*700637cbSDimitry Andric }
556*700637cbSDimitry Andric LLVM_DEBUG(llvm::dbgs() << "AllInferrableEffectsToVerify: ";
557*700637cbSDimitry Andric AllInferrableEffectsToVerify.dump(llvm::dbgs());
558*700637cbSDimitry Andric llvm::dbgs() << "\n";);
559*700637cbSDimitry Andric
560*700637cbSDimitry Andric // We can use DeclsWithEffectsToVerify as a stack for a
561*700637cbSDimitry Andric // depth-first traversal; there's no need for a second container. But first,
562*700637cbSDimitry Andric // reverse it, so when working from the end, Decls are verified in the order
563*700637cbSDimitry Andric // they are declared.
564*700637cbSDimitry Andric SmallVector<const Decl *> &VerificationQueue = S.DeclsWithEffectsToVerify;
565*700637cbSDimitry Andric std::reverse(VerificationQueue.begin(), VerificationQueue.end());
566*700637cbSDimitry Andric
567*700637cbSDimitry Andric while (!VerificationQueue.empty()) {
568*700637cbSDimitry Andric const Decl *D = VerificationQueue.back();
569*700637cbSDimitry Andric if (FuncAnalysisPtr AP = DeclAnalysis.lookup(D)) {
570*700637cbSDimitry Andric if (auto *Pending = dyn_cast<PendingFunctionAnalysis *>(AP)) {
571*700637cbSDimitry Andric // All children have been traversed; finish analysis.
572*700637cbSDimitry Andric finishPendingAnalysis(D, Pending);
573*700637cbSDimitry Andric }
574*700637cbSDimitry Andric VerificationQueue.pop_back();
575*700637cbSDimitry Andric continue;
576*700637cbSDimitry Andric }
577*700637cbSDimitry Andric
578*700637cbSDimitry Andric // Not previously visited; begin a new analysis for this Decl.
579*700637cbSDimitry Andric PendingFunctionAnalysis *Pending = verifyDecl(D);
580*700637cbSDimitry Andric if (Pending == nullptr) {
581*700637cbSDimitry Andric // Completed now.
582*700637cbSDimitry Andric VerificationQueue.pop_back();
583*700637cbSDimitry Andric continue;
584*700637cbSDimitry Andric }
585*700637cbSDimitry Andric
586*700637cbSDimitry Andric // Analysis remains pending because there are direct callees to be
587*700637cbSDimitry Andric // verified first. Push them onto the queue.
588*700637cbSDimitry Andric for (PendingFunctionAnalysis::DirectCall &Call :
589*700637cbSDimitry Andric Pending->unverifiedCalls()) {
590*700637cbSDimitry Andric FuncAnalysisPtr AP = DeclAnalysis.lookup(Call.Callee);
591*700637cbSDimitry Andric if (AP.isNull()) {
592*700637cbSDimitry Andric VerificationQueue.push_back(Call.Callee);
593*700637cbSDimitry Andric continue;
594*700637cbSDimitry Andric }
595*700637cbSDimitry Andric
596*700637cbSDimitry Andric // This indicates recursion (not necessarily direct). For the
597*700637cbSDimitry Andric // purposes of effect analysis, we can just ignore it since
598*700637cbSDimitry Andric // no effects forbid recursion.
599*700637cbSDimitry Andric assert(isa<PendingFunctionAnalysis *>(AP));
600*700637cbSDimitry Andric Call.Recursed = true;
601*700637cbSDimitry Andric }
602*700637cbSDimitry Andric }
603*700637cbSDimitry Andric }
604*700637cbSDimitry Andric
605*700637cbSDimitry Andric private:
606*700637cbSDimitry Andric // Verify a single Decl. Return the pending structure if that was the result,
607*700637cbSDimitry Andric // else null. This method must not recurse.
verifyDecl(const Decl * D)608*700637cbSDimitry Andric PendingFunctionAnalysis *verifyDecl(const Decl *D) {
609*700637cbSDimitry Andric CallableInfo CInfo(*D);
610*700637cbSDimitry Andric bool isExternC = false;
611*700637cbSDimitry Andric
612*700637cbSDimitry Andric if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
613*700637cbSDimitry Andric isExternC = FD->getCanonicalDecl()->isExternCContext();
614*700637cbSDimitry Andric
615*700637cbSDimitry Andric // For C++, with non-extern "C" linkage only - if any of the Decl's declared
616*700637cbSDimitry Andric // effects forbid throwing (e.g. nonblocking) then the function should also
617*700637cbSDimitry Andric // be declared noexcept.
618*700637cbSDimitry Andric if (S.getLangOpts().CPlusPlus && !isExternC) {
619*700637cbSDimitry Andric for (FunctionEffect Effect : CInfo.Effects) {
620*700637cbSDimitry Andric if (!(Effect.flags() & FunctionEffect::FE_ExcludeThrow))
621*700637cbSDimitry Andric continue;
622*700637cbSDimitry Andric
623*700637cbSDimitry Andric bool IsNoexcept = false;
624*700637cbSDimitry Andric if (auto *FD = D->getAsFunction()) {
625*700637cbSDimitry Andric IsNoexcept = isNoexcept(FD);
626*700637cbSDimitry Andric } else if (auto *BD = dyn_cast<BlockDecl>(D)) {
627*700637cbSDimitry Andric if (auto *TSI = BD->getSignatureAsWritten()) {
628*700637cbSDimitry Andric auto *FPT = TSI->getType()->castAs<FunctionProtoType>();
629*700637cbSDimitry Andric IsNoexcept = FPT->isNothrow() || BD->hasAttr<NoThrowAttr>();
630*700637cbSDimitry Andric }
631*700637cbSDimitry Andric }
632*700637cbSDimitry Andric if (!IsNoexcept)
633*700637cbSDimitry Andric S.Diag(D->getBeginLoc(), diag::warn_perf_constraint_implies_noexcept)
634*700637cbSDimitry Andric << GetCallableDeclKind(D, nullptr) << Effect.name();
635*700637cbSDimitry Andric break;
636*700637cbSDimitry Andric }
637*700637cbSDimitry Andric }
638*700637cbSDimitry Andric
639*700637cbSDimitry Andric // Build a PendingFunctionAnalysis on the stack. If it turns out to be
640*700637cbSDimitry Andric // complete, we'll have avoided a heap allocation; if it's incomplete, it's
641*700637cbSDimitry Andric // a fairly trivial move to a heap-allocated object.
642*700637cbSDimitry Andric PendingFunctionAnalysis FAnalysis(S, CInfo, AllInferrableEffectsToVerify);
643*700637cbSDimitry Andric
644*700637cbSDimitry Andric LLVM_DEBUG(llvm::dbgs()
645*700637cbSDimitry Andric << "\nVerifying " << CInfo.getNameForDiagnostic(S) << " ";
646*700637cbSDimitry Andric FAnalysis.dump(S, llvm::dbgs()););
647*700637cbSDimitry Andric
648*700637cbSDimitry Andric FunctionBodyASTVisitor Visitor(*this, FAnalysis, CInfo);
649*700637cbSDimitry Andric
650*700637cbSDimitry Andric Visitor.run();
651*700637cbSDimitry Andric if (FAnalysis.isComplete()) {
652*700637cbSDimitry Andric completeAnalysis(CInfo, std::move(FAnalysis));
653*700637cbSDimitry Andric return nullptr;
654*700637cbSDimitry Andric }
655*700637cbSDimitry Andric // Move the pending analysis to the heap and save it in the map.
656*700637cbSDimitry Andric PendingFunctionAnalysis *PendingPtr =
657*700637cbSDimitry Andric new PendingFunctionAnalysis(std::move(FAnalysis));
658*700637cbSDimitry Andric DeclAnalysis[D] = PendingPtr;
659*700637cbSDimitry Andric LLVM_DEBUG(llvm::dbgs() << "inserted pending " << PendingPtr << "\n";
660*700637cbSDimitry Andric DeclAnalysis.dump(S, llvm::dbgs()););
661*700637cbSDimitry Andric return PendingPtr;
662*700637cbSDimitry Andric }
663*700637cbSDimitry Andric
664*700637cbSDimitry Andric // Consume PendingFunctionAnalysis, create with it a CompleteFunctionAnalysis,
665*700637cbSDimitry Andric // inserted in the container.
completeAnalysis(const CallableInfo & CInfo,PendingFunctionAnalysis && Pending)666*700637cbSDimitry Andric void completeAnalysis(const CallableInfo &CInfo,
667*700637cbSDimitry Andric PendingFunctionAnalysis &&Pending) {
668*700637cbSDimitry Andric if (ArrayRef<Violation> Viols =
669*700637cbSDimitry Andric Pending.getSortedViolationsForExplicitEffects(S.getSourceManager());
670*700637cbSDimitry Andric !Viols.empty())
671*700637cbSDimitry Andric emitDiagnostics(Viols, CInfo);
672*700637cbSDimitry Andric
673*700637cbSDimitry Andric CompleteFunctionAnalysis *CompletePtr = new CompleteFunctionAnalysis(
674*700637cbSDimitry Andric S.getASTContext(), std::move(Pending), CInfo.Effects,
675*700637cbSDimitry Andric AllInferrableEffectsToVerify);
676*700637cbSDimitry Andric DeclAnalysis[CInfo.CDecl] = CompletePtr;
677*700637cbSDimitry Andric LLVM_DEBUG(llvm::dbgs() << "inserted complete " << CompletePtr << "\n";
678*700637cbSDimitry Andric DeclAnalysis.dump(S, llvm::dbgs()););
679*700637cbSDimitry Andric }
680*700637cbSDimitry Andric
681*700637cbSDimitry Andric // Called after all direct calls requiring inference have been found -- or
682*700637cbSDimitry Andric // not. Repeats calls to FunctionBodyASTVisitor::followCall() but without
683*700637cbSDimitry Andric // the possibility of inference. Deletes Pending.
finishPendingAnalysis(const Decl * D,PendingFunctionAnalysis * Pending)684*700637cbSDimitry Andric void finishPendingAnalysis(const Decl *D, PendingFunctionAnalysis *Pending) {
685*700637cbSDimitry Andric CallableInfo Caller(*D);
686*700637cbSDimitry Andric LLVM_DEBUG(llvm::dbgs() << "finishPendingAnalysis for "
687*700637cbSDimitry Andric << Caller.getNameForDiagnostic(S) << " : ";
688*700637cbSDimitry Andric Pending->dump(S, llvm::dbgs()); llvm::dbgs() << "\n";);
689*700637cbSDimitry Andric for (const PendingFunctionAnalysis::DirectCall &Call :
690*700637cbSDimitry Andric Pending->unverifiedCalls()) {
691*700637cbSDimitry Andric if (Call.Recursed)
692*700637cbSDimitry Andric continue;
693*700637cbSDimitry Andric
694*700637cbSDimitry Andric CallableInfo Callee(*Call.Callee);
695*700637cbSDimitry Andric followCall(Caller, *Pending, Callee, Call.CallLoc,
696*700637cbSDimitry Andric /*AssertNoFurtherInference=*/true, Call.VSite);
697*700637cbSDimitry Andric }
698*700637cbSDimitry Andric completeAnalysis(Caller, std::move(*Pending));
699*700637cbSDimitry Andric delete Pending;
700*700637cbSDimitry Andric }
701*700637cbSDimitry Andric
702*700637cbSDimitry Andric // Here we have a call to a Decl, either explicitly via a CallExpr or some
703*700637cbSDimitry Andric // other AST construct. PFA pertains to the caller.
followCall(const CallableInfo & Caller,PendingFunctionAnalysis & PFA,const CallableInfo & Callee,SourceLocation CallLoc,bool AssertNoFurtherInference,ViolationSite VSite)704*700637cbSDimitry Andric void followCall(const CallableInfo &Caller, PendingFunctionAnalysis &PFA,
705*700637cbSDimitry Andric const CallableInfo &Callee, SourceLocation CallLoc,
706*700637cbSDimitry Andric bool AssertNoFurtherInference, ViolationSite VSite) {
707*700637cbSDimitry Andric const bool DirectCall = Callee.isCalledDirectly();
708*700637cbSDimitry Andric
709*700637cbSDimitry Andric // Initially, the declared effects; inferred effects will be added.
710*700637cbSDimitry Andric FunctionEffectKindSet CalleeEffects = Callee.Effects;
711*700637cbSDimitry Andric
712*700637cbSDimitry Andric bool IsInferencePossible = DirectCall;
713*700637cbSDimitry Andric
714*700637cbSDimitry Andric if (DirectCall)
715*700637cbSDimitry Andric if (CompleteFunctionAnalysis *CFA =
716*700637cbSDimitry Andric DeclAnalysis.completedAnalysisForDecl(Callee.CDecl)) {
717*700637cbSDimitry Andric // Combine declared effects with those which may have been inferred.
718*700637cbSDimitry Andric CalleeEffects.insert(CFA->VerifiedEffects);
719*700637cbSDimitry Andric IsInferencePossible = false; // We've already traversed it.
720*700637cbSDimitry Andric }
721*700637cbSDimitry Andric
722*700637cbSDimitry Andric if (AssertNoFurtherInference) {
723*700637cbSDimitry Andric assert(!IsInferencePossible);
724*700637cbSDimitry Andric }
725*700637cbSDimitry Andric
726*700637cbSDimitry Andric if (!Callee.isVerifiable())
727*700637cbSDimitry Andric IsInferencePossible = false;
728*700637cbSDimitry Andric
729*700637cbSDimitry Andric LLVM_DEBUG(llvm::dbgs()
730*700637cbSDimitry Andric << "followCall from " << Caller.getNameForDiagnostic(S)
731*700637cbSDimitry Andric << " to " << Callee.getNameForDiagnostic(S)
732*700637cbSDimitry Andric << "; verifiable: " << Callee.isVerifiable() << "; callee ";
733*700637cbSDimitry Andric CalleeEffects.dump(llvm::dbgs()); llvm::dbgs() << "\n";
734*700637cbSDimitry Andric llvm::dbgs() << " callee " << Callee.CDecl << " canonical "
735*700637cbSDimitry Andric << Callee.CDecl->getCanonicalDecl() << "\n";);
736*700637cbSDimitry Andric
737*700637cbSDimitry Andric auto Check1Effect = [&](FunctionEffect Effect, bool Inferring) {
738*700637cbSDimitry Andric if (!Effect.shouldDiagnoseFunctionCall(DirectCall, CalleeEffects))
739*700637cbSDimitry Andric return;
740*700637cbSDimitry Andric
741*700637cbSDimitry Andric // If inference is not allowed, or the target is indirect (virtual
742*700637cbSDimitry Andric // method/function ptr?), generate a Violation now.
743*700637cbSDimitry Andric if (!IsInferencePossible ||
744*700637cbSDimitry Andric !(Effect.flags() & FunctionEffect::FE_InferrableOnCallees)) {
745*700637cbSDimitry Andric if (Callee.FuncType == SpecialFuncType::None)
746*700637cbSDimitry Andric PFA.checkAddViolation(Inferring,
747*700637cbSDimitry Andric {Effect, ViolationID::CallsDeclWithoutEffect,
748*700637cbSDimitry Andric VSite, CallLoc, Callee.CDecl});
749*700637cbSDimitry Andric else
750*700637cbSDimitry Andric PFA.checkAddViolation(
751*700637cbSDimitry Andric Inferring,
752*700637cbSDimitry Andric {Effect, ViolationID::AllocatesMemory, VSite, CallLoc});
753*700637cbSDimitry Andric } else {
754*700637cbSDimitry Andric // Inference is allowed and necessary; defer it.
755*700637cbSDimitry Andric PFA.addUnverifiedDirectCall(Callee.CDecl, CallLoc, VSite);
756*700637cbSDimitry Andric }
757*700637cbSDimitry Andric };
758*700637cbSDimitry Andric
759*700637cbSDimitry Andric for (FunctionEffect Effect : PFA.DeclaredVerifiableEffects)
760*700637cbSDimitry Andric Check1Effect(Effect, false);
761*700637cbSDimitry Andric
762*700637cbSDimitry Andric for (FunctionEffect Effect : PFA.EffectsToInfer)
763*700637cbSDimitry Andric Check1Effect(Effect, true);
764*700637cbSDimitry Andric }
765*700637cbSDimitry Andric
766*700637cbSDimitry Andric // Describe a callable Decl for a diagnostic.
767*700637cbSDimitry Andric // (Not an enum class because the value is always converted to an integer for
768*700637cbSDimitry Andric // use in a diagnostic.)
769*700637cbSDimitry Andric enum CallableDeclKind {
770*700637cbSDimitry Andric CDK_Function,
771*700637cbSDimitry Andric CDK_Constructor,
772*700637cbSDimitry Andric CDK_Destructor,
773*700637cbSDimitry Andric CDK_Lambda,
774*700637cbSDimitry Andric CDK_Block,
775*700637cbSDimitry Andric CDK_MemberInitializer,
776*700637cbSDimitry Andric };
777*700637cbSDimitry Andric
778*700637cbSDimitry Andric // Describe a call site or target using an enum mapping to a %select{}
779*700637cbSDimitry Andric // in a diagnostic, e.g. warn_func_effect_violation,
780*700637cbSDimitry Andric // warn_perf_constraint_implies_noexcept, and others.
GetCallableDeclKind(const Decl * D,const Violation * V)781*700637cbSDimitry Andric static CallableDeclKind GetCallableDeclKind(const Decl *D,
782*700637cbSDimitry Andric const Violation *V) {
783*700637cbSDimitry Andric if (V != nullptr &&
784*700637cbSDimitry Andric V->Site.kind() == ViolationSite::Kind::MemberInitializer)
785*700637cbSDimitry Andric return CDK_MemberInitializer;
786*700637cbSDimitry Andric if (isa<BlockDecl>(D))
787*700637cbSDimitry Andric return CDK_Block;
788*700637cbSDimitry Andric if (auto *Method = dyn_cast<CXXMethodDecl>(D)) {
789*700637cbSDimitry Andric if (isa<CXXConstructorDecl>(D))
790*700637cbSDimitry Andric return CDK_Constructor;
791*700637cbSDimitry Andric if (isa<CXXDestructorDecl>(D))
792*700637cbSDimitry Andric return CDK_Destructor;
793*700637cbSDimitry Andric const CXXRecordDecl *Rec = Method->getParent();
794*700637cbSDimitry Andric if (Rec->isLambda())
795*700637cbSDimitry Andric return CDK_Lambda;
796*700637cbSDimitry Andric }
797*700637cbSDimitry Andric return CDK_Function;
798*700637cbSDimitry Andric };
799*700637cbSDimitry Andric
800*700637cbSDimitry Andric // Should only be called when function's analysis is determined to be
801*700637cbSDimitry Andric // complete.
emitDiagnostics(ArrayRef<Violation> Viols,const CallableInfo & CInfo)802*700637cbSDimitry Andric void emitDiagnostics(ArrayRef<Violation> Viols, const CallableInfo &CInfo) {
803*700637cbSDimitry Andric if (Viols.empty())
804*700637cbSDimitry Andric return;
805*700637cbSDimitry Andric
806*700637cbSDimitry Andric auto MaybeAddTemplateNote = [&](const Decl *D) {
807*700637cbSDimitry Andric if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
808*700637cbSDimitry Andric while (FD != nullptr && FD->isTemplateInstantiation() &&
809*700637cbSDimitry Andric FD->getPointOfInstantiation().isValid()) {
810*700637cbSDimitry Andric S.Diag(FD->getPointOfInstantiation(),
811*700637cbSDimitry Andric diag::note_func_effect_from_template);
812*700637cbSDimitry Andric FD = FD->getTemplateInstantiationPattern();
813*700637cbSDimitry Andric }
814*700637cbSDimitry Andric }
815*700637cbSDimitry Andric };
816*700637cbSDimitry Andric
817*700637cbSDimitry Andric // For note_func_effect_call_indirect.
818*700637cbSDimitry Andric enum { Indirect_VirtualMethod, Indirect_FunctionPtr };
819*700637cbSDimitry Andric
820*700637cbSDimitry Andric auto MaybeAddSiteContext = [&](const Decl *D, const Violation &V) {
821*700637cbSDimitry Andric // If a violation site is a member initializer, add a note pointing to
822*700637cbSDimitry Andric // the constructor which invoked it.
823*700637cbSDimitry Andric if (V.Site.kind() == ViolationSite::Kind::MemberInitializer) {
824*700637cbSDimitry Andric unsigned ImplicitCtor = 0;
825*700637cbSDimitry Andric if (auto *Ctor = dyn_cast<CXXConstructorDecl>(D);
826*700637cbSDimitry Andric Ctor && Ctor->isImplicit())
827*700637cbSDimitry Andric ImplicitCtor = 1;
828*700637cbSDimitry Andric S.Diag(D->getLocation(), diag::note_func_effect_in_constructor)
829*700637cbSDimitry Andric << ImplicitCtor;
830*700637cbSDimitry Andric }
831*700637cbSDimitry Andric
832*700637cbSDimitry Andric // If a violation site is a default argument expression, add a note
833*700637cbSDimitry Andric // pointing to the call site using the default argument.
834*700637cbSDimitry Andric else if (V.Site.kind() == ViolationSite::Kind::DefaultArgExpr)
835*700637cbSDimitry Andric S.Diag(V.Site.defaultArgExpr()->getUsedLocation(),
836*700637cbSDimitry Andric diag::note_in_evaluating_default_argument);
837*700637cbSDimitry Andric };
838*700637cbSDimitry Andric
839*700637cbSDimitry Andric // Top-level violations are warnings.
840*700637cbSDimitry Andric for (const Violation &Viol1 : Viols) {
841*700637cbSDimitry Andric StringRef effectName = Viol1.Effect.name();
842*700637cbSDimitry Andric switch (Viol1.ID) {
843*700637cbSDimitry Andric case ViolationID::None:
844*700637cbSDimitry Andric case ViolationID::DeclDisallowsInference: // Shouldn't happen
845*700637cbSDimitry Andric // here.
846*700637cbSDimitry Andric llvm_unreachable("Unexpected violation kind");
847*700637cbSDimitry Andric break;
848*700637cbSDimitry Andric case ViolationID::AllocatesMemory:
849*700637cbSDimitry Andric case ViolationID::ThrowsOrCatchesExceptions:
850*700637cbSDimitry Andric case ViolationID::HasStaticLocalVariable:
851*700637cbSDimitry Andric case ViolationID::AccessesThreadLocalVariable:
852*700637cbSDimitry Andric case ViolationID::AccessesObjCMethodOrProperty:
853*700637cbSDimitry Andric S.Diag(Viol1.Loc, diag::warn_func_effect_violation)
854*700637cbSDimitry Andric << GetCallableDeclKind(CInfo.CDecl, &Viol1) << effectName
855*700637cbSDimitry Andric << Viol1.diagnosticSelectIndex();
856*700637cbSDimitry Andric MaybeAddSiteContext(CInfo.CDecl, Viol1);
857*700637cbSDimitry Andric MaybeAddTemplateNote(CInfo.CDecl);
858*700637cbSDimitry Andric break;
859*700637cbSDimitry Andric case ViolationID::CallsExprWithoutEffect:
860*700637cbSDimitry Andric S.Diag(Viol1.Loc, diag::warn_func_effect_calls_expr_without_effect)
861*700637cbSDimitry Andric << GetCallableDeclKind(CInfo.CDecl, &Viol1) << effectName;
862*700637cbSDimitry Andric MaybeAddSiteContext(CInfo.CDecl, Viol1);
863*700637cbSDimitry Andric MaybeAddTemplateNote(CInfo.CDecl);
864*700637cbSDimitry Andric break;
865*700637cbSDimitry Andric
866*700637cbSDimitry Andric case ViolationID::CallsDeclWithoutEffect: {
867*700637cbSDimitry Andric CallableInfo CalleeInfo(*Viol1.Callee);
868*700637cbSDimitry Andric std::string CalleeName = CalleeInfo.getNameForDiagnostic(S);
869*700637cbSDimitry Andric
870*700637cbSDimitry Andric S.Diag(Viol1.Loc, diag::warn_func_effect_calls_func_without_effect)
871*700637cbSDimitry Andric << GetCallableDeclKind(CInfo.CDecl, &Viol1) << effectName
872*700637cbSDimitry Andric << GetCallableDeclKind(CalleeInfo.CDecl, nullptr) << CalleeName;
873*700637cbSDimitry Andric MaybeAddSiteContext(CInfo.CDecl, Viol1);
874*700637cbSDimitry Andric MaybeAddTemplateNote(CInfo.CDecl);
875*700637cbSDimitry Andric
876*700637cbSDimitry Andric // Emit notes explaining the transitive chain of inferences: Why isn't
877*700637cbSDimitry Andric // the callee safe?
878*700637cbSDimitry Andric for (const Decl *Callee = Viol1.Callee; Callee != nullptr;) {
879*700637cbSDimitry Andric std::optional<CallableInfo> MaybeNextCallee;
880*700637cbSDimitry Andric CompleteFunctionAnalysis *Completed =
881*700637cbSDimitry Andric DeclAnalysis.completedAnalysisForDecl(CalleeInfo.CDecl);
882*700637cbSDimitry Andric if (Completed == nullptr) {
883*700637cbSDimitry Andric // No result - could be
884*700637cbSDimitry Andric // - non-inline and extern
885*700637cbSDimitry Andric // - indirect (virtual or through function pointer)
886*700637cbSDimitry Andric // - effect has been explicitly disclaimed (e.g. "blocking")
887*700637cbSDimitry Andric
888*700637cbSDimitry Andric CallableType CType = CalleeInfo.type();
889*700637cbSDimitry Andric if (CType == CallableType::Virtual)
890*700637cbSDimitry Andric S.Diag(Callee->getLocation(),
891*700637cbSDimitry Andric diag::note_func_effect_call_indirect)
892*700637cbSDimitry Andric << Indirect_VirtualMethod << effectName;
893*700637cbSDimitry Andric else if (CType == CallableType::Unknown)
894*700637cbSDimitry Andric S.Diag(Callee->getLocation(),
895*700637cbSDimitry Andric diag::note_func_effect_call_indirect)
896*700637cbSDimitry Andric << Indirect_FunctionPtr << effectName;
897*700637cbSDimitry Andric else if (CalleeInfo.Effects.contains(Viol1.Effect.oppositeKind()))
898*700637cbSDimitry Andric S.Diag(Callee->getLocation(),
899*700637cbSDimitry Andric diag::note_func_effect_call_disallows_inference)
900*700637cbSDimitry Andric << GetCallableDeclKind(CInfo.CDecl, nullptr) << effectName
901*700637cbSDimitry Andric << FunctionEffect(Viol1.Effect.oppositeKind()).name();
902*700637cbSDimitry Andric else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(Callee);
903*700637cbSDimitry Andric FD == nullptr || FD->getBuiltinID() == 0) {
904*700637cbSDimitry Andric // A builtin callee generally doesn't have a useful source
905*700637cbSDimitry Andric // location at which to insert a note.
906*700637cbSDimitry Andric S.Diag(Callee->getLocation(), diag::note_func_effect_call_extern)
907*700637cbSDimitry Andric << effectName;
908*700637cbSDimitry Andric }
909*700637cbSDimitry Andric break;
910*700637cbSDimitry Andric }
911*700637cbSDimitry Andric const Violation *PtrViol2 =
912*700637cbSDimitry Andric Completed->firstViolationForEffect(Viol1.Effect);
913*700637cbSDimitry Andric if (PtrViol2 == nullptr)
914*700637cbSDimitry Andric break;
915*700637cbSDimitry Andric
916*700637cbSDimitry Andric const Violation &Viol2 = *PtrViol2;
917*700637cbSDimitry Andric switch (Viol2.ID) {
918*700637cbSDimitry Andric case ViolationID::None:
919*700637cbSDimitry Andric llvm_unreachable("Unexpected violation kind");
920*700637cbSDimitry Andric break;
921*700637cbSDimitry Andric case ViolationID::DeclDisallowsInference:
922*700637cbSDimitry Andric S.Diag(Viol2.Loc, diag::note_func_effect_call_disallows_inference)
923*700637cbSDimitry Andric << GetCallableDeclKind(CalleeInfo.CDecl, nullptr) << effectName
924*700637cbSDimitry Andric << Viol2.CalleeEffectPreventingInference->name();
925*700637cbSDimitry Andric break;
926*700637cbSDimitry Andric case ViolationID::CallsExprWithoutEffect:
927*700637cbSDimitry Andric S.Diag(Viol2.Loc, diag::note_func_effect_call_indirect)
928*700637cbSDimitry Andric << Indirect_FunctionPtr << effectName;
929*700637cbSDimitry Andric break;
930*700637cbSDimitry Andric case ViolationID::AllocatesMemory:
931*700637cbSDimitry Andric case ViolationID::ThrowsOrCatchesExceptions:
932*700637cbSDimitry Andric case ViolationID::HasStaticLocalVariable:
933*700637cbSDimitry Andric case ViolationID::AccessesThreadLocalVariable:
934*700637cbSDimitry Andric case ViolationID::AccessesObjCMethodOrProperty:
935*700637cbSDimitry Andric S.Diag(Viol2.Loc, diag::note_func_effect_violation)
936*700637cbSDimitry Andric << GetCallableDeclKind(CalleeInfo.CDecl, &Viol2) << effectName
937*700637cbSDimitry Andric << Viol2.diagnosticSelectIndex();
938*700637cbSDimitry Andric MaybeAddSiteContext(CalleeInfo.CDecl, Viol2);
939*700637cbSDimitry Andric break;
940*700637cbSDimitry Andric case ViolationID::CallsDeclWithoutEffect:
941*700637cbSDimitry Andric MaybeNextCallee.emplace(*Viol2.Callee);
942*700637cbSDimitry Andric S.Diag(Viol2.Loc, diag::note_func_effect_calls_func_without_effect)
943*700637cbSDimitry Andric << GetCallableDeclKind(CalleeInfo.CDecl, &Viol2) << effectName
944*700637cbSDimitry Andric << GetCallableDeclKind(Viol2.Callee, nullptr)
945*700637cbSDimitry Andric << MaybeNextCallee->getNameForDiagnostic(S);
946*700637cbSDimitry Andric break;
947*700637cbSDimitry Andric }
948*700637cbSDimitry Andric MaybeAddTemplateNote(Callee);
949*700637cbSDimitry Andric Callee = Viol2.Callee;
950*700637cbSDimitry Andric if (MaybeNextCallee) {
951*700637cbSDimitry Andric CalleeInfo = *MaybeNextCallee;
952*700637cbSDimitry Andric CalleeName = CalleeInfo.getNameForDiagnostic(S);
953*700637cbSDimitry Andric }
954*700637cbSDimitry Andric }
955*700637cbSDimitry Andric } break;
956*700637cbSDimitry Andric }
957*700637cbSDimitry Andric }
958*700637cbSDimitry Andric }
959*700637cbSDimitry Andric
960*700637cbSDimitry Andric // ----------
961*700637cbSDimitry Andric // This AST visitor is used to traverse the body of a function during effect
962*700637cbSDimitry Andric // verification. This happens in 2 situations:
963*700637cbSDimitry Andric // [1] The function has declared effects which need to be validated.
964*700637cbSDimitry Andric // [2] The function has not explicitly declared an effect in question, and is
965*700637cbSDimitry Andric // being checked for implicit conformance.
966*700637cbSDimitry Andric //
967*700637cbSDimitry Andric // Violations are always routed to a PendingFunctionAnalysis.
968*700637cbSDimitry Andric struct FunctionBodyASTVisitor : DynamicRecursiveASTVisitor {
969*700637cbSDimitry Andric Analyzer &Outer;
970*700637cbSDimitry Andric PendingFunctionAnalysis &CurrentFunction;
971*700637cbSDimitry Andric CallableInfo &CurrentCaller;
972*700637cbSDimitry Andric ViolationSite VSite;
973*700637cbSDimitry Andric const Expr *TrailingRequiresClause = nullptr;
974*700637cbSDimitry Andric const Expr *NoexceptExpr = nullptr;
975*700637cbSDimitry Andric
FunctionBodyASTVisitor__anon1adc617b0111::Analyzer::FunctionBodyASTVisitor976*700637cbSDimitry Andric FunctionBodyASTVisitor(Analyzer &Outer,
977*700637cbSDimitry Andric PendingFunctionAnalysis &CurrentFunction,
978*700637cbSDimitry Andric CallableInfo &CurrentCaller)
979*700637cbSDimitry Andric : Outer(Outer), CurrentFunction(CurrentFunction),
980*700637cbSDimitry Andric CurrentCaller(CurrentCaller) {
981*700637cbSDimitry Andric ShouldVisitImplicitCode = true;
982*700637cbSDimitry Andric ShouldWalkTypesOfTypeLocs = false;
983*700637cbSDimitry Andric }
984*700637cbSDimitry Andric
985*700637cbSDimitry Andric // -- Entry point --
run__anon1adc617b0111::Analyzer::FunctionBodyASTVisitor986*700637cbSDimitry Andric void run() {
987*700637cbSDimitry Andric // The target function may have implicit code paths beyond the
988*700637cbSDimitry Andric // body: member and base destructors. Visit these first.
989*700637cbSDimitry Andric if (auto *Dtor = dyn_cast<CXXDestructorDecl>(CurrentCaller.CDecl))
990*700637cbSDimitry Andric followDestructor(dyn_cast<CXXRecordDecl>(Dtor->getParent()), Dtor);
991*700637cbSDimitry Andric
992*700637cbSDimitry Andric if (auto *FD = dyn_cast<FunctionDecl>(CurrentCaller.CDecl)) {
993*700637cbSDimitry Andric TrailingRequiresClause = FD->getTrailingRequiresClause().ConstraintExpr;
994*700637cbSDimitry Andric
995*700637cbSDimitry Andric // Note that FD->getType->getAs<FunctionProtoType>() can yield a
996*700637cbSDimitry Andric // noexcept Expr which has been boiled down to a constant expression.
997*700637cbSDimitry Andric // Going through the TypeSourceInfo obtains the actual expression which
998*700637cbSDimitry Andric // will be traversed as part of the function -- unless we capture it
999*700637cbSDimitry Andric // here and have TraverseStmt skip it.
1000*700637cbSDimitry Andric if (TypeSourceInfo *TSI = FD->getTypeSourceInfo()) {
1001*700637cbSDimitry Andric if (FunctionProtoTypeLoc TL =
1002*700637cbSDimitry Andric TSI->getTypeLoc().getAs<FunctionProtoTypeLoc>())
1003*700637cbSDimitry Andric if (const FunctionProtoType *FPT = TL.getTypePtr())
1004*700637cbSDimitry Andric NoexceptExpr = FPT->getNoexceptExpr();
1005*700637cbSDimitry Andric }
1006*700637cbSDimitry Andric }
1007*700637cbSDimitry Andric
1008*700637cbSDimitry Andric // Do an AST traversal of the function/block body
1009*700637cbSDimitry Andric TraverseDecl(const_cast<Decl *>(CurrentCaller.CDecl));
1010*700637cbSDimitry Andric }
1011*700637cbSDimitry Andric
1012*700637cbSDimitry Andric // -- Methods implementing common logic --
1013*700637cbSDimitry Andric
1014*700637cbSDimitry Andric // Handle a language construct forbidden by some effects. Only effects whose
1015*700637cbSDimitry Andric // flags include the specified flag receive a violation. \p Flag describes
1016*700637cbSDimitry Andric // the construct.
diagnoseLanguageConstruct__anon1adc617b0111::Analyzer::FunctionBodyASTVisitor1017*700637cbSDimitry Andric void diagnoseLanguageConstruct(FunctionEffect::FlagBit Flag,
1018*700637cbSDimitry Andric ViolationID VID, SourceLocation Loc,
1019*700637cbSDimitry Andric const Decl *Callee = nullptr) {
1020*700637cbSDimitry Andric // If there are any declared verifiable effects which forbid the construct
1021*700637cbSDimitry Andric // represented by the flag, store just one violation.
1022*700637cbSDimitry Andric for (FunctionEffect Effect : CurrentFunction.DeclaredVerifiableEffects) {
1023*700637cbSDimitry Andric if (Effect.flags() & Flag) {
1024*700637cbSDimitry Andric addViolation(/*inferring=*/false, Effect, VID, Loc, Callee);
1025*700637cbSDimitry Andric break;
1026*700637cbSDimitry Andric }
1027*700637cbSDimitry Andric }
1028*700637cbSDimitry Andric // For each inferred effect which forbids the construct, store a
1029*700637cbSDimitry Andric // violation, if we don't already have a violation for that effect.
1030*700637cbSDimitry Andric for (FunctionEffect Effect : CurrentFunction.EffectsToInfer)
1031*700637cbSDimitry Andric if (Effect.flags() & Flag)
1032*700637cbSDimitry Andric addViolation(/*inferring=*/true, Effect, VID, Loc, Callee);
1033*700637cbSDimitry Andric }
1034*700637cbSDimitry Andric
addViolation__anon1adc617b0111::Analyzer::FunctionBodyASTVisitor1035*700637cbSDimitry Andric void addViolation(bool Inferring, FunctionEffect Effect, ViolationID VID,
1036*700637cbSDimitry Andric SourceLocation Loc, const Decl *Callee = nullptr) {
1037*700637cbSDimitry Andric CurrentFunction.checkAddViolation(
1038*700637cbSDimitry Andric Inferring, Violation(Effect, VID, VSite, Loc, Callee));
1039*700637cbSDimitry Andric }
1040*700637cbSDimitry Andric
1041*700637cbSDimitry Andric // Here we have a call to a Decl, either explicitly via a CallExpr or some
1042*700637cbSDimitry Andric // other AST construct. CallableInfo pertains to the callee.
followCall__anon1adc617b0111::Analyzer::FunctionBodyASTVisitor1043*700637cbSDimitry Andric void followCall(CallableInfo &CI, SourceLocation CallLoc) {
1044*700637cbSDimitry Andric // Check for a call to a builtin function, whose effects are
1045*700637cbSDimitry Andric // handled specially.
1046*700637cbSDimitry Andric if (const auto *FD = dyn_cast<FunctionDecl>(CI.CDecl)) {
1047*700637cbSDimitry Andric if (unsigned BuiltinID = FD->getBuiltinID()) {
1048*700637cbSDimitry Andric CI.Effects = getBuiltinFunctionEffects(BuiltinID);
1049*700637cbSDimitry Andric if (CI.Effects.empty()) {
1050*700637cbSDimitry Andric // A builtin with no known effects is assumed safe.
1051*700637cbSDimitry Andric return;
1052*700637cbSDimitry Andric }
1053*700637cbSDimitry Andric // A builtin WITH effects doesn't get any special treatment for
1054*700637cbSDimitry Andric // being noreturn/noexcept, e.g. longjmp(), so we skip the check
1055*700637cbSDimitry Andric // below.
1056*700637cbSDimitry Andric } else {
1057*700637cbSDimitry Andric // If the callee is both `noreturn` and `noexcept`, it presumably
1058*700637cbSDimitry Andric // terminates. Ignore it for the purposes of effect analysis.
1059*700637cbSDimitry Andric // If not C++, `noreturn` alone is sufficient.
1060*700637cbSDimitry Andric if (FD->isNoReturn() &&
1061*700637cbSDimitry Andric (!Outer.S.getLangOpts().CPlusPlus || isNoexcept(FD)))
1062*700637cbSDimitry Andric return;
1063*700637cbSDimitry Andric }
1064*700637cbSDimitry Andric }
1065*700637cbSDimitry Andric
1066*700637cbSDimitry Andric Outer.followCall(CurrentCaller, CurrentFunction, CI, CallLoc,
1067*700637cbSDimitry Andric /*AssertNoFurtherInference=*/false, VSite);
1068*700637cbSDimitry Andric }
1069*700637cbSDimitry Andric
checkIndirectCall__anon1adc617b0111::Analyzer::FunctionBodyASTVisitor1070*700637cbSDimitry Andric void checkIndirectCall(CallExpr *Call, QualType CalleeType) {
1071*700637cbSDimitry Andric FunctionEffectKindSet CalleeEffects;
1072*700637cbSDimitry Andric if (FunctionEffectsRef Effects = FunctionEffectsRef::get(CalleeType);
1073*700637cbSDimitry Andric !Effects.empty())
1074*700637cbSDimitry Andric CalleeEffects.insert(Effects);
1075*700637cbSDimitry Andric
1076*700637cbSDimitry Andric auto Check1Effect = [&](FunctionEffect Effect, bool Inferring) {
1077*700637cbSDimitry Andric if (Effect.shouldDiagnoseFunctionCall(
1078*700637cbSDimitry Andric /*direct=*/false, CalleeEffects))
1079*700637cbSDimitry Andric addViolation(Inferring, Effect, ViolationID::CallsExprWithoutEffect,
1080*700637cbSDimitry Andric Call->getBeginLoc());
1081*700637cbSDimitry Andric };
1082*700637cbSDimitry Andric
1083*700637cbSDimitry Andric for (FunctionEffect Effect : CurrentFunction.DeclaredVerifiableEffects)
1084*700637cbSDimitry Andric Check1Effect(Effect, false);
1085*700637cbSDimitry Andric
1086*700637cbSDimitry Andric for (FunctionEffect Effect : CurrentFunction.EffectsToInfer)
1087*700637cbSDimitry Andric Check1Effect(Effect, true);
1088*700637cbSDimitry Andric }
1089*700637cbSDimitry Andric
1090*700637cbSDimitry Andric // This destructor's body should be followed by the caller, but here we
1091*700637cbSDimitry Andric // follow the field and base destructors.
followDestructor__anon1adc617b0111::Analyzer::FunctionBodyASTVisitor1092*700637cbSDimitry Andric void followDestructor(const CXXRecordDecl *Rec,
1093*700637cbSDimitry Andric const CXXDestructorDecl *Dtor) {
1094*700637cbSDimitry Andric SourceLocation DtorLoc = Dtor->getLocation();
1095*700637cbSDimitry Andric for (const FieldDecl *Field : Rec->fields())
1096*700637cbSDimitry Andric followTypeDtor(Field->getType(), DtorLoc);
1097*700637cbSDimitry Andric
1098*700637cbSDimitry Andric if (const auto *Class = dyn_cast<CXXRecordDecl>(Rec))
1099*700637cbSDimitry Andric for (const CXXBaseSpecifier &Base : Class->bases())
1100*700637cbSDimitry Andric followTypeDtor(Base.getType(), DtorLoc);
1101*700637cbSDimitry Andric }
1102*700637cbSDimitry Andric
followTypeDtor__anon1adc617b0111::Analyzer::FunctionBodyASTVisitor1103*700637cbSDimitry Andric void followTypeDtor(QualType QT, SourceLocation CallSite) {
1104*700637cbSDimitry Andric const Type *Ty = QT.getTypePtr();
1105*700637cbSDimitry Andric while (Ty->isArrayType()) {
1106*700637cbSDimitry Andric const ArrayType *Arr = Ty->getAsArrayTypeUnsafe();
1107*700637cbSDimitry Andric QT = Arr->getElementType();
1108*700637cbSDimitry Andric Ty = QT.getTypePtr();
1109*700637cbSDimitry Andric }
1110*700637cbSDimitry Andric
1111*700637cbSDimitry Andric if (Ty->isRecordType()) {
1112*700637cbSDimitry Andric if (const CXXRecordDecl *Class = Ty->getAsCXXRecordDecl()) {
1113*700637cbSDimitry Andric if (CXXDestructorDecl *Dtor = Class->getDestructor();
1114*700637cbSDimitry Andric Dtor && !Dtor->isDeleted()) {
1115*700637cbSDimitry Andric CallableInfo CI(*Dtor);
1116*700637cbSDimitry Andric followCall(CI, CallSite);
1117*700637cbSDimitry Andric }
1118*700637cbSDimitry Andric }
1119*700637cbSDimitry Andric }
1120*700637cbSDimitry Andric }
1121*700637cbSDimitry Andric
1122*700637cbSDimitry Andric // -- Methods for use of RecursiveASTVisitor --
1123*700637cbSDimitry Andric
VisitCXXThrowExpr__anon1adc617b0111::Analyzer::FunctionBodyASTVisitor1124*700637cbSDimitry Andric bool VisitCXXThrowExpr(CXXThrowExpr *Throw) override {
1125*700637cbSDimitry Andric diagnoseLanguageConstruct(FunctionEffect::FE_ExcludeThrow,
1126*700637cbSDimitry Andric ViolationID::ThrowsOrCatchesExceptions,
1127*700637cbSDimitry Andric Throw->getThrowLoc());
1128*700637cbSDimitry Andric return true;
1129*700637cbSDimitry Andric }
1130*700637cbSDimitry Andric
VisitCXXCatchStmt__anon1adc617b0111::Analyzer::FunctionBodyASTVisitor1131*700637cbSDimitry Andric bool VisitCXXCatchStmt(CXXCatchStmt *Catch) override {
1132*700637cbSDimitry Andric diagnoseLanguageConstruct(FunctionEffect::FE_ExcludeCatch,
1133*700637cbSDimitry Andric ViolationID::ThrowsOrCatchesExceptions,
1134*700637cbSDimitry Andric Catch->getCatchLoc());
1135*700637cbSDimitry Andric return true;
1136*700637cbSDimitry Andric }
1137*700637cbSDimitry Andric
VisitObjCAtThrowStmt__anon1adc617b0111::Analyzer::FunctionBodyASTVisitor1138*700637cbSDimitry Andric bool VisitObjCAtThrowStmt(ObjCAtThrowStmt *Throw) override {
1139*700637cbSDimitry Andric diagnoseLanguageConstruct(FunctionEffect::FE_ExcludeThrow,
1140*700637cbSDimitry Andric ViolationID::ThrowsOrCatchesExceptions,
1141*700637cbSDimitry Andric Throw->getThrowLoc());
1142*700637cbSDimitry Andric return true;
1143*700637cbSDimitry Andric }
1144*700637cbSDimitry Andric
VisitObjCAtCatchStmt__anon1adc617b0111::Analyzer::FunctionBodyASTVisitor1145*700637cbSDimitry Andric bool VisitObjCAtCatchStmt(ObjCAtCatchStmt *Catch) override {
1146*700637cbSDimitry Andric diagnoseLanguageConstruct(FunctionEffect::FE_ExcludeCatch,
1147*700637cbSDimitry Andric ViolationID::ThrowsOrCatchesExceptions,
1148*700637cbSDimitry Andric Catch->getAtCatchLoc());
1149*700637cbSDimitry Andric return true;
1150*700637cbSDimitry Andric }
1151*700637cbSDimitry Andric
VisitObjCAtFinallyStmt__anon1adc617b0111::Analyzer::FunctionBodyASTVisitor1152*700637cbSDimitry Andric bool VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *Finally) override {
1153*700637cbSDimitry Andric diagnoseLanguageConstruct(FunctionEffect::FE_ExcludeCatch,
1154*700637cbSDimitry Andric ViolationID::ThrowsOrCatchesExceptions,
1155*700637cbSDimitry Andric Finally->getAtFinallyLoc());
1156*700637cbSDimitry Andric return true;
1157*700637cbSDimitry Andric }
1158*700637cbSDimitry Andric
VisitObjCMessageExpr__anon1adc617b0111::Analyzer::FunctionBodyASTVisitor1159*700637cbSDimitry Andric bool VisitObjCMessageExpr(ObjCMessageExpr *Msg) override {
1160*700637cbSDimitry Andric diagnoseLanguageConstruct(FunctionEffect::FE_ExcludeObjCMessageSend,
1161*700637cbSDimitry Andric ViolationID::AccessesObjCMethodOrProperty,
1162*700637cbSDimitry Andric Msg->getBeginLoc());
1163*700637cbSDimitry Andric return true;
1164*700637cbSDimitry Andric }
1165*700637cbSDimitry Andric
VisitObjCAutoreleasePoolStmt__anon1adc617b0111::Analyzer::FunctionBodyASTVisitor1166*700637cbSDimitry Andric bool VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *ARP) override {
1167*700637cbSDimitry Andric // Under the hood, @autorelease (potentially?) allocates memory and
1168*700637cbSDimitry Andric // invokes ObjC methods. We don't currently have memory allocation as
1169*700637cbSDimitry Andric // a "language construct" but we do have ObjC messaging, so diagnose that.
1170*700637cbSDimitry Andric diagnoseLanguageConstruct(FunctionEffect::FE_ExcludeObjCMessageSend,
1171*700637cbSDimitry Andric ViolationID::AccessesObjCMethodOrProperty,
1172*700637cbSDimitry Andric ARP->getBeginLoc());
1173*700637cbSDimitry Andric return true;
1174*700637cbSDimitry Andric }
1175*700637cbSDimitry Andric
VisitObjCAtSynchronizedStmt__anon1adc617b0111::Analyzer::FunctionBodyASTVisitor1176*700637cbSDimitry Andric bool VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *Sync) override {
1177*700637cbSDimitry Andric // Under the hood, this calls objc_sync_enter and objc_sync_exit, wrapped
1178*700637cbSDimitry Andric // in a @try/@finally block. Diagnose this generically as "ObjC
1179*700637cbSDimitry Andric // messaging".
1180*700637cbSDimitry Andric diagnoseLanguageConstruct(FunctionEffect::FE_ExcludeObjCMessageSend,
1181*700637cbSDimitry Andric ViolationID::AccessesObjCMethodOrProperty,
1182*700637cbSDimitry Andric Sync->getBeginLoc());
1183*700637cbSDimitry Andric return true;
1184*700637cbSDimitry Andric }
1185*700637cbSDimitry Andric
VisitSEHExceptStmt__anon1adc617b0111::Analyzer::FunctionBodyASTVisitor1186*700637cbSDimitry Andric bool VisitSEHExceptStmt(SEHExceptStmt *Exc) override {
1187*700637cbSDimitry Andric diagnoseLanguageConstruct(FunctionEffect::FE_ExcludeCatch,
1188*700637cbSDimitry Andric ViolationID::ThrowsOrCatchesExceptions,
1189*700637cbSDimitry Andric Exc->getExceptLoc());
1190*700637cbSDimitry Andric return true;
1191*700637cbSDimitry Andric }
1192*700637cbSDimitry Andric
VisitCallExpr__anon1adc617b0111::Analyzer::FunctionBodyASTVisitor1193*700637cbSDimitry Andric bool VisitCallExpr(CallExpr *Call) override {
1194*700637cbSDimitry Andric LLVM_DEBUG(llvm::dbgs()
1195*700637cbSDimitry Andric << "VisitCallExpr : "
1196*700637cbSDimitry Andric << Call->getBeginLoc().printToString(Outer.S.SourceMgr)
1197*700637cbSDimitry Andric << "\n";);
1198*700637cbSDimitry Andric
1199*700637cbSDimitry Andric Expr *CalleeExpr = Call->getCallee();
1200*700637cbSDimitry Andric if (const Decl *Callee = CalleeExpr->getReferencedDeclOfCallee()) {
1201*700637cbSDimitry Andric CallableInfo CI(*Callee);
1202*700637cbSDimitry Andric followCall(CI, Call->getBeginLoc());
1203*700637cbSDimitry Andric return true;
1204*700637cbSDimitry Andric }
1205*700637cbSDimitry Andric
1206*700637cbSDimitry Andric if (isa<CXXPseudoDestructorExpr>(CalleeExpr)) {
1207*700637cbSDimitry Andric // Just destroying a scalar, fine.
1208*700637cbSDimitry Andric return true;
1209*700637cbSDimitry Andric }
1210*700637cbSDimitry Andric
1211*700637cbSDimitry Andric // No Decl, just an Expr. Just check based on its type.
1212*700637cbSDimitry Andric checkIndirectCall(Call, CalleeExpr->getType());
1213*700637cbSDimitry Andric
1214*700637cbSDimitry Andric return true;
1215*700637cbSDimitry Andric }
1216*700637cbSDimitry Andric
VisitVarDecl__anon1adc617b0111::Analyzer::FunctionBodyASTVisitor1217*700637cbSDimitry Andric bool VisitVarDecl(VarDecl *Var) override {
1218*700637cbSDimitry Andric LLVM_DEBUG(llvm::dbgs()
1219*700637cbSDimitry Andric << "VisitVarDecl : "
1220*700637cbSDimitry Andric << Var->getBeginLoc().printToString(Outer.S.SourceMgr)
1221*700637cbSDimitry Andric << "\n";);
1222*700637cbSDimitry Andric
1223*700637cbSDimitry Andric if (Var->isStaticLocal())
1224*700637cbSDimitry Andric diagnoseLanguageConstruct(FunctionEffect::FE_ExcludeStaticLocalVars,
1225*700637cbSDimitry Andric ViolationID::HasStaticLocalVariable,
1226*700637cbSDimitry Andric Var->getLocation());
1227*700637cbSDimitry Andric
1228*700637cbSDimitry Andric const QualType::DestructionKind DK =
1229*700637cbSDimitry Andric Var->needsDestruction(Outer.S.getASTContext());
1230*700637cbSDimitry Andric if (DK == QualType::DK_cxx_destructor)
1231*700637cbSDimitry Andric followTypeDtor(Var->getType(), Var->getLocation());
1232*700637cbSDimitry Andric return true;
1233*700637cbSDimitry Andric }
1234*700637cbSDimitry Andric
VisitCXXNewExpr__anon1adc617b0111::Analyzer::FunctionBodyASTVisitor1235*700637cbSDimitry Andric bool VisitCXXNewExpr(CXXNewExpr *New) override {
1236*700637cbSDimitry Andric // RecursiveASTVisitor does not visit the implicit call to operator new.
1237*700637cbSDimitry Andric if (FunctionDecl *FD = New->getOperatorNew()) {
1238*700637cbSDimitry Andric CallableInfo CI(*FD, SpecialFuncType::OperatorNew);
1239*700637cbSDimitry Andric followCall(CI, New->getBeginLoc());
1240*700637cbSDimitry Andric }
1241*700637cbSDimitry Andric
1242*700637cbSDimitry Andric // It's a bit excessive to check operator delete here, since it's
1243*700637cbSDimitry Andric // just a fallback for operator new followed by a failed constructor.
1244*700637cbSDimitry Andric // We could check it via New->getOperatorDelete().
1245*700637cbSDimitry Andric
1246*700637cbSDimitry Andric // It DOES however visit the called constructor
1247*700637cbSDimitry Andric return true;
1248*700637cbSDimitry Andric }
1249*700637cbSDimitry Andric
VisitCXXDeleteExpr__anon1adc617b0111::Analyzer::FunctionBodyASTVisitor1250*700637cbSDimitry Andric bool VisitCXXDeleteExpr(CXXDeleteExpr *Delete) override {
1251*700637cbSDimitry Andric // RecursiveASTVisitor does not visit the implicit call to operator
1252*700637cbSDimitry Andric // delete.
1253*700637cbSDimitry Andric if (FunctionDecl *FD = Delete->getOperatorDelete()) {
1254*700637cbSDimitry Andric CallableInfo CI(*FD, SpecialFuncType::OperatorDelete);
1255*700637cbSDimitry Andric followCall(CI, Delete->getBeginLoc());
1256*700637cbSDimitry Andric }
1257*700637cbSDimitry Andric
1258*700637cbSDimitry Andric // It DOES however visit the called destructor
1259*700637cbSDimitry Andric
1260*700637cbSDimitry Andric return true;
1261*700637cbSDimitry Andric }
1262*700637cbSDimitry Andric
VisitCXXConstructExpr__anon1adc617b0111::Analyzer::FunctionBodyASTVisitor1263*700637cbSDimitry Andric bool VisitCXXConstructExpr(CXXConstructExpr *Construct) override {
1264*700637cbSDimitry Andric LLVM_DEBUG(llvm::dbgs() << "VisitCXXConstructExpr : "
1265*700637cbSDimitry Andric << Construct->getBeginLoc().printToString(
1266*700637cbSDimitry Andric Outer.S.SourceMgr)
1267*700637cbSDimitry Andric << "\n";);
1268*700637cbSDimitry Andric
1269*700637cbSDimitry Andric // RecursiveASTVisitor does not visit the implicit call to the
1270*700637cbSDimitry Andric // constructor.
1271*700637cbSDimitry Andric const CXXConstructorDecl *Ctor = Construct->getConstructor();
1272*700637cbSDimitry Andric CallableInfo CI(*Ctor);
1273*700637cbSDimitry Andric followCall(CI, Construct->getLocation());
1274*700637cbSDimitry Andric
1275*700637cbSDimitry Andric return true;
1276*700637cbSDimitry Andric }
1277*700637cbSDimitry Andric
TraverseStmt__anon1adc617b0111::Analyzer::FunctionBodyASTVisitor1278*700637cbSDimitry Andric bool TraverseStmt(Stmt *Statement) override {
1279*700637cbSDimitry Andric // If this statement is a `requires` clause from the top-level function
1280*700637cbSDimitry Andric // being traversed, ignore it, since it's not generating runtime code.
1281*700637cbSDimitry Andric // We skip the traversal of lambdas (beyond their captures, see
1282*700637cbSDimitry Andric // TraverseLambdaExpr below), so just caching this from our constructor
1283*700637cbSDimitry Andric // should suffice.
1284*700637cbSDimitry Andric if (Statement != TrailingRequiresClause && Statement != NoexceptExpr)
1285*700637cbSDimitry Andric return DynamicRecursiveASTVisitor::TraverseStmt(Statement);
1286*700637cbSDimitry Andric return true;
1287*700637cbSDimitry Andric }
1288*700637cbSDimitry Andric
TraverseConstructorInitializer__anon1adc617b0111::Analyzer::FunctionBodyASTVisitor1289*700637cbSDimitry Andric bool TraverseConstructorInitializer(CXXCtorInitializer *Init) override {
1290*700637cbSDimitry Andric ViolationSite PrevVS = VSite;
1291*700637cbSDimitry Andric if (Init->isAnyMemberInitializer())
1292*700637cbSDimitry Andric VSite.setKind(ViolationSite::Kind::MemberInitializer);
1293*700637cbSDimitry Andric bool Result =
1294*700637cbSDimitry Andric DynamicRecursiveASTVisitor::TraverseConstructorInitializer(Init);
1295*700637cbSDimitry Andric VSite = PrevVS;
1296*700637cbSDimitry Andric return Result;
1297*700637cbSDimitry Andric }
1298*700637cbSDimitry Andric
TraverseCXXDefaultArgExpr__anon1adc617b0111::Analyzer::FunctionBodyASTVisitor1299*700637cbSDimitry Andric bool TraverseCXXDefaultArgExpr(CXXDefaultArgExpr *E) override {
1300*700637cbSDimitry Andric LLVM_DEBUG(llvm::dbgs()
1301*700637cbSDimitry Andric << "TraverseCXXDefaultArgExpr : "
1302*700637cbSDimitry Andric << E->getUsedLocation().printToString(Outer.S.SourceMgr)
1303*700637cbSDimitry Andric << "\n";);
1304*700637cbSDimitry Andric
1305*700637cbSDimitry Andric ViolationSite PrevVS = VSite;
1306*700637cbSDimitry Andric if (VSite.kind() == ViolationSite::Kind::Default)
1307*700637cbSDimitry Andric VSite = ViolationSite{E};
1308*700637cbSDimitry Andric
1309*700637cbSDimitry Andric bool Result = DynamicRecursiveASTVisitor::TraverseCXXDefaultArgExpr(E);
1310*700637cbSDimitry Andric VSite = PrevVS;
1311*700637cbSDimitry Andric return Result;
1312*700637cbSDimitry Andric }
1313*700637cbSDimitry Andric
TraverseLambdaExpr__anon1adc617b0111::Analyzer::FunctionBodyASTVisitor1314*700637cbSDimitry Andric bool TraverseLambdaExpr(LambdaExpr *Lambda) override {
1315*700637cbSDimitry Andric // We override this so as to be able to skip traversal of the lambda's
1316*700637cbSDimitry Andric // body. We have to explicitly traverse the captures. Why not return
1317*700637cbSDimitry Andric // false from shouldVisitLambdaBody()? Because we need to visit a lambda's
1318*700637cbSDimitry Andric // body when we are verifying the lambda itself; we only want to skip it
1319*700637cbSDimitry Andric // in the context of the outer function.
1320*700637cbSDimitry Andric for (unsigned I = 0, N = Lambda->capture_size(); I < N; ++I)
1321*700637cbSDimitry Andric TraverseLambdaCapture(Lambda, Lambda->capture_begin() + I,
1322*700637cbSDimitry Andric Lambda->capture_init_begin()[I]);
1323*700637cbSDimitry Andric
1324*700637cbSDimitry Andric return true;
1325*700637cbSDimitry Andric }
1326*700637cbSDimitry Andric
TraverseBlockExpr__anon1adc617b0111::Analyzer::FunctionBodyASTVisitor1327*700637cbSDimitry Andric bool TraverseBlockExpr(BlockExpr * /*unused*/) override {
1328*700637cbSDimitry Andric // As with lambdas, don't traverse the block's body.
1329*700637cbSDimitry Andric // TODO: are the capture expressions (ctor call?) safe?
1330*700637cbSDimitry Andric return true;
1331*700637cbSDimitry Andric }
1332*700637cbSDimitry Andric
VisitDeclRefExpr__anon1adc617b0111::Analyzer::FunctionBodyASTVisitor1333*700637cbSDimitry Andric bool VisitDeclRefExpr(DeclRefExpr *E) override {
1334*700637cbSDimitry Andric const ValueDecl *Val = E->getDecl();
1335*700637cbSDimitry Andric if (const auto *Var = dyn_cast<VarDecl>(Val)) {
1336*700637cbSDimitry Andric if (Var->getTLSKind() != VarDecl::TLS_None) {
1337*700637cbSDimitry Andric // At least on macOS, thread-local variables are initialized on
1338*700637cbSDimitry Andric // first access, including a heap allocation.
1339*700637cbSDimitry Andric diagnoseLanguageConstruct(FunctionEffect::FE_ExcludeThreadLocalVars,
1340*700637cbSDimitry Andric ViolationID::AccessesThreadLocalVariable,
1341*700637cbSDimitry Andric E->getLocation());
1342*700637cbSDimitry Andric }
1343*700637cbSDimitry Andric }
1344*700637cbSDimitry Andric return true;
1345*700637cbSDimitry Andric }
1346*700637cbSDimitry Andric
TraverseGenericSelectionExpr__anon1adc617b0111::Analyzer::FunctionBodyASTVisitor1347*700637cbSDimitry Andric bool TraverseGenericSelectionExpr(GenericSelectionExpr *Node) override {
1348*700637cbSDimitry Andric return TraverseStmt(Node->getResultExpr());
1349*700637cbSDimitry Andric }
1350*700637cbSDimitry Andric bool
TraverseUnaryExprOrTypeTraitExpr__anon1adc617b0111::Analyzer::FunctionBodyASTVisitor1351*700637cbSDimitry Andric TraverseUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *Node) override {
1352*700637cbSDimitry Andric return true;
1353*700637cbSDimitry Andric }
1354*700637cbSDimitry Andric
TraverseTypeOfExprTypeLoc__anon1adc617b0111::Analyzer::FunctionBodyASTVisitor1355*700637cbSDimitry Andric bool TraverseTypeOfExprTypeLoc(TypeOfExprTypeLoc Node) override {
1356*700637cbSDimitry Andric return true;
1357*700637cbSDimitry Andric }
1358*700637cbSDimitry Andric
TraverseDecltypeTypeLoc__anon1adc617b0111::Analyzer::FunctionBodyASTVisitor1359*700637cbSDimitry Andric bool TraverseDecltypeTypeLoc(DecltypeTypeLoc Node) override { return true; }
1360*700637cbSDimitry Andric
TraverseCXXNoexceptExpr__anon1adc617b0111::Analyzer::FunctionBodyASTVisitor1361*700637cbSDimitry Andric bool TraverseCXXNoexceptExpr(CXXNoexceptExpr *Node) override {
1362*700637cbSDimitry Andric return true;
1363*700637cbSDimitry Andric }
1364*700637cbSDimitry Andric
TraverseCXXTypeidExpr__anon1adc617b0111::Analyzer::FunctionBodyASTVisitor1365*700637cbSDimitry Andric bool TraverseCXXTypeidExpr(CXXTypeidExpr *Node) override { return true; }
1366*700637cbSDimitry Andric
1367*700637cbSDimitry Andric // Skip concept requirements since they don't generate code.
TraverseConceptRequirement__anon1adc617b0111::Analyzer::FunctionBodyASTVisitor1368*700637cbSDimitry Andric bool TraverseConceptRequirement(concepts::Requirement *R) override {
1369*700637cbSDimitry Andric return true;
1370*700637cbSDimitry Andric }
1371*700637cbSDimitry Andric };
1372*700637cbSDimitry Andric };
1373*700637cbSDimitry Andric
~AnalysisMap()1374*700637cbSDimitry Andric Analyzer::AnalysisMap::~AnalysisMap() {
1375*700637cbSDimitry Andric for (const auto &Item : *this) {
1376*700637cbSDimitry Andric FuncAnalysisPtr AP = Item.second;
1377*700637cbSDimitry Andric if (auto *PFA = dyn_cast<PendingFunctionAnalysis *>(AP))
1378*700637cbSDimitry Andric delete PFA;
1379*700637cbSDimitry Andric else
1380*700637cbSDimitry Andric delete cast<CompleteFunctionAnalysis *>(AP);
1381*700637cbSDimitry Andric }
1382*700637cbSDimitry Andric }
1383*700637cbSDimitry Andric
1384*700637cbSDimitry Andric } // anonymous namespace
1385*700637cbSDimitry Andric
1386*700637cbSDimitry Andric namespace clang {
1387*700637cbSDimitry Andric
diagnoseConflictingFunctionEffect(const FunctionEffectsRef & FX,const FunctionEffectWithCondition & NewEC,SourceLocation NewAttrLoc)1388*700637cbSDimitry Andric bool Sema::diagnoseConflictingFunctionEffect(
1389*700637cbSDimitry Andric const FunctionEffectsRef &FX, const FunctionEffectWithCondition &NewEC,
1390*700637cbSDimitry Andric SourceLocation NewAttrLoc) {
1391*700637cbSDimitry Andric // If the new effect has a condition, we can't detect conflicts until the
1392*700637cbSDimitry Andric // condition is resolved.
1393*700637cbSDimitry Andric if (NewEC.Cond.getCondition() != nullptr)
1394*700637cbSDimitry Andric return false;
1395*700637cbSDimitry Andric
1396*700637cbSDimitry Andric // Diagnose the new attribute as incompatible with a previous one.
1397*700637cbSDimitry Andric auto Incompatible = [&](const FunctionEffectWithCondition &PrevEC) {
1398*700637cbSDimitry Andric Diag(NewAttrLoc, diag::err_attributes_are_not_compatible)
1399*700637cbSDimitry Andric << ("'" + NewEC.description() + "'")
1400*700637cbSDimitry Andric << ("'" + PrevEC.description() + "'") << false;
1401*700637cbSDimitry Andric // We don't necessarily have the location of the previous attribute,
1402*700637cbSDimitry Andric // so no note.
1403*700637cbSDimitry Andric return true;
1404*700637cbSDimitry Andric };
1405*700637cbSDimitry Andric
1406*700637cbSDimitry Andric // Compare against previous attributes.
1407*700637cbSDimitry Andric FunctionEffect::Kind NewKind = NewEC.Effect.kind();
1408*700637cbSDimitry Andric
1409*700637cbSDimitry Andric for (const FunctionEffectWithCondition &PrevEC : FX) {
1410*700637cbSDimitry Andric // Again, can't check yet when the effect is conditional.
1411*700637cbSDimitry Andric if (PrevEC.Cond.getCondition() != nullptr)
1412*700637cbSDimitry Andric continue;
1413*700637cbSDimitry Andric
1414*700637cbSDimitry Andric FunctionEffect::Kind PrevKind = PrevEC.Effect.kind();
1415*700637cbSDimitry Andric // Note that we allow PrevKind == NewKind; it's redundant and ignored.
1416*700637cbSDimitry Andric
1417*700637cbSDimitry Andric if (PrevEC.Effect.oppositeKind() == NewKind)
1418*700637cbSDimitry Andric return Incompatible(PrevEC);
1419*700637cbSDimitry Andric
1420*700637cbSDimitry Andric // A new allocating is incompatible with a previous nonblocking.
1421*700637cbSDimitry Andric if (PrevKind == FunctionEffect::Kind::NonBlocking &&
1422*700637cbSDimitry Andric NewKind == FunctionEffect::Kind::Allocating)
1423*700637cbSDimitry Andric return Incompatible(PrevEC);
1424*700637cbSDimitry Andric
1425*700637cbSDimitry Andric // A new nonblocking is incompatible with a previous allocating.
1426*700637cbSDimitry Andric if (PrevKind == FunctionEffect::Kind::Allocating &&
1427*700637cbSDimitry Andric NewKind == FunctionEffect::Kind::NonBlocking)
1428*700637cbSDimitry Andric return Incompatible(PrevEC);
1429*700637cbSDimitry Andric }
1430*700637cbSDimitry Andric
1431*700637cbSDimitry Andric return false;
1432*700637cbSDimitry Andric }
1433*700637cbSDimitry Andric
diagnoseFunctionEffectMergeConflicts(const FunctionEffectSet::Conflicts & Errs,SourceLocation NewLoc,SourceLocation OldLoc)1434*700637cbSDimitry Andric void Sema::diagnoseFunctionEffectMergeConflicts(
1435*700637cbSDimitry Andric const FunctionEffectSet::Conflicts &Errs, SourceLocation NewLoc,
1436*700637cbSDimitry Andric SourceLocation OldLoc) {
1437*700637cbSDimitry Andric for (const FunctionEffectSet::Conflict &Conflict : Errs) {
1438*700637cbSDimitry Andric Diag(NewLoc, diag::warn_conflicting_func_effects)
1439*700637cbSDimitry Andric << Conflict.Kept.description() << Conflict.Rejected.description();
1440*700637cbSDimitry Andric Diag(OldLoc, diag::note_previous_declaration);
1441*700637cbSDimitry Andric }
1442*700637cbSDimitry Andric }
1443*700637cbSDimitry Andric
1444*700637cbSDimitry Andric // Decl should be a FunctionDecl or BlockDecl.
maybeAddDeclWithEffects(const Decl * D,const FunctionEffectsRef & FX)1445*700637cbSDimitry Andric void Sema::maybeAddDeclWithEffects(const Decl *D,
1446*700637cbSDimitry Andric const FunctionEffectsRef &FX) {
1447*700637cbSDimitry Andric if (!D->hasBody()) {
1448*700637cbSDimitry Andric if (const auto *FD = D->getAsFunction(); FD && !FD->willHaveBody())
1449*700637cbSDimitry Andric return;
1450*700637cbSDimitry Andric }
1451*700637cbSDimitry Andric
1452*700637cbSDimitry Andric if (Diags.getIgnoreAllWarnings() ||
1453*700637cbSDimitry Andric (Diags.getSuppressSystemWarnings() &&
1454*700637cbSDimitry Andric SourceMgr.isInSystemHeader(D->getLocation())))
1455*700637cbSDimitry Andric return;
1456*700637cbSDimitry Andric
1457*700637cbSDimitry Andric if (hasUncompilableErrorOccurred())
1458*700637cbSDimitry Andric return;
1459*700637cbSDimitry Andric
1460*700637cbSDimitry Andric // For code in dependent contexts, we'll do this at instantiation time.
1461*700637cbSDimitry Andric // Without this check, we would analyze the function based on placeholder
1462*700637cbSDimitry Andric // template parameters, and potentially generate spurious diagnostics.
1463*700637cbSDimitry Andric if (cast<DeclContext>(D)->isDependentContext())
1464*700637cbSDimitry Andric return;
1465*700637cbSDimitry Andric
1466*700637cbSDimitry Andric addDeclWithEffects(D, FX);
1467*700637cbSDimitry Andric }
1468*700637cbSDimitry Andric
addDeclWithEffects(const Decl * D,const FunctionEffectsRef & FX)1469*700637cbSDimitry Andric void Sema::addDeclWithEffects(const Decl *D, const FunctionEffectsRef &FX) {
1470*700637cbSDimitry Andric // To avoid the possibility of conflict, don't add effects which are
1471*700637cbSDimitry Andric // not FE_InferrableOnCallees and therefore not verified; this removes
1472*700637cbSDimitry Andric // blocking/allocating but keeps nonblocking/nonallocating.
1473*700637cbSDimitry Andric // Also, ignore any conditions when building the list of effects.
1474*700637cbSDimitry Andric bool AnyVerifiable = false;
1475*700637cbSDimitry Andric for (const FunctionEffectWithCondition &EC : FX)
1476*700637cbSDimitry Andric if (EC.Effect.flags() & FunctionEffect::FE_InferrableOnCallees) {
1477*700637cbSDimitry Andric AllEffectsToVerify.insert(EC.Effect);
1478*700637cbSDimitry Andric AnyVerifiable = true;
1479*700637cbSDimitry Andric }
1480*700637cbSDimitry Andric
1481*700637cbSDimitry Andric // Record the declaration for later analysis.
1482*700637cbSDimitry Andric if (AnyVerifiable)
1483*700637cbSDimitry Andric DeclsWithEffectsToVerify.push_back(D);
1484*700637cbSDimitry Andric }
1485*700637cbSDimitry Andric
performFunctionEffectAnalysis(TranslationUnitDecl * TU)1486*700637cbSDimitry Andric void Sema::performFunctionEffectAnalysis(TranslationUnitDecl *TU) {
1487*700637cbSDimitry Andric if (hasUncompilableErrorOccurred() || Diags.getIgnoreAllWarnings())
1488*700637cbSDimitry Andric return;
1489*700637cbSDimitry Andric if (TU == nullptr)
1490*700637cbSDimitry Andric return;
1491*700637cbSDimitry Andric Analyzer{*this}.run(*TU);
1492*700637cbSDimitry Andric }
1493*700637cbSDimitry Andric
FunctionEffectDiffVector(const FunctionEffectsRef & Old,const FunctionEffectsRef & New)1494*700637cbSDimitry Andric Sema::FunctionEffectDiffVector::FunctionEffectDiffVector(
1495*700637cbSDimitry Andric const FunctionEffectsRef &Old, const FunctionEffectsRef &New) {
1496*700637cbSDimitry Andric
1497*700637cbSDimitry Andric FunctionEffectsRef::iterator POld = Old.begin();
1498*700637cbSDimitry Andric FunctionEffectsRef::iterator OldEnd = Old.end();
1499*700637cbSDimitry Andric FunctionEffectsRef::iterator PNew = New.begin();
1500*700637cbSDimitry Andric FunctionEffectsRef::iterator NewEnd = New.end();
1501*700637cbSDimitry Andric
1502*700637cbSDimitry Andric while (true) {
1503*700637cbSDimitry Andric int cmp = 0;
1504*700637cbSDimitry Andric if (POld == OldEnd) {
1505*700637cbSDimitry Andric if (PNew == NewEnd)
1506*700637cbSDimitry Andric break;
1507*700637cbSDimitry Andric cmp = 1;
1508*700637cbSDimitry Andric } else if (PNew == NewEnd)
1509*700637cbSDimitry Andric cmp = -1;
1510*700637cbSDimitry Andric else {
1511*700637cbSDimitry Andric FunctionEffectWithCondition Old = *POld;
1512*700637cbSDimitry Andric FunctionEffectWithCondition New = *PNew;
1513*700637cbSDimitry Andric if (Old.Effect.kind() < New.Effect.kind())
1514*700637cbSDimitry Andric cmp = -1;
1515*700637cbSDimitry Andric else if (New.Effect.kind() < Old.Effect.kind())
1516*700637cbSDimitry Andric cmp = 1;
1517*700637cbSDimitry Andric else {
1518*700637cbSDimitry Andric cmp = 0;
1519*700637cbSDimitry Andric if (Old.Cond.getCondition() != New.Cond.getCondition()) {
1520*700637cbSDimitry Andric // FIXME: Cases where the expressions are equivalent but
1521*700637cbSDimitry Andric // don't have the same identity.
1522*700637cbSDimitry Andric push_back(FunctionEffectDiff{
1523*700637cbSDimitry Andric Old.Effect.kind(), FunctionEffectDiff::Kind::ConditionMismatch,
1524*700637cbSDimitry Andric Old, New});
1525*700637cbSDimitry Andric }
1526*700637cbSDimitry Andric }
1527*700637cbSDimitry Andric }
1528*700637cbSDimitry Andric
1529*700637cbSDimitry Andric if (cmp < 0) {
1530*700637cbSDimitry Andric // removal
1531*700637cbSDimitry Andric FunctionEffectWithCondition Old = *POld;
1532*700637cbSDimitry Andric push_back(FunctionEffectDiff{Old.Effect.kind(),
1533*700637cbSDimitry Andric FunctionEffectDiff::Kind::Removed, Old,
1534*700637cbSDimitry Andric std::nullopt});
1535*700637cbSDimitry Andric ++POld;
1536*700637cbSDimitry Andric } else if (cmp > 0) {
1537*700637cbSDimitry Andric // addition
1538*700637cbSDimitry Andric FunctionEffectWithCondition New = *PNew;
1539*700637cbSDimitry Andric push_back(FunctionEffectDiff{New.Effect.kind(),
1540*700637cbSDimitry Andric FunctionEffectDiff::Kind::Added,
1541*700637cbSDimitry Andric std::nullopt, New});
1542*700637cbSDimitry Andric ++PNew;
1543*700637cbSDimitry Andric } else {
1544*700637cbSDimitry Andric ++POld;
1545*700637cbSDimitry Andric ++PNew;
1546*700637cbSDimitry Andric }
1547*700637cbSDimitry Andric }
1548*700637cbSDimitry Andric }
1549*700637cbSDimitry Andric
shouldDiagnoseConversion(QualType SrcType,const FunctionEffectsRef & SrcFX,QualType DstType,const FunctionEffectsRef & DstFX) const1550*700637cbSDimitry Andric bool Sema::FunctionEffectDiff::shouldDiagnoseConversion(
1551*700637cbSDimitry Andric QualType SrcType, const FunctionEffectsRef &SrcFX, QualType DstType,
1552*700637cbSDimitry Andric const FunctionEffectsRef &DstFX) const {
1553*700637cbSDimitry Andric
1554*700637cbSDimitry Andric switch (EffectKind) {
1555*700637cbSDimitry Andric case FunctionEffect::Kind::NonAllocating:
1556*700637cbSDimitry Andric // nonallocating can't be added (spoofed) during a conversion, unless we
1557*700637cbSDimitry Andric // have nonblocking.
1558*700637cbSDimitry Andric if (DiffKind == Kind::Added) {
1559*700637cbSDimitry Andric for (const auto &CFE : SrcFX) {
1560*700637cbSDimitry Andric if (CFE.Effect.kind() == FunctionEffect::Kind::NonBlocking)
1561*700637cbSDimitry Andric return false;
1562*700637cbSDimitry Andric }
1563*700637cbSDimitry Andric }
1564*700637cbSDimitry Andric [[fallthrough]];
1565*700637cbSDimitry Andric case FunctionEffect::Kind::NonBlocking:
1566*700637cbSDimitry Andric // nonblocking can't be added (spoofed) during a conversion.
1567*700637cbSDimitry Andric switch (DiffKind) {
1568*700637cbSDimitry Andric case Kind::Added:
1569*700637cbSDimitry Andric return true;
1570*700637cbSDimitry Andric case Kind::Removed:
1571*700637cbSDimitry Andric return false;
1572*700637cbSDimitry Andric case Kind::ConditionMismatch:
1573*700637cbSDimitry Andric // FIXME: Condition mismatches are too coarse right now -- expressions
1574*700637cbSDimitry Andric // which are equivalent but don't have the same identity are detected as
1575*700637cbSDimitry Andric // mismatches. We're going to diagnose those anyhow until expression
1576*700637cbSDimitry Andric // matching is better.
1577*700637cbSDimitry Andric return true;
1578*700637cbSDimitry Andric }
1579*700637cbSDimitry Andric break;
1580*700637cbSDimitry Andric case FunctionEffect::Kind::Blocking:
1581*700637cbSDimitry Andric case FunctionEffect::Kind::Allocating:
1582*700637cbSDimitry Andric return false;
1583*700637cbSDimitry Andric }
1584*700637cbSDimitry Andric llvm_unreachable("unknown effect kind");
1585*700637cbSDimitry Andric }
1586*700637cbSDimitry Andric
shouldDiagnoseRedeclaration(const FunctionDecl & OldFunction,const FunctionEffectsRef & OldFX,const FunctionDecl & NewFunction,const FunctionEffectsRef & NewFX) const1587*700637cbSDimitry Andric bool Sema::FunctionEffectDiff::shouldDiagnoseRedeclaration(
1588*700637cbSDimitry Andric const FunctionDecl &OldFunction, const FunctionEffectsRef &OldFX,
1589*700637cbSDimitry Andric const FunctionDecl &NewFunction, const FunctionEffectsRef &NewFX) const {
1590*700637cbSDimitry Andric switch (EffectKind) {
1591*700637cbSDimitry Andric case FunctionEffect::Kind::NonAllocating:
1592*700637cbSDimitry Andric case FunctionEffect::Kind::NonBlocking:
1593*700637cbSDimitry Andric // nonblocking/nonallocating can't be removed in a redeclaration.
1594*700637cbSDimitry Andric switch (DiffKind) {
1595*700637cbSDimitry Andric case Kind::Added:
1596*700637cbSDimitry Andric return false; // No diagnostic.
1597*700637cbSDimitry Andric case Kind::Removed:
1598*700637cbSDimitry Andric return true; // Issue diagnostic.
1599*700637cbSDimitry Andric case Kind::ConditionMismatch:
1600*700637cbSDimitry Andric // All these forms of mismatches are diagnosed.
1601*700637cbSDimitry Andric return true;
1602*700637cbSDimitry Andric }
1603*700637cbSDimitry Andric break;
1604*700637cbSDimitry Andric case FunctionEffect::Kind::Blocking:
1605*700637cbSDimitry Andric case FunctionEffect::Kind::Allocating:
1606*700637cbSDimitry Andric return false;
1607*700637cbSDimitry Andric }
1608*700637cbSDimitry Andric llvm_unreachable("unknown effect kind");
1609*700637cbSDimitry Andric }
1610*700637cbSDimitry Andric
1611*700637cbSDimitry Andric Sema::FunctionEffectDiff::OverrideResult
shouldDiagnoseMethodOverride(const CXXMethodDecl & OldMethod,const FunctionEffectsRef & OldFX,const CXXMethodDecl & NewMethod,const FunctionEffectsRef & NewFX) const1612*700637cbSDimitry Andric Sema::FunctionEffectDiff::shouldDiagnoseMethodOverride(
1613*700637cbSDimitry Andric const CXXMethodDecl &OldMethod, const FunctionEffectsRef &OldFX,
1614*700637cbSDimitry Andric const CXXMethodDecl &NewMethod, const FunctionEffectsRef &NewFX) const {
1615*700637cbSDimitry Andric switch (EffectKind) {
1616*700637cbSDimitry Andric case FunctionEffect::Kind::NonAllocating:
1617*700637cbSDimitry Andric case FunctionEffect::Kind::NonBlocking:
1618*700637cbSDimitry Andric switch (DiffKind) {
1619*700637cbSDimitry Andric
1620*700637cbSDimitry Andric // If added on an override, that's fine and not diagnosed.
1621*700637cbSDimitry Andric case Kind::Added:
1622*700637cbSDimitry Andric return OverrideResult::NoAction;
1623*700637cbSDimitry Andric
1624*700637cbSDimitry Andric // If missing from an override (removed), propagate from base to derived.
1625*700637cbSDimitry Andric case Kind::Removed:
1626*700637cbSDimitry Andric return OverrideResult::Merge;
1627*700637cbSDimitry Andric
1628*700637cbSDimitry Andric // If there's a mismatch involving the effect's polarity or condition,
1629*700637cbSDimitry Andric // issue a warning.
1630*700637cbSDimitry Andric case Kind::ConditionMismatch:
1631*700637cbSDimitry Andric return OverrideResult::Warn;
1632*700637cbSDimitry Andric }
1633*700637cbSDimitry Andric break;
1634*700637cbSDimitry Andric case FunctionEffect::Kind::Blocking:
1635*700637cbSDimitry Andric case FunctionEffect::Kind::Allocating:
1636*700637cbSDimitry Andric return OverrideResult::NoAction;
1637*700637cbSDimitry Andric }
1638*700637cbSDimitry Andric llvm_unreachable("unknown effect kind");
1639*700637cbSDimitry Andric }
1640*700637cbSDimitry Andric
1641*700637cbSDimitry Andric } // namespace clang
1642