Skip to content

Commit e7ad0db

Browse files
dougsonosSirraide
andauthored
Apply suggestions from code review
Co-authored-by: Sirraide <[email protected]>
1 parent 2c3e35e commit e7ad0db

File tree

1 file changed

+26
-27
lines changed

1 file changed

+26
-27
lines changed

clang/docs/FunctionEffectAnalysis.rst

Lines changed: 26 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ Introduction
1111
============
1212

1313
Clang Function Effect Analysis is a language extension which can warn about "unsafe"
14-
constructs. The feature is currently tailored for the Performance Constraint attributes,
14+
constructs. The feature is currently tailored for the Performance Constraint attributes
1515
``nonblocking`` and ``nonallocating``; functions with these attributes are verified as not
1616
containing any language constructs or calls to other functions which violate the constraint.
1717
(See :doc:`AttributeReference`.)
@@ -61,7 +61,7 @@ placement on a C++ type alias.
6161

6262
Like ``noexcept``, ``nonblocking`` and ``nonallocating`` have an optional argument, a compile-time
6363
constant boolean expression. By default, the argument is ``true``, so ``[[clang::nonblocking]]``
64-
is equivalent to ``[[clang::nonblocking(true)]]``, and declares the function type as never locking.
64+
is equivalent to ``[[clang::nonblocking(true)]]``, and declares the function type as never blocking.
6565

6666

6767
Attribute semantics
@@ -71,34 +71,32 @@ Together with ``noexcept``, the ``nonallocating`` and ``nonblocking`` attributes
7171
series of performance constraints. From weakest to strongest:
7272

7373
- ``noexcept`` (as per the C++ standard): The function type will never throw an exception.
74-
- ``nonallocating``: The function type will never allocate memory on the heap, and never throw an
74+
- ``nonallocating``: The function type will never allocate memory on the heap or throw an
7575
exception.
76-
- ``nonblocking``: The function type will never block on a lock, never allocate memory on the heap,
77-
and never throw an exception.
76+
- ``nonblocking``: The function type will never block on a lock, allocate memory on the heap,
77+
or throw an exception.
7878

7979
``nonblocking`` includes the ``nonallocating`` guarantee.
8080

8181
While ``nonblocking`` and ``nonallocating`` are conceptually a superset of ``noexcept``, neither
8282
attribute implicitly specifies ``noexcept``. Further, ``noexcept`` has a specified runtime behavior of
8383
aborting if an exception is thrown, while the ``nonallocating`` and ``nonblocking`` attributes are
84-
purely for compile-time analysis and have no potential runtime behavior. Nonetheless, Clang emits a
84+
mainly for compile-time analysis and have no runtime behavior, except in code built
85+
with Clang's :doc:`RealtimeSanitizer`. Nonetheless, Clang emits a
8586
warning if, in C++, a function is declared ``nonblocking`` or ``nonallocating`` without
8687
``noexcept``. This diagnostic is controlled by ``-Wperf-constraint-implies-noexcept``.
8788

88-
Also, the ``nonblocking`` and ``blocking`` attributes do have special runtime behavior in code built
89-
with Clang's :doc:`RealtimeSanitizer`.
90-
9189
``nonblocking(true)`` and ``nonallocating(true)`` apply to function *types*, and by extension, to
9290
function-like declarations. When applied to a declaration with a body, the compiler verifies the
93-
function, as described in the section "Analysis and warnings", below. Functions without an explicit
94-
performance constraint are not verified.
91+
function, as described in the section "Analysis and warnings", below.
9592

9693
``blocking`` and ``allocating`` are synonyms for ``nonblocking(false)`` and
9794
``nonallocating(false)``, respectively. They can be used on a function-like declaration to
9895
explicitly disable any potential inference of ``nonblocking`` or ``nonallocating`` during
9996
verification. (Inference is described later in this document). ``nonblocking(false)`` and
100-
``nonallocating(false)`` are legal, but superfluous when applied to a function *type*.
101-
``float (int) [[nonblocking(false)]]`` and ``float (int)`` are identical types.
97+
``nonallocating(false)`` are legal, but superfluous when applied to a function *type*
98+
that is not part of a declarator: ``float (int) [[nonblocking(false)]]`` and
99+
``float (int)`` are identical types.
102100

103101
For functions with no explicit performance constraint, the worst is assumed: the function
104102
allocates memory and potentially blocks, unless it can be inferred otherwise. This is detailed in the
@@ -125,7 +123,8 @@ Type conversions
125123
----------------
126124

127125
A performance constraint can be removed or weakened via an implicit conversion. An attempt to add
128-
or strengthen a performance constraint is unsafe and results in a warning.
126+
or strengthen a performance constraint is unsafe and results in a warning. The rules for this
127+
are comparable to that for ``noexcept`` in C++17 and later.
129128

130129
.. code-block:: c++
131130

@@ -162,7 +161,7 @@ or strengthen a performance constraint is unsafe and results in a warning.
162161
Virtual methods
163162
---------------
164163

165-
In C++, when a base class's virtual method has a performance constraint, overriding methods in
164+
In C++, when a virtual method has a performance constraint, overriding methods in
166165
subclasses inherit the constraint.
167166

168167
.. code-block:: c++
@@ -195,19 +194,19 @@ First, consider that ``noexcept`` is integral to a function's type:
195194
// error: exception specification in declaration does not match previous
196195
// declaration
197196

198-
Unlike ``noexcept``, a redeclaration of `f2` with an added or stronger performance constraint is
199-
legal, and propagates the attribute to the previous declaration:
197+
Unlike ``noexcept``, a redeclaration of ``f2`` with an added or stronger performance constraint is
198+
legal and propagates the attribute to the previous declaration:
200199

201200
.. code-block:: c++
202201

203202
int f2();
204203
int f2() [[clang::nonblocking]]; // redeclaration with stronger constraint is OK.
205204

206-
This greatly eases adoption, by making it possible to annotate functions in external libraries
205+
This greatly eases adoption by making it possible to annotate functions in external libraries
207206
without modifying library headers.
208207

209-
A redeclaration with a removed or weaker performance constraint produces a warning, in order to
210-
parallel the behavior of ``noexcept``:
208+
A redeclaration with a removed or weaker performance constraint produces a warning, paralleling
209+
the behavior of ``noexcept``:
211210

212211
.. code-block:: c++
213212

@@ -275,7 +274,7 @@ following rules. Such functions:
275274
a. The callee is also explicitly declared with the same ``nonblocking`` or ``nonallocating``
276275
attribute (or stronger).
277276
b. The callee is defined in the same translation unit as the caller, does not have the ``false``
278-
form of the required attribute, and can be verified to be have the same attribute or stronger,
277+
form of the required attribute, and can be verified to have the same attribute or stronger,
279278
according to these same rules.
280279
c. The callee is a built-in function that is known not to block or allocate.
281280
d. The callee is declared ``noreturn`` and, if compiling C++, the callee is also declared
@@ -324,7 +323,7 @@ Inferring ``nonblocking`` or ``nonallocating``
324323
----------------------------------------------
325324

326325
In the absence of a ``nonblocking`` or ``nonallocating`` attribute (whether ``true`` or ``false``),
327-
a function, when found to be called from a performance-constrained function, can be analyzed to
326+
a function that is called from a performance-constrained function may be analyzed to
328327
infer whether it has a desired attribute. This analysis happens when the function is not a virtual
329328
method, and it has a visible definition within the current translation unit (i.e. its body can be
330329
traversed).
@@ -389,8 +388,8 @@ A construct like this can be used to exempt code from the checks described here:
389388
Disabling the diagnostic allows for:
390389

391390
- constructs which do block, but which in practice are used in ways to avoid unbounded blocking,
392-
e.g. a thread pool with semaphores to coordinate multiple realtime threads.
393-
- using libraries which are safe but not yet annotated.
391+
e.g. a thread pool with semaphores to coordinate multiple realtime threads;
392+
- using libraries which are safe but not yet annotated;
394393
- incremental adoption in a large codebase.
395394

396395
Adoption
@@ -420,7 +419,7 @@ which throw exceptions include:
420419
-----------------------------
421420

422421
``std::function<R(Args...)>`` is generally incompatible with ``nonblocking`` and ``nonallocating``
423-
code, because an implementation typically allocates heap memory in the constructor.
422+
code, because a typical implementation may allocate heap memory in the constructor.
424423

425424
Alternatives:
426425

@@ -537,8 +536,8 @@ At least for an operating system's C functions, it is possible to define an over
537536
redeclares safe common functions (e.g. ``pthread_self()``) with the addition of ``nonblocking``.
538537
This may help in adopting the feature incrementally.
539538

540-
It also helps that for many of the functions in the standard C libraries (notably ``<math.h>``),
541-
Clang generates calls to built-in functions, which the diagnosis understands to be safe.
539+
It also helps that many of the functions in the standard C libraries (notably ``<math.h>``)
540+
are treated as built-in functions by Clang, which the diagnosis understands to be safe.
542541

543542
Much of the C++ standard library consists of inline templated functions which work well with
544543
inference. A small number of primitives may need explicit ``nonblocking/nonallocating`` attributes.

0 commit comments

Comments
 (0)