summaryrefslogtreecommitdiffstats
path: root/Include
diff options
context:
space:
mode:
authorVictor Stinner <vstinner@python.org>2022-11-28 15:40:08 (GMT)
committerGitHub <noreply@github.com>2022-11-28 15:40:08 (GMT)
commit02f72b8b938e301bbaaf0142547014e074bd564c (patch)
tree1ffd7f82d70652c6f480a67fe70aa8ae248fae18 /Include
parent53eef27133c1da395b3b4d7ce0ab1d5b743ffb41 (diff)
downloadcpython-02f72b8b938e301bbaaf0142547014e074bd564c.zip
cpython-02f72b8b938e301bbaaf0142547014e074bd564c.tar.gz
cpython-02f72b8b938e301bbaaf0142547014e074bd564c.tar.bz2
gh-89653: PEP 670: Convert macros to functions (#99843)
Convert macros to static inline functions to avoid macro pitfalls, like duplication of side effects: * DK_ENTRIES() * DK_UNICODE_ENTRIES() * PyCode_GetNumFree() * PyFloat_AS_DOUBLE() * PyInstanceMethod_GET_FUNCTION() * PyMemoryView_GET_BASE() * PyMemoryView_GET_BUFFER() * PyMethod_GET_FUNCTION() * PyMethod_GET_SELF() * PySet_GET_SIZE() * _PyHeapType_GET_MEMBERS() Changes: * PyCode_GetNumFree() casts PyCode_GetNumFree.co_nfreevars from int to Py_ssize_t to be future proof, and because Py_ssize_t is commonly used in the C API. * PyCode_GetNumFree() doesn't cast its argument: the replaced macro already required the exact type PyCodeObject*. * Add assertions in some functions using "CAST" macros to check the arguments type when Python is built with assertions (debug build). * Remove an outdated comment in unicodeobject.h.
Diffstat (limited to 'Include')
-rw-r--r--Include/cpython/classobject.h34
-rw-r--r--Include/cpython/code.h7
-rw-r--r--Include/cpython/floatobject.h10
-rw-r--r--Include/cpython/memoryobject.h13
-rw-r--r--Include/cpython/setobject.h9
-rw-r--r--Include/cpython/unicodeobject.h2
-rw-r--r--Include/internal/pycore_dict.h21
-rw-r--r--Include/internal/pycore_object.h5
8 files changed, 74 insertions, 27 deletions
diff --git a/Include/cpython/classobject.h b/Include/cpython/classobject.h
index 0510419..d7c9ddd 100644
--- a/Include/cpython/classobject.h
+++ b/Include/cpython/classobject.h
@@ -26,12 +26,20 @@ PyAPI_FUNC(PyObject *) PyMethod_New(PyObject *, PyObject *);
PyAPI_FUNC(PyObject *) PyMethod_Function(PyObject *);
PyAPI_FUNC(PyObject *) PyMethod_Self(PyObject *);
-/* Macros for direct access to these values. Type checks are *not*
- done, so use with care. */
-#define PyMethod_GET_FUNCTION(meth) \
- (((PyMethodObject *)(meth)) -> im_func)
-#define PyMethod_GET_SELF(meth) \
- (((PyMethodObject *)(meth)) -> im_self)
+#define _PyMethod_CAST(meth) \
+ (assert(PyMethod_Check(meth)), _Py_CAST(PyMethodObject*, meth))
+
+/* Static inline functions for direct access to these values.
+ Type checks are *not* done, so use with care. */
+static inline PyObject* PyMethod_GET_FUNCTION(PyObject *meth) {
+ return _PyMethod_CAST(meth)->im_func;
+}
+#define PyMethod_GET_FUNCTION(meth) PyMethod_GET_FUNCTION(_PyObject_CAST(meth))
+
+static inline PyObject* PyMethod_GET_SELF(PyObject *meth) {
+ return _PyMethod_CAST(meth)->im_self;
+}
+#define PyMethod_GET_SELF(meth) PyMethod_GET_SELF(_PyObject_CAST(meth))
typedef struct {
PyObject_HEAD
@@ -45,10 +53,16 @@ PyAPI_DATA(PyTypeObject) PyInstanceMethod_Type;
PyAPI_FUNC(PyObject *) PyInstanceMethod_New(PyObject *);
PyAPI_FUNC(PyObject *) PyInstanceMethod_Function(PyObject *);
-/* Macros for direct access to these values. Type checks are *not*
- done, so use with care. */
-#define PyInstanceMethod_GET_FUNCTION(meth) \
- (((PyInstanceMethodObject *)(meth)) -> func)
+#define _PyInstanceMethod_CAST(meth) \
+ (assert(PyInstanceMethod_Check(meth)), \
+ _Py_CAST(PyInstanceMethodObject*, meth))
+
+/* Static inline function for direct access to these values.
+ Type checks are *not* done, so use with care. */
+static inline PyObject* PyInstanceMethod_GET_FUNCTION(PyObject *meth) {
+ return _PyInstanceMethod_CAST(meth)->func;
+}
+#define PyInstanceMethod_GET_FUNCTION(meth) PyInstanceMethod_GET_FUNCTION(_PyObject_CAST(meth))
#ifdef __cplusplus
}
diff --git a/Include/cpython/code.h b/Include/cpython/code.h
index ebac0b1..15b464f 100644
--- a/Include/cpython/code.h
+++ b/Include/cpython/code.h
@@ -147,7 +147,12 @@ struct PyCodeObject _PyCode_DEF(1);
PyAPI_DATA(PyTypeObject) PyCode_Type;
#define PyCode_Check(op) Py_IS_TYPE((op), &PyCode_Type)
-#define PyCode_GetNumFree(op) ((op)->co_nfreevars)
+
+static inline Py_ssize_t PyCode_GetNumFree(PyCodeObject *op) {
+ assert(PyCode_Check(op));
+ return op->co_nfreevars;
+}
+
#define _PyCode_CODE(CO) ((_Py_CODEUNIT *)(CO)->co_code_adaptive)
#define _PyCode_NBYTES(CO) (Py_SIZE(CO) * (Py_ssize_t)sizeof(_Py_CODEUNIT))
diff --git a/Include/cpython/floatobject.h b/Include/cpython/floatobject.h
index 7795d9f..1270930 100644
--- a/Include/cpython/floatobject.h
+++ b/Include/cpython/floatobject.h
@@ -7,9 +7,15 @@ typedef struct {
double ob_fval;
} PyFloatObject;
-// Macro version of PyFloat_AsDouble() trading safety for speed.
+#define _PyFloat_CAST(op) \
+ (assert(PyFloat_Check(op)), _Py_CAST(PyFloatObject*, op))
+
+// Static inline version of PyFloat_AsDouble() trading safety for speed.
// It doesn't check if op is a double object.
-#define PyFloat_AS_DOUBLE(op) (((PyFloatObject *)(op))->ob_fval)
+static inline double PyFloat_AS_DOUBLE(PyObject *op) {
+ return _PyFloat_CAST(op)->ob_fval;
+}
+#define PyFloat_AS_DOUBLE(op) PyFloat_AS_DOUBLE(_PyObject_CAST(op))
PyAPI_FUNC(int) PyFloat_Pack2(double x, char *p, int le);
diff --git a/Include/cpython/memoryobject.h b/Include/cpython/memoryobject.h
index e2a1e16..deab3cc 100644
--- a/Include/cpython/memoryobject.h
+++ b/Include/cpython/memoryobject.h
@@ -36,7 +36,16 @@ typedef struct {
Py_ssize_t ob_array[1]; /* shape, strides, suboffsets */
} PyMemoryViewObject;
+#define _PyMemoryView_CAST(op) _Py_CAST(PyMemoryViewObject*, op)
+
/* Get a pointer to the memoryview's private copy of the exporter's buffer. */
-#define PyMemoryView_GET_BUFFER(op) (&((PyMemoryViewObject *)(op))->view)
+static inline Py_buffer* PyMemoryView_GET_BUFFER(PyObject *op) {
+ return (&_PyMemoryView_CAST(op)->view);
+}
+#define PyMemoryView_GET_BUFFER(op) PyMemoryView_GET_BUFFER(_PyObject_CAST(op))
+
/* Get a pointer to the exporting object (this may be NULL!). */
-#define PyMemoryView_GET_BASE(op) (((PyMemoryViewObject *)(op))->view.obj)
+static inline PyObject* PyMemoryView_GET_BASE(PyObject *op) {
+ return _PyMemoryView_CAST(op)->view.obj;
+}
+#define PyMemoryView_GET_BASE(op) PyMemoryView_GET_BASE(_PyObject_CAST(op))
diff --git a/Include/cpython/setobject.h b/Include/cpython/setobject.h
index b4443a6..20fd63e 100644
--- a/Include/cpython/setobject.h
+++ b/Include/cpython/setobject.h
@@ -58,8 +58,13 @@ typedef struct {
PyObject *weakreflist; /* List of weak references */
} PySetObject;
-#define PySet_GET_SIZE(so) \
- (assert(PyAnySet_Check(so)), (((PySetObject *)(so))->used))
+#define _PySet_CAST(so) \
+ (assert(PyAnySet_Check(so)), _Py_CAST(PySetObject*, so))
+
+static inline Py_ssize_t PySet_GET_SIZE(PyObject *so) {
+ return _PySet_CAST(so)->used;
+}
+#define PySet_GET_SIZE(so) PySet_GET_SIZE(_PyObject_CAST(so))
PyAPI_DATA(PyObject *) _PySet_Dummy;
diff --git a/Include/cpython/unicodeobject.h b/Include/cpython/unicodeobject.h
index 86eeab6..a75336f 100644
--- a/Include/cpython/unicodeobject.h
+++ b/Include/cpython/unicodeobject.h
@@ -231,8 +231,6 @@ enum PyUnicode_Kind {
// new compiler warnings on "kind < PyUnicode_KIND(str)" (compare signed and
// unsigned numbers) where kind type is an int or on
// "unsigned int kind = PyUnicode_KIND(str)" (cast signed to unsigned).
-// Only declare the function as static inline function in the limited C API
-// version 3.12 which is stricter.
#define PyUnicode_KIND(op) (_PyASCIIObject_CAST(op)->state.kind)
/* Return a void pointer to the raw unicode buffer. */
diff --git a/Include/internal/pycore_dict.h b/Include/internal/pycore_dict.h
index 25bd3bf..04b7084 100644
--- a/Include/internal/pycore_dict.h
+++ b/Include/internal/pycore_dict.h
@@ -128,12 +128,21 @@ struct _dictvalues {
#else
#define DK_SIZE(dk) (1<<DK_LOG_SIZE(dk))
#endif
-#define DK_ENTRIES(dk) \
- (assert((dk)->dk_kind == DICT_KEYS_GENERAL), \
- (PyDictKeyEntry*)(&((int8_t*)((dk)->dk_indices))[(size_t)1 << (dk)->dk_log2_index_bytes]))
-#define DK_UNICODE_ENTRIES(dk) \
- (assert((dk)->dk_kind != DICT_KEYS_GENERAL), \
- (PyDictUnicodeEntry*)(&((int8_t*)((dk)->dk_indices))[(size_t)1 << (dk)->dk_log2_index_bytes]))
+
+static inline void* _DK_ENTRIES(PyDictKeysObject *dk) {
+ int8_t *indices = (int8_t*)(dk->dk_indices);
+ size_t index = (size_t)1 << dk->dk_log2_index_bytes;
+ return (&indices[index]);
+}
+static inline PyDictKeyEntry* DK_ENTRIES(PyDictKeysObject *dk) {
+ assert(dk->dk_kind == DICT_KEYS_GENERAL);
+ return (PyDictKeyEntry*)_DK_ENTRIES(dk);
+}
+static inline PyDictUnicodeEntry* DK_UNICODE_ENTRIES(PyDictKeysObject *dk) {
+ assert(dk->dk_kind != DICT_KEYS_GENERAL);
+ return (PyDictUnicodeEntry*)_DK_ENTRIES(dk);
+}
+
#define DK_IS_UNICODE(dk) ((dk)->dk_kind != DICT_KEYS_GENERAL)
#define DICT_VERSION_INCREMENT (1 << DICT_MAX_WATCHERS)
diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h
index 8b78f79..33c8c0b 100644
--- a/Include/internal/pycore_object.h
+++ b/Include/internal/pycore_object.h
@@ -355,8 +355,9 @@ extern int _PyType_HasSubclasses(PyTypeObject *);
extern PyObject* _PyType_GetSubclasses(PyTypeObject *);
// Access macro to the members which are floating "behind" the object
-#define _PyHeapType_GET_MEMBERS(etype) \
- ((PyMemberDef *)(((char *)(etype)) + Py_TYPE(etype)->tp_basicsize))
+static inline PyMemberDef* _PyHeapType_GET_MEMBERS(PyHeapTypeObject *etype) {
+ return (PyMemberDef*)((char*)etype + Py_TYPE(etype)->tp_basicsize);
+}
PyAPI_FUNC(PyObject *) _PyObject_LookupSpecial(PyObject *, PyObject *);