[clang] nonblocking/nonallocating attributes: 2nd pass caller/callee analysis (PR #99656)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Sep 25 16:56:50 PDT 2024
================
@@ -0,0 +1,1572 @@
+//=== SemaFunctionEffects.cpp - Sema handling of function effects ---------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements Sema handling of function effects.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/AST/Stmt.h"
+#include "clang/AST/Type.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Sema/SemaInternal.h"
+
+#define DEBUG_TYPE "effectanalysis"
+
+using namespace clang;
+
+namespace {
+
+enum class ViolationID : uint8_t {
+ None = 0, // Sentinel for an empty Violation.
+ // These first few map to a %select{} in a diagnostic.
+ BaseDiagnosticIndex,
+ AllocatesMemory = BaseDiagnosticIndex,
+ ThrowsOrCatchesExceptions,
+ HasStaticLocalVariable,
+ AccessesThreadLocalVariable,
+ AccessesObjCMethodOrProperty,
+
+ // These only apply to callees, where the analysis stops at the Decl.
+ DeclDisallowsInference,
+
+ // These both apply to indirect calls. The difference is that sometimes
+ // we have an actual Decl (generally a variable) which is the function
+ // pointer being called, and sometimes, typically due to a cast, we only
+ // have an expression.
+ CallsDeclWithoutEffect,
+ CallsExprWithoutEffect,
+};
+
+// Information about the AST context in which a violation was found, so
+// that diagnostics can point to the correct source.
+class ViolationSite {
+public:
+ enum class Kind : uint8_t {
+ Default = 0, // Function body.
+ MemberInitializer = 1,
+ DefaultArgExpr = 2
+ };
+
+private:
+ llvm::PointerIntPair<CXXDefaultArgExpr *, 2, Kind> Impl;
+
+public:
+ ViolationSite() = default;
+
+ explicit ViolationSite(CXXDefaultArgExpr *E)
+ : Impl(E, Kind::DefaultArgExpr) {}
+
+ Kind kind() const { return static_cast<Kind>(Impl.getInt()); }
+ CXXDefaultArgExpr *defaultArgExpr() const { return Impl.getPointer(); }
+
+ void setKind(Kind K) { Impl.setPointerAndInt(nullptr, K); }
+};
+
+// Represents a violation of the rules, 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. Can be transformed into either a Diagnostic
+// (warning or a note), depending on whether the violation pertains to a
+// function failing to be verifed as holding an effect vs. a function failing to
+// be inferred as holding that effect.
+struct Violation {
+ FunctionEffect Effect;
+ FunctionEffect
+ CalleeEffectPreventingInference; // Only for certain IDs; can be None.
+ ViolationID ID = ViolationID::None;
+ ViolationSite Site;
+ SourceLocation Loc;
+ const Decl *Callee = nullptr; // Only valid for Calls*.
+
+ Violation() = default;
+
+ Violation(FunctionEffect Effect, ViolationID ID, ViolationSite VS,
+ SourceLocation Loc, const Decl *Callee = nullptr,
+ std::optional<FunctionEffect> CalleeEffect = std::nullopt)
+ : Effect(Effect), CalleeEffectPreventingInference(
+ CalleeEffect.value_or(FunctionEffect())),
+ ID(ID), Site(VS), Loc(Loc), Callee(Callee) {}
+
+ unsigned diagnosticSelectIndex() const {
+ return unsigned(ID) - unsigned(ViolationID::BaseDiagnosticIndex);
+ }
+};
+
+enum class SpecialFuncType : uint8_t { None, OperatorNew, OperatorDelete };
+enum class CallableType : uint8_t {
+ // 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->isTrivial()) {
+ // Otherwise `struct x { int a; };` would have an unverifiable default
+ // constructor.
+ return true;
+ }
+ return FD->hasBody();
+}
+
+static bool isNoexcept(const FunctionDecl *FD) {
+ const auto *FPT = FD->getType()->castAs<FunctionProtoType>();
----------------
Sirraide wrote:
(or at least some platforms—e.g. Windows, I think—unwind the stack when `longjmp()` is called; I don’t know if it allocates tho, I’m not really a backend guy)
https://github.com/llvm/llvm-project/pull/99656
More information about the cfe-commits
mailing list