[clang] nonblocking/nonallocating attributes (was: nolock/noalloc) (PR #84983)

via cfe-commits cfe-commits at lists.llvm.org
Tue Apr 9 08:58:49 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.
----------------
Sirraide wrote:

I don’t think complicating the API for the purpose of being able to use STL algorithms in the implementation is a good idea. It’d probably be less error-prone to just make the small vector a private member.

https://github.com/llvm/llvm-project/pull/84983


More information about the cfe-commits mailing list