================ @@ -4429,6 +4434,284 @@ class FunctionNoProtoType : public FunctionType, public llvm::FoldingSetNode { } }; +// ------------------------------------------------------------------------------ + +class Decl; +class CXXMethodDecl; +class FunctionTypeEffectsRef; +class FunctionTypeEffectSet; + +/* + TODO: Idea about how to move most of the FunctionEffect business out of + Type.h, thus removing these forward declarations. + + - Keep FunctionEffect itself here but make it more minimal. Don't define flags + or any behaviors, just the Kind and an accessor. + - Keep FunctionEffectCondExpr here. + - Make FunctionProtoType and ExtProtoInfo use only ArrayRef<FunctionEffect> + and ArrayRef<FunctionEffectCondExpr>. + - Somewhere in Sema, define ExtFunctionEffect, which holds a FunctionEffect + and has all the behavior-related methods. + - There too, define the containers. FunctionTypeEffectsRef can have a + constructor or factory method that initializes itself from a + FunctionProtoType. +*/ + +/// Represents an abstract function effect, using just an enumeration describing +/// its kind. +class FunctionEffect { +public: + /// Identifies the particular effect. + enum class Kind : uint8_t { + None, + NonBlocking, + NonAllocating, + }; + + /// Flags describing some behaviors of the effect. + using Flags = unsigned; + enum FlagBit : Flags { + // 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, + Merge // Base method's effects are merged with those of the override. + }; + +private: + Kind FKind = Kind::None; + + // Expansion: for hypothetical TCB+types, there could be one Kind for TCB, + // then ~16(?) bits "SubKind" to map to a specific named TCB. SubKind would + // be considered for uniqueness. + +public: + FunctionEffect() = default; + + explicit FunctionEffect(Kind K) : FKind(K) {} + + /// The kind of the effect. + Kind kind() const { return FKind; } + + /// Flags describing some behaviors of the effect. + Flags flags() const { + switch (FKind) { + case Kind::NonBlocking: + return FE_InferrableOnCallees | FE_ExcludeThrow | FE_ExcludeCatch | + FE_ExcludeObjCMessageSend | FE_ExcludeStaticLocalVars | + FE_ExcludeThreadLocalVars; + case Kind::NonAllocating: + // Same as NonBlocking, except without FE_ExcludeStaticLocalVars + return FE_InferrableOnCallees | FE_ExcludeThrow | FE_ExcludeCatch | + FE_ExcludeObjCMessageSend | FE_ExcludeThreadLocalVars; + case Kind::None: + break; + } + llvm_unreachable("unknown effect kind"); + } + + /// The description printed in diagnostics, e.g. 'nonblocking'. + StringRef name() const; + + /// Return true if adding or removing the effect as part of a type conversion + /// should generate a diagnostic. + bool shouldDiagnoseConversion(bool Adding, QualType OldType, + const FunctionTypeEffectsRef &OldFX, + QualType NewType, + const FunctionTypeEffectsRef &NewFX) const; + + /// Return true if adding or removing the effect in a redeclaration should + /// generate a diagnostic. + bool shouldDiagnoseRedeclaration(bool Adding, const FunctionDecl &OldFunction, + const FunctionTypeEffectsRef &OldFX, + const FunctionDecl &NewFunction, + const FunctionTypeEffectsRef &NewFX) const; + + /// Return true if adding or removing the effect in a C++ virtual method + /// override should generate a diagnostic. + OverrideResult + shouldDiagnoseMethodOverride(bool Adding, const CXXMethodDecl &OldMethod, + const FunctionTypeEffectsRef &OldFX, + const CXXMethodDecl &NewMethod, + const FunctionTypeEffectsRef &NewFX) const; + + /// Return true if the effect is allowed to be inferred on the callee, + /// which is either a FunctionDecl or BlockDecl. + /// 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(const Decl &Callee) 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 shouldDiagnoseFunctionCall(bool Direct, + ArrayRef<FunctionEffect> CalleeFX) const; + + friend bool operator==(const FunctionEffect &LHS, const FunctionEffect &RHS) { + return LHS.FKind == RHS.FKind; + } + friend bool operator!=(const FunctionEffect &LHS, const FunctionEffect &RHS) { + return !(LHS == RHS); + } + friend bool operator<(const FunctionEffect &LHS, const FunctionEffect &RHS) { + return LHS.FKind < RHS.FKind; + } + friend bool operator>(const FunctionEffect &LHS, const FunctionEffect &RHS) { + return LHS.FKind > RHS.FKind; + } +}; + +/// Wrap a function effect's condition expression in another struct so +/// that FunctionProtoType's TrailingObjects can treat it separately. +struct FunctionEffectCondExpr { + const Expr *Cond = nullptr; // if null, unconditional + ---------------- Sirraide wrote:
Yeah, having to introduce helpers like these to tell apart trailing objects that would otherwise have the same type sounds reasonable. https://github.com/llvm/llvm-project/pull/84983 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits