PEP 670 (#2115)
This commit is contained in:
parent
a0380afe17
commit
401d207bd3
116
pep-0670.rst
116
pep-0670.rst
|
@ -15,8 +15,7 @@ Abstract
|
|||
Convert macros to static inline functions or regular functions.
|
||||
|
||||
Remove the return value of macros having a return value, whereas they
|
||||
should not, to prevent misusing the C API and to detect bugs in C
|
||||
extensions.
|
||||
should not, to detect bugs in C extensions when the C API is misused.
|
||||
|
||||
Some function arguments are still casted to ``PyObject*`` to prevent
|
||||
emitting new compiler warnings.
|
||||
|
@ -31,21 +30,22 @@ known for years, while others have been discovered recently in Python.
|
|||
Working around macro pitfalls makes the macro coder harder to read and
|
||||
to maintain.
|
||||
|
||||
Converting macros to static inline functions and regular functions has
|
||||
multiple advantages:
|
||||
Converting macros to functions has multiple advantages:
|
||||
|
||||
* By design, functions don't have macro pitfalls.
|
||||
* Arguments type and return type are well defined.
|
||||
* Debuggers and profilers can retrieve the name of inlined functions.
|
||||
* Debuggers can put breakpoints on inlined functions.
|
||||
* Variables have a well defined scope.
|
||||
* Code is usually easier to read and maintain than similar macro code.
|
||||
Functions don't need workaround for macro pitfalls:
|
||||
* Code is usually easier to read and to maintain than similar macro
|
||||
code. Functions don't need the following workarounds for macro
|
||||
pitfalls:
|
||||
|
||||
* Adding parentheses around arguments.
|
||||
* Using line continuation characters if the function is written on
|
||||
* Add parentheses around arguments.
|
||||
* Use line continuation characters if the function is written on
|
||||
multiple lines.
|
||||
* Using ``do { ... } while (0)`` to write multiple statements.
|
||||
* Add commas to execute multiple expressions.
|
||||
* Use ``do { ... } while (0)`` to write multiple statements.
|
||||
|
||||
|
||||
Macro Pitfalls
|
||||
|
@ -64,53 +64,12 @@ common macro pitfalls:
|
|||
- Newlines in arguments.
|
||||
|
||||
|
||||
Macros arguments type and return type are undefined
|
||||
---------------------------------------------------
|
||||
|
||||
Many macros cast their arguments to ``PyObject*`` each time the argument
|
||||
is used. It makes the code less readable.
|
||||
|
||||
The return type of a macro is not defined. The macro code must be read
|
||||
to guess what is the return type.
|
||||
|
||||
|
||||
Macros are hard to read
|
||||
-----------------------
|
||||
|
||||
Working around macro pitfalls requires to:
|
||||
|
||||
* Add parentheses around arguments
|
||||
* Add ``do { ... } while (0)`` if there are multiple statements.
|
||||
* Add commas to execute multiple expressions.
|
||||
|
||||
All these workarounds make the macro code harder to read and to
|
||||
maintain.
|
||||
|
||||
Use macros in macros
|
||||
--------------------
|
||||
|
||||
Writing a macro using ``#ifdef`` or using other macros can require
|
||||
working around preprocessor limitations which imply writing code harder
|
||||
to read.
|
||||
|
||||
Macro having a return value whereas it should not
|
||||
-------------------------------------------------
|
||||
|
||||
If a macro is implemented as an expression, it has a return value. In
|
||||
some cases, the macro must not have a return value and can be misued in
|
||||
third party C extensions: see `bpo-30459
|
||||
<https://bugs.python.org/issue30459>`_.
|
||||
|
||||
It is not easy to notice such issue while writing or reviewing a macro
|
||||
code.
|
||||
|
||||
|
||||
Performance and inlining
|
||||
========================
|
||||
|
||||
Static inline functions is a feature added to C99. In 2021, C compilers
|
||||
can inline them and have efficient heuristics to decide if a function
|
||||
should be inlined or not.
|
||||
Static inline functions is a feature added to the C99 standard. In 2021,
|
||||
C compilers can inline them and have efficient heuristics to decide if a
|
||||
function should be inlined or not.
|
||||
|
||||
When a C compiler decides to not inline, there is likely a good reason.
|
||||
For example, inlining would reuse a register which require to
|
||||
|
@ -216,32 +175,48 @@ used outside Python.
|
|||
Cast to PyObject*
|
||||
-----------------
|
||||
|
||||
To prevent emitting new compiler warnings, a macro is used to cast some
|
||||
function arguments to ``PyObject*``, so the converted functions still
|
||||
accept pointers to other structures which inherit from ``PyObject`` (ex:
|
||||
``PyTupleObject``).
|
||||
When a macro is converted to a function and the macro casts its
|
||||
arguments to ``PyObject*``, the new function comes with a new macro
|
||||
which cast arguments to ``PyObject*`` to prevent emitting new compiler
|
||||
warnings. So the converted functions still accept pointers to structures
|
||||
inheriting from ``PyObject`` (ex: ``PyTupleObject``).
|
||||
|
||||
For example, the ``Py_TYPE(obj)`` macro casts its ``obj`` argument to
|
||||
``PyObject*``.
|
||||
``PyObject*``::
|
||||
|
||||
Later, the cast can be removed on a case by case basic, but it is out of
|
||||
#define _PyObject_CAST_CONST(op) ((const PyObject*)(op))
|
||||
|
||||
static inline PyTypeObject* _Py_TYPE(const PyObject *ob) {
|
||||
return ob->ob_type;
|
||||
}
|
||||
#define Py_TYPE(ob) _Py_TYPE(_PyObject_CAST_CONST(ob))
|
||||
|
||||
The undocumented private ``_Py_TYPE()`` function must not be called
|
||||
directly. Only the documented public ``Py_TYPE()`` macro must be used.
|
||||
|
||||
Later, the cast can be removed on a case by case basis, but it is out of
|
||||
this PEP scope.
|
||||
|
||||
Remove the return value
|
||||
-----------------------
|
||||
|
||||
Macros having a return value, whereas they should not, are converted to
|
||||
static inline functions or regular functions using the ``void`` return
|
||||
type (no return value) to prevent misusing the C API and to detect bugs
|
||||
in C extensions.
|
||||
When a macro is implemented as an expression, it has an implicit return
|
||||
value. In some cases, the macro must not have a return value and can be
|
||||
misused in third party C extensions. See `bpo-30459
|
||||
<https://bugs.python.org/issue30459>`_ for the example of
|
||||
``PyList_SET_ITEM()`` and ``PyCell_SET()`` macros. It is not easy to
|
||||
notice this issue while reviewing a macro code.
|
||||
|
||||
These macros are converted to functions using the ``void`` return type
|
||||
to remove their return value. Removing the return value detects bugs in
|
||||
C extensions when the C API is misused.
|
||||
|
||||
|
||||
Backwards Compatibility
|
||||
=======================
|
||||
|
||||
Converting macros having a return value, whereas they should not, to
|
||||
functions using the ``void`` return type is an incompatible change made
|
||||
on purpose: see the `Remove the return value`_ section.
|
||||
Removing the return value of macros is an incompatible change made on
|
||||
purpose: see the `Remove the return value`_ section.
|
||||
|
||||
|
||||
Rejected Ideas
|
||||
|
@ -250,9 +225,10 @@ Rejected Ideas
|
|||
Keep macros, but fix some macro issues
|
||||
--------------------------------------
|
||||
|
||||
The `Macro having a return value whereas it should not`_ issue can be
|
||||
fixed by casting the macro result to ``void``. For example, the
|
||||
``PyList_SET_ITEM()`` macro was already fixed like that.
|
||||
Converting macros to functions is not needed to `remove the return
|
||||
value`_: casting a macro return value to ``void`` also fix the issue.
|
||||
For example, the ``PyList_SET_ITEM()`` macro was already fixed like
|
||||
that.
|
||||
|
||||
Macros are always "inlined" with any C compiler.
|
||||
|
||||
|
@ -262,7 +238,7 @@ the macro.
|
|||
People using macros should be considered "consenting adults". People who
|
||||
feel unsafe with macros should simply not use them.
|
||||
|
||||
Example of macros hard to read
|
||||
Example of hard to read macros
|
||||
==============================
|
||||
|
||||
_Py_NewReference()
|
||||
|
|
Loading…
Reference in New Issue