================ @@ -2397,6 +2397,1262 @@ class UnsafeBufferUsageReporter : public UnsafeBufferUsageHandler { }; } // namespace +// ============================================================================= + +namespace FXAnalysis { + +enum class DiagnosticID : uint8_t { + None = 0, // sentinel for an empty Diagnostic + Throws, + Catches, + CallsObjC, + AllocatesMemory, + HasStaticLocal, + AccessesThreadLocal, + + // These only apply to callees, where the analysis stops at the Decl + DeclDisallowsInference, + + CallsDeclWithoutEffect, + CallsExprWithoutEffect, +}; + +// Holds an effect diagnosis, potentially for the entire duration of the +// analysis phase, in order to refer to it when explaining why a caller has been +// made unsafe by a callee. +struct Diagnostic { + FunctionEffect Effect; + DiagnosticID ID = DiagnosticID::None; + SourceLocation Loc; + const Decl *Callee = nullptr; // only valid for Calls* + + Diagnostic() = default; + + Diagnostic(const FunctionEffect &Effect, DiagnosticID ID, SourceLocation Loc, + const Decl *Callee = nullptr) + : Effect(Effect), ID(ID), Loc(Loc), Callee(Callee) {} +}; + +enum class SpecialFuncType : uint8_t { None, OperatorNew, OperatorDelete }; +enum class CallType { + // unknown: probably function pointer + Unknown, + Function, + Virtual, + Block +}; + +// Return whether a function's effects CAN be verified. +// The question of whether it SHOULD be verified is independent. +static bool functionIsVerifiable(const FunctionDecl *FD) { + if (!(FD->hasBody() || FD->isInlined())) { + // externally defined; we couldn't verify if we wanted to. + return false; + } + if (FD->isTrivial()) { + // Otherwise `struct x { int a; };` would have an unverifiable default + // constructor. + return true; + } + return true; +} + +/// A mutable set of FunctionEffect, for use in places where any conditions +/// have been resolved or can be ignored. +class EffectSet { + // This implementation optimizes footprint, since we hold one of these for + // every function visited, which, due to inference, can be many more functions + // than have declared effects. + + template <typename T, typename SizeT, SizeT Capacity> struct FixedVector { + SizeT Count = 0; + T Items[Capacity] = {}; + + using value_type = T; + + using iterator = T *; + using const_iterator = const T *; + iterator begin() { return &Items[0]; } + iterator end() { return &Items[Count]; } + const_iterator begin() const { return &Items[0]; } + const_iterator end() const { return &Items[Count]; } + const_iterator cbegin() const { return &Items[0]; } + const_iterator cend() const { return &Items[Count]; } + + void insert(iterator I, const T &Value) { + assert(Count < Capacity); + iterator E = end(); + if (I != E) + std::copy_backward(I, E, E + 1); + *I = Value; + ++Count; + } + + void push_back(const T &Value) { + assert(Count < Capacity); + Items[Count++] = Value; + } + }; + + // As long as FunctionEffect is only 1 byte, and there are only 2 verifiable + // effects, this fixed-size vector with a capacity of 7 is more than + // sufficient and is only 8 bytes. + FixedVector<FunctionEffect, uint8_t, 7> Impl; ---------------- dougsonos wrote:
After trying parts of each of these options, I settled on 3, naming it `FunctionEffectKindSet`, holding just a bitmap of the `FunctionEffect::Kind`s. Instead of making it convertible to `ArrayRef<FunctionEffect>`, changed the interface of the one method requiring one. Will push after addressing more feedback. https://github.com/llvm/llvm-project/pull/99656 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits