PyObject* kw);
#define _PyCFunction_TrampolineCall(meth, self, args) \
- _PyEM_TrampolineCall( \
- (*(PyCFunctionWithKeywords)(void(*)(void))(meth)), (self), (args), NULL)
+ _PyEM_TrampolineCall(*_PyCFunctionWithKeywords_CAST(meth), (self), (args), NULL)
#define _PyCFunctionWithKeywords_TrampolineCall(meth, self, args, kw) \
_PyEM_TrampolineCall((meth), (self), (args), (kw))
-#define descr_set_trampoline_call(set, obj, value, closure) \
- ((int)_PyEM_TrampolineCall((PyCFunctionWithKeywords)(set), (obj), (value), (PyObject*)(closure)))
+#define descr_set_trampoline_call(set, obj, value, closure) \
+ ((int)_PyEM_TrampolineCall(_PyCFunctionWithKeywords_CAST(set), (obj), \
+ (value), (PyObject*)(closure)))
-#define descr_get_trampoline_call(get, obj, closure) \
- _PyEM_TrampolineCall((PyCFunctionWithKeywords)(get), (obj), (PyObject*)(closure), NULL)
+#define descr_get_trampoline_call(get, obj, closure) \
+ _PyEM_TrampolineCall(_PyCFunctionWithKeywords_CAST(get), (obj), \
+ (PyObject*)(closure), NULL)
#else // defined(__EMSCRIPTEN__) && defined(PY_CALL_TRAMPOLINE)
typedef PyCFunctionFast _PyCFunctionFast;
typedef PyCFunctionFastWithKeywords _PyCFunctionFastWithKeywords;
-// Cast an function to the PyCFunction type to use it with PyMethodDef.
+// Cast a function to the PyCFunction type to use it with PyMethodDef.
//
// This macro can be used to prevent compiler warnings if the first parameter
// uses a different pointer type than PyObject* (ex: METH_VARARGS and METH_O
// used to prevent a compiler warning. If the function has a single parameter,
// it triggers an undefined behavior when Python calls it with 2 parameters
// (bpo-33012).
-#define _PyCFunction_CAST(func) \
- _Py_CAST(PyCFunction, _Py_CAST(void(*)(void), (func)))
+#define _PyCFunction_CAST(func) \
+ _Py_FUNC_CAST(PyCFunction, func)
+// The macros below are given for semantic convenience, allowing users
+// to see whether a cast to suppress an undefined behavior is necessary.
+// Note: At runtime, the original function signature must be respected.
+#define _PyCFunctionFast_CAST(func) \
+ _Py_FUNC_CAST(PyCFunctionFast, func)
+#define _PyCFunctionWithKeywords_CAST(func) \
+ _Py_FUNC_CAST(PyCFunctionWithKeywords, func)
+#define _PyCFunctionFastWithKeywords_CAST(func) \
+ _Py_FUNC_CAST(PyCFunctionFastWithKeywords, func)
PyAPI_FUNC(PyCFunction) PyCFunction_GetFunction(PyObject *);
PyAPI_FUNC(PyObject *) PyCFunction_GetSelf(PyObject *);
// Macro to use the more powerful/dangerous C-style cast even in C++.
#define _Py_CAST(type, expr) ((type)(expr))
+// Cast a function to another function type T.
+//
+// The macro first casts the function to the "void func(void)" type
+// to prevent compiler warnings.
+//
+// Note that using this cast only prevents the compiler from emitting
+// warnings, but does not prevent an undefined behavior at runtime if
+// the original function signature is not respected.
+#define _Py_FUNC_CAST(T, func) _Py_CAST(T, _Py_CAST(void(*)(void), (func)))
+
// Static inline functions should use _Py_NULL rather than using directly NULL
// to prevent C++ compiler warnings. On C23 and newer and on C++11 and newer,
// _Py_NULL is defined as nullptr.
wrapperfunc wrapper = descr->d_base->wrapper;
if (descr->d_base->flags & PyWrapperFlag_KEYWORDS) {
- wrapperfunc_kwds wk = (wrapperfunc_kwds)(void(*)(void))wrapper;
+ wrapperfunc_kwds wk = _Py_FUNC_CAST(wrapperfunc_kwds, wrapper);
return (*wk)(self, args, descr->d_wrapped, kwds);
}
PyObject *result;
if (flags & METH_KEYWORDS) {
result = _PyCFunctionWithKeywords_TrampolineCall(
- (*(PyCFunctionWithKeywords)(void(*)(void))meth),
+ *_PyCFunctionWithKeywords_CAST(meth),
self, args, kwargs);
}
else {
"__repr__($self, /)\n--\n\nReturn repr(self)."),
TPSLOT(__hash__, tp_hash, slot_tp_hash, wrap_hashfunc,
"__hash__($self, /)\n--\n\nReturn hash(self)."),
- FLSLOT(__call__, tp_call, slot_tp_call, (wrapperfunc)(void(*)(void))wrap_call,
+ FLSLOT(__call__, tp_call, slot_tp_call,
+ _Py_FUNC_CAST(wrapperfunc, wrap_call),
"__call__($self, /, *args, **kwargs)\n--\n\nCall self as a function.",
PyWrapperFlag_KEYWORDS),
TPSLOT(__str__, tp_str, slot_tp_str, wrap_unaryfunc,
TPSLOT(__delete__, tp_descr_set, slot_tp_descr_set,
wrap_descr_delete,
"__delete__($self, instance, /)\n--\n\nDelete an attribute of instance."),
- FLSLOT(__init__, tp_init, slot_tp_init, (wrapperfunc)(void(*)(void))wrap_init,
+ FLSLOT(__init__, tp_init, slot_tp_init,
+ _Py_FUNC_CAST(wrapperfunc, wrap_init),
"__init__($self, /, *args, **kwargs)\n--\n\n"
"Initialize self. See help(type(self)) for accurate signature.",
PyWrapperFlag_KEYWORDS),
DECREF_INPUTS();
ERROR_IF(true, error);
}
- PyObject *res_o = ((PyCFunctionFast)(void(*)(void))cfunc)(
+ PyObject *res_o = _PyCFunctionFast_CAST(cfunc)(
PyCFunction_GET_SELF(callable_o),
args_o,
total_args);
STAT_INC(CALL, hit);
/* res = func(self, arguments, nargs, kwnames) */
PyCFunctionFastWithKeywords cfunc =
- (PyCFunctionFastWithKeywords)(void(*)(void))
- PyCFunction_GET_FUNCTION(callable_o);
+ _PyCFunctionFastWithKeywords_CAST(PyCFunction_GET_FUNCTION(callable_o));
STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o);
if (CONVERSION_FAILED(args_o)) {
ERROR_IF(true, error);
}
PyCFunctionFastWithKeywords cfunc =
- (PyCFunctionFastWithKeywords)(void(*)(void))meth->ml_meth;
+ _PyCFunctionFastWithKeywords_CAST(meth->ml_meth);
PyObject *res_o = cfunc(self, (args_o + 1), nargs, NULL);
STACKREFS_TO_PYOBJECTS_CLEANUP(args_o);
assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
DECREF_INPUTS();
ERROR_IF(true, error);
}
- PyCFunctionFast cfunc =
- (PyCFunctionFast)(void(*)(void))meth->ml_meth;
+ PyCFunctionFast cfunc = _PyCFunctionFast_CAST(meth->ml_meth);
PyObject *res_o = cfunc(self, (args_o + 1), nargs);
STACKREFS_TO_PYOBJECTS_CLEANUP(args_o);
assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
JUMP_TO_ERROR();
}
_PyFrame_SetStackPointer(frame, stack_pointer);
- PyObject *res_o = ((PyCFunctionFast)(void(*)(void))cfunc)(
+ PyObject *res_o = _PyCFunctionFast_CAST(cfunc)(
PyCFunction_GET_SELF(callable_o),
args_o,
total_args);
STAT_INC(CALL, hit);
_PyFrame_SetStackPointer(frame, stack_pointer);
PyCFunctionFastWithKeywords cfunc =
- (PyCFunctionFastWithKeywords)(void(*)(void))
- PyCFunction_GET_FUNCTION(callable_o);
+ _PyCFunctionFastWithKeywords_CAST(PyCFunction_GET_FUNCTION(callable_o));
stack_pointer = _PyFrame_GetStackPointer(frame);
STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o);
if (CONVERSION_FAILED(args_o)) {
}
_PyFrame_SetStackPointer(frame, stack_pointer);
PyCFunctionFastWithKeywords cfunc =
- (PyCFunctionFastWithKeywords)(void(*)(void))meth->ml_meth;
+ _PyCFunctionFastWithKeywords_CAST(meth->ml_meth);
PyObject *res_o = cfunc(self, (args_o + 1), nargs, NULL);
stack_pointer = _PyFrame_GetStackPointer(frame);
STACKREFS_TO_PYOBJECTS_CLEANUP(args_o);
JUMP_TO_ERROR();
}
_PyFrame_SetStackPointer(frame, stack_pointer);
- PyCFunctionFast cfunc =
- (PyCFunctionFast)(void(*)(void))meth->ml_meth;
+ PyCFunctionFast cfunc = _PyCFunctionFast_CAST(meth->ml_meth);
PyObject *res_o = cfunc(self, (args_o + 1), nargs);
stack_pointer = _PyFrame_GetStackPointer(frame);
STACKREFS_TO_PYOBJECTS_CLEANUP(args_o);
JUMP_TO_LABEL(error);
}
_PyFrame_SetStackPointer(frame, stack_pointer);
- PyObject *res_o = ((PyCFunctionFast)(void(*)(void))cfunc)(
+ PyObject *res_o = _PyCFunctionFast_CAST(cfunc)(
PyCFunction_GET_SELF(callable_o),
args_o,
total_args);
STAT_INC(CALL, hit);
_PyFrame_SetStackPointer(frame, stack_pointer);
PyCFunctionFastWithKeywords cfunc =
- (PyCFunctionFastWithKeywords)(void(*)(void))
- PyCFunction_GET_FUNCTION(callable_o);
+ _PyCFunctionFastWithKeywords_CAST(PyCFunction_GET_FUNCTION(callable_o));
stack_pointer = _PyFrame_GetStackPointer(frame);
STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o);
if (CONVERSION_FAILED(args_o)) {
JUMP_TO_LABEL(error);
}
_PyFrame_SetStackPointer(frame, stack_pointer);
- PyCFunctionFast cfunc =
- (PyCFunctionFast)(void(*)(void))meth->ml_meth;
+ PyCFunctionFast cfunc = _PyCFunctionFast_CAST(meth->ml_meth);
PyObject *res_o = cfunc(self, (args_o + 1), nargs);
stack_pointer = _PyFrame_GetStackPointer(frame);
STACKREFS_TO_PYOBJECTS_CLEANUP(args_o);
}
_PyFrame_SetStackPointer(frame, stack_pointer);
PyCFunctionFastWithKeywords cfunc =
- (PyCFunctionFastWithKeywords)(void(*)(void))meth->ml_meth;
+ _PyCFunctionFastWithKeywords_CAST(meth->ml_meth);
PyObject *res_o = cfunc(self, (args_o + 1), nargs, NULL);
stack_pointer = _PyFrame_GetStackPointer(frame);
STACKREFS_TO_PYOBJECTS_CLEANUP(args_o);