[clang] Add clang/docs/FunctionEffectAnalysis.rst. (PR #109855)

via cfe-commits cfe-commits at lists.llvm.org
Thu Sep 26 05:09:38 PDT 2024


================
@@ -0,0 +1,503 @@
+========================
+Function Effect Analysis
+========================
+
+Introduction
+============
+
+Clang Function Effect Analysis is a C++ language extension which can warn about "unsafe"
+constructs. The feature is currently tailored for the Performance Constraint attributes,
+``nonblocking`` and ``nonallocating``; functions with these attributes are verified as not
+containing any language constructs or calls to other functions which violate the constraint.
+(See :doc:`AttributeReference`.)
+
+
+The ``nonblocking`` and ``nonallocating`` attributes
+====================================================
+
+Attribute syntax
+----------------
+
+The ``nonblocking`` and ``nonallocating`` attributes apply to function types, allowing them to be
+attached to functions, blocks, function pointers, lambdas, and member functions.
+
+.. code-block:: c++
+
+  // Functions
+  void nonblockingFunction() [[clang::nonblocking]];
+  void nonallocatingFunction() [[clang::nonallocating]];
+
+  // Function pointers
+  void (*nonblockingFunctionPtr)() [[clang::nonblocking]];
+
+  // Typedefs, type aliases.
+  typedef void (*NBFunctionPtrTypedef)() [[clang::nonblocking]];
+  using NBFunctionPtrTypeAlias_gnu = __attribute__((nonblocking)) void (*)();
+  using NBFunctionPtrTypeAlias_std = void (*)() [[clang::nonblocking]];
+
+  // C++ methods
+  struct Struct {
+    void NBMethod() [[clang::nonblocking]];
+  };
+
+  // C++ lambdas
+  auto nbLambda = []() [[clang::nonblocking]] {};
+
+  // Blocks
+  void (^nbBlock)() = ^() [[clang::nonblocking]] {};
+
+The attribute applies only to the function itself. In particular, it does not apply to any nested
+functions or declarations, such as blocks, lambdas, and local classes.
+
+This document uses the C++/C23 syntax ``[[clang::nonblocking]]``, since it parallels the placement 
+of the ``noexcept`` specifier, and the attributes have other similarities to ``noexcept``. The GNU
+``__attribute__((nonblocking))`` syntax is also supported. Note that it requires a different 
+placement on a C++ type alias.
+
+Like ``noexcept``, ``nonblocking`` and ``nonallocating`` have an optional argument, a compile-time
+constant boolean expression. By default, the argument is true, so ``[[clang::nonblocking(true)]]``
+is equivalent to ``[[clang::nonblocking]]``, and declares the function type as never locking.
+
+
+Attribute semantics
+-------------------
+
+Together with ``noexcept``, the ``nonallocating`` and ``nonblocking`` attributes define an ordered
+series of performance constraints. From weakest to strongest:
+
+- ``noexcept`` (as per the C++ standard): The function type will never throw an exception.
+- ``nonallocating``: The function type will never allocate memory on the heap, and never throw an
+  exception.
+- ``nonblocking``: The function type will never block on a lock, never allocate memory on the heap,
+  and never throw an exception.
+
+``nonblocking`` includes the ``nonallocating`` guarantee. 
+
+``nonblocking`` and ``nonallocating`` include the ``noexcept`` guarantee, but the presence of either
+attribute does not implicitly specify ``noexcept``. (It would be inappropriate for a Clang 
+attribute, ignored by non-Clang compilers, to imply a standard language feature.)
+
+``nonblocking(true)`` and ``nonallocating(true)`` apply to function *types*, and by extension, to
+function-like declarations. When applied to a declaration with a body, the compiler verifies the
+function, as described in the section "Analysis and warnings", below. Functions without an explicit
+performance constraint are not verified.
+
+``nonblocking(false)`` and ``nonallocating(false)`` are synonyms for the attributes ``blocking`` and
+``allocating``. They can be used on a function-like declaration to explicitly disable any potential
+inference of ``nonblocking`` or ``nonallocating`` during verification. (Inference is described later
+in this document). ``nonblocking(false)`` and ``nonallocating(false)`` are legal, but superfluous 
+when applied to a function *type*. ``float (int) [[nonblocking(false)]]`` and ``float (int)`` are
+identical types.
+
+For all functions with no explicit performance constraint, the worst is assumed, that the function
+allocates memory and potentially blocks, unless it can be inferred otherwise, as described in the
+discussion of verification.
+
+The following list describes the meanings of all permutations of the two attributes and arguments:
+
+- ``nonblocking(true)`` + ``nonallocating(true)``: valid; ``nonallocating(true)`` is superfluous but
+  does not contradict the guarantee.
+- ``nonblocking(true)`` + ``nonallocating(false)``: error, contradictory.
+- ``nonblocking(false)`` + ``nonallocating(true)``: valid; the function does not allocate memory,
+  but may lock for other reasons.
+- ``nonblocking(false)`` + ``nonallocating(false)``: valid.
+
+Type conversions
+----------------
+
+A performance constraint can be removed or weakened via an implicit conversion. An attempt to add
+or strengthen a performance constraint is unsafe and results in a warning.
+
+.. code-block:: c++
+
+  void unannotated();
+  void nonblocking() [[clang::nonblocking]];
+  void nonallocating() [[clang::nonallocating]];
+
+  void example()
+  {
+    // It's fine to remove a performance constraint.
+    void (*fp_plain)();
+    fp_plain = unannotated;
+    fp_plain = nonblocking;
+    fp_plain = nonallocating;
+
+    // Adding/spoofing nonblocking is unsafe.
+    void (*fp_nonblocking)() [[clang::nonblocking]];
+    fp_nonblocking = nullptr;
+    fp_nonblocking = nonblocking;
+    fp_nonblocking = unannotated;
+    // ^ warning: attribute 'nonblocking' should not be added via type conversion
+    fp_nonblocking = nonallocating;
+    // ^ warning: attribute 'nonblocking' should not be added via type conversion
+
+    // Adding/spoofing nonallocating is unsafe.
+    void (*fp_nonallocating)() [[clang::nonallocating]];
+    fp_nonallocating = nullptr;
+    fp_nonallocating = nonallocating;
+    fp_nonallocating = nonblocking; // no warning because nonblocking includes nonallocating 
+    fp_nonallocating = unannotated;
+    // ^ warning: attribute 'nonallocating' should not be added via type conversion
+  }
+
+Virtual methods
+---------------
+
+In C++, when a base class's virtual method has a performance constraint, overriding methods in
+subclasses inherit the attribute.
----------------
Sirraide wrote:

```suggestion
subclasses inherit the constraint.
```
‘inherit the attribute’ is technically not wrong, but the point here is that the constraint is what’s inherited (via inheriting the attribute).

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


More information about the cfe-commits mailing list