[clang] nolock/noalloc attributes (PR #84983)

via cfe-commits cfe-commits at lists.llvm.org
Tue Mar 12 16:22:57 PDT 2024


================
@@ -2380,6 +2382,1239 @@ class UnsafeBufferUsageReporter : public UnsafeBufferUsageHandler {
 };
 } // namespace
 
+// =============================================================================
+
+// Temporary debugging option
+#define FX_ANALYZER_VERIFY_DECL_LIST 1
+
+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
+  DeclWithoutConstraintOrInference,
+
+  CallsUnsafeDecl,
+  CallsDisallowedExpr,
+};
+
+struct Diagnostic {
+  const FunctionEffect *Effect = nullptr;
+  const Decl *Callee = nullptr; // only valid for Calls*
+  SourceLocation Loc;
+  DiagnosticID ID = DiagnosticID::None;
+
+  Diagnostic() = default;
+
+  Diagnostic(const FunctionEffect *Effect, DiagnosticID ID, SourceLocation Loc,
+             const Decl *Callee = nullptr)
+      : Effect(Effect), Callee(Callee), Loc(Loc), ID(ID) {}
+};
+
+enum class SpecialFuncType : uint8_t { None, OperatorNew, OperatorDelete };
+enum class CallType {
+  Unknown,
+  Function,
+  Virtual,
+  Block
+  // unknown: probably function pointer
+};
+
+// Return whether the function 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;
+}
+
+// Transitory, more extended information about a callable, which can be a
+// function, block, function pointer...
+struct CallableInfo {
+  const Decl *CDecl;
+  mutable std::optional<std::string>
+      MaybeName; // mutable because built on demand in const method
+  SpecialFuncType FuncType = SpecialFuncType::None;
+  FunctionEffectSet Effects;
+  CallType CType = CallType::Unknown;
+
+  CallableInfo(const Decl &CD, SpecialFuncType FT = SpecialFuncType::None)
+      : CDecl(&CD), FuncType(FT) {
+    // llvm::errs() << "CallableInfo " << name() << "\n";
+
+    if (auto *FD = dyn_cast<FunctionDecl>(CDecl)) {
+      assert(FD->getCanonicalDecl() == FD);
+      // Use the function's definition, if any.
+      if (auto *Def = FD->getDefinition()) {
+        CDecl = FD = Def;
+      }
+      CType = CallType::Function;
+      if (auto *Method = dyn_cast<CXXMethodDecl>(FD)) {
+        if (Method->isVirtual()) {
+          CType = CallType::Virtual;
+        }
+      }
+      Effects = FD->getFunctionEffects();
+    } else if (auto *BD = dyn_cast<BlockDecl>(CDecl)) {
+      CType = CallType::Block;
+      Effects = BD->getFunctionEffects();
+    } else if (auto *VD = dyn_cast<ValueDecl>(CDecl)) {
+      // ValueDecl is function, enum, or variable, so just look at the type.
+      Effects = FunctionEffectSet::get(*VD->getType());
+    }
+  }
+
+  bool isDirectCall() const {
+    return CType == CallType::Function || CType == CallType::Block;
+  }
+
+  bool isVerifiable() const {
+    switch (CType) {
+    case CallType::Unknown:
+    case CallType::Virtual:
+      break;
+    case CallType::Block:
+      return true;
+    case CallType::Function:
+      return functionIsVerifiable(dyn_cast<FunctionDecl>(CDecl));
+    }
+    return false;
+  }
+
+  /// Generate a name for logging and diagnostics.
+  std::string name(Sema &Sem) const {
+    if (!MaybeName) {
+      std::string Name;
+      llvm::raw_string_ostream OS(Name);
+
+      if (auto *FD = dyn_cast<FunctionDecl>(CDecl)) {
+        FD->getNameForDiagnostic(OS, Sem.getPrintingPolicy(),
+                                 /*Qualified=*/true);
+      } else if (auto *BD = dyn_cast<BlockDecl>(CDecl)) {
+        OS << "(block " << BD->getBlockManglingNumber() << ")";
+      } else if (auto *VD = dyn_cast<NamedDecl>(CDecl)) {
+        VD->printQualifiedName(OS);
+      }
+      MaybeName = Name;
+    }
+    return *MaybeName;
+  }
+};
+
+// ----------
+// Map effects to single diagnostics.
+class EffectToDiagnosticMap {
+  // Since we currently only have a tiny number of effects (typically no more
+  // than 1), use a sorted SmallVector.
----------------
Sirraide wrote:

This is minor, but maybe `SmallVector<Element, 1>` might make sense if it’s usually really no more than 1.

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


More information about the cfe-commits mailing list