[clang] nonblocking/nonallocating attributes (was: nolock/noalloc) (PR #84983)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Apr 9 08:58:48 PDT 2024
================
@@ -4429,6 +4433,218 @@ class FunctionNoProtoType : public FunctionType, public llvm::FoldingSetNode {
}
};
+// ------------------------------------------------------------------------------
+
+// TODO: Should FunctionEffect be located elsewhere, where Decl is not
+// forward-declared?
+class Decl;
+class CXXMethodDecl;
+class FunctionEffectSet;
+class TypeSourceInfo;
+
+/// Represents an abstract function effect.
+class FunctionEffect {
+public:
+ /// Identifies the particular type of effect.
+ enum class Type {
+ None = 0,
+ NonBlocking,
+ NonAllocating,
+ };
+
+ /// Flags describing behaviors of the effect.
+ // (Why not a struct with bitfields? There's one function that would like to
+ // test a caller-specified bit. There are some potential optimizations that
+ // would OR together the bits of multiple effects.)
+ using Flags = unsigned;
+ enum FlagBit : unsigned {
+ // Can verification inspect callees' implementations? (e.g. nonblocking:
+ // yes, tcb+types: no)
+ FE_InferrableOnCallees = 0x1,
+
+ // Language constructs which effects can diagnose as disallowed.
+ FE_ExcludeThrow = 0x2,
+ FE_ExcludeCatch = 0x4,
+ FE_ExcludeObjCMessageSend = 0x8,
+ FE_ExcludeStaticLocalVars = 0x10,
+ FE_ExcludeThreadLocalVars = 0x20
+ };
+
+ /// Describes the result of effects differing between a base class's virtual
+ /// method and an overriding method in a subclass.
+ enum class OverrideResult {
+ Ignore,
+ Warn,
+ Propagate // Base method's effects are merged with those of the override.
+ };
+
+private:
+ // For uniqueness, currently only Type_ is significant.
+
+ LLVM_PREFERRED_TYPE(Type)
+ unsigned Type_ : 2;
+ Flags Flags_ : 8; // A constant function of Type but cached here.
+
+ // Expansion: for hypothetical TCB+types, there could be one Type for TCB,
+ // then ~16(?) bits "Subtype" to map to a specific named TCB. Subtype would
+ // be considered for uniqueness.
+
+ // Since this struct is serialized as if it were a uint32_t, it's important
+ // to pad and explicitly zero the extra bits.
+ [[maybe_unused]] unsigned Padding : 22;
+
+public:
+ using CalleeDeclOrType =
+ llvm::PointerUnion<const Decl *, const FunctionProtoType *>;
+
+ FunctionEffect() : Type_(unsigned(Type::None)), Flags_(0), Padding(0) {}
+
+ explicit FunctionEffect(Type T);
+
+ /// The type of the effect.
+ Type type() const { return Type(Type_); }
+
+ /// Flags describing behaviors of the effect.
+ Flags flags() const { return Flags_; }
+
+ /// The description printed in diagnostics, e.g. 'nonblocking'.
+ StringRef name() const;
+
+ /// A hashable representation.
+ uint32_t opaqueRepr() const { return Type_ | (Flags_ << 2u); }
+
+ /// Return true if adding or removing the effect as part of a type conversion
+ /// should generate a diagnostic.
+ bool diagnoseConversion(bool Adding, QualType OldType,
+ FunctionEffectSet OldFX, QualType NewType,
+ FunctionEffectSet NewFX) const;
+
+ /// Return true if adding or removing the effect in a redeclaration should
+ /// generate a diagnostic.
+ bool diagnoseRedeclaration(bool Adding, const FunctionDecl &OldFunction,
+ FunctionEffectSet OldFX,
+ const FunctionDecl &NewFunction,
+ FunctionEffectSet NewFX) const;
+
+ /// Return true if adding or removing the effect in a C++ virtual method
+ /// override should generate a diagnostic.
+ OverrideResult diagnoseMethodOverride(bool Adding,
+ const CXXMethodDecl &OldMethod,
+ FunctionEffectSet OldFX,
+ const CXXMethodDecl &NewMethod,
+ FunctionEffectSet NewFX) const;
+
+ /// Return true if the effect is allowed to be inferred on a Decl of the
+ /// specified type (generally a FunctionProtoType but TypeSourceInfo is
+ /// provided so any AttributedType sugar can be examined). TSI can be null
+ /// on an implicit function like a default constructor.
+ ///
+ /// This is only used if the effect has FE_InferrableOnCallees flag set.
+ /// Example: This allows nonblocking(false) to prevent inference for the
+ /// function.
+ bool canInferOnFunction(QualType QT, const TypeSourceInfo *FType) const;
+
+ // Return false for success. When true is returned for a direct call, then the
+ // FE_InferrableOnCallees flag may trigger inference rather than an immediate
+ // diagnostic. Caller should be assumed to have the effect (it may not have it
+ // explicitly when inferring).
+ bool diagnoseFunctionCall(bool Direct, FunctionEffectSet CalleeFX) const;
+
+ friend bool operator==(const FunctionEffect &LHS, const FunctionEffect &RHS) {
+ return LHS.Type_ == RHS.Type_;
+ }
+ friend bool operator!=(const FunctionEffect &LHS, const FunctionEffect &RHS) {
+ return LHS.Type_ != RHS.Type_;
+ }
+ friend bool operator<(const FunctionEffect &LHS, const FunctionEffect &RHS) {
+ return LHS.Type_ < RHS.Type_;
+ }
+};
+
+// It is the user's responsibility to keep this in set form: elements are
+// ordered and unique.
+// We could hide the mutating methods which are capable of breaking the
+// invariant, but they're needed and safe when used with STL set algorithms.
+class MutableFunctionEffectSet : public SmallVector<FunctionEffect, 4> {
+public:
+ using SmallVector::insert;
+ using SmallVector::SmallVector;
+
+ MutableFunctionEffectSet(const FunctionEffect &Effect);
+ using Base = SmallVector<FunctionEffect, 4>;
+
+ /// Maintains order/uniquenesss.
+ void insert(const FunctionEffect &Effect);
+
+ MutableFunctionEffectSet &operator|=(FunctionEffectSet RHS);
+
+ operator llvm::ArrayRef<FunctionEffect>() const { return {data(), size()}; }
+};
+
+/// A constant, uniqued set of FunctionEffect instances.
+// These sets will tend to be very small (0-1 elements), so represent them as
+// sorted spans, which are compatible with the STL set algorithms.
+class FunctionEffectSet {
+private:
+ friend class ASTContext; // so it can call the private constructor
+
+ explicit FunctionEffectSet(llvm::ArrayRef<FunctionEffect> Array)
+ : Impl(Array) {}
+
+ // Points to a separately allocated array, uniqued.
+ llvm::ArrayRef<FunctionEffect> Impl;
+
+public:
+ using Differences = SmallVector<std::pair<FunctionEffect, /*added=*/bool>>;
+
+ FunctionEffectSet() = default;
+
+ const void *getOpaqueValue() const { return Impl.data(); }
+ llvm::ArrayRef<uint32_t> serializable() const {
+ static_assert(sizeof(FunctionEffect) == sizeof(uint32_t));
+ const uint32_t *ptr = reinterpret_cast<const uint32_t *>(Impl.data());
+ return {const_cast<uint32_t *>(ptr), Impl.size()};
----------------
Sirraide wrote:
Pretty sure this is UB since you can’t just access a `FunctionEffect` via a `uint32_t*`. Returning an `ArrayRef<char>` should be fine since any object can be accessed via a `char*`, but also, do we have to do this this way?
https://github.com/llvm/llvm-project/pull/84983
More information about the cfe-commits
mailing list