Skip to content

Commit 09fb715

Browse files
committed
feat(semantics): use a macro for suppressing UB warnings
1 parent 0f04f24 commit 09fb715

File tree

9 files changed

+36
-30
lines changed

9 files changed

+36
-30
lines changed

Include/internal/pycore_emscripten_trampoline.h

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,17 +37,18 @@ _PyEM_TrampolineCall(PyCFunctionWithKeywords func,
3737
PyObject* kw);
3838

3939
#define _PyCFunction_TrampolineCall(meth, self, args) \
40-
_PyEM_TrampolineCall( \
41-
(*(PyCFunctionWithKeywords)(void(*)(void))(meth)), (self), (args), NULL)
40+
_PyEM_TrampolineCall(*_PyCFunctionWithKeywords_CAST(meth), (self), (args), NULL)
4241

4342
#define _PyCFunctionWithKeywords_TrampolineCall(meth, self, args, kw) \
4443
_PyEM_TrampolineCall((meth), (self), (args), (kw))
4544

46-
#define descr_set_trampoline_call(set, obj, value, closure) \
47-
((int)_PyEM_TrampolineCall((PyCFunctionWithKeywords)(set), (obj), (value), (PyObject*)(closure)))
45+
#define descr_set_trampoline_call(set, obj, value, closure) \
46+
((int)_PyEM_TrampolineCall(_PyCFunctionWithKeywords_CAST(set), (obj), \
47+
(value), (PyObject*)(closure)))
4848

49-
#define descr_get_trampoline_call(get, obj, closure) \
50-
_PyEM_TrampolineCall((PyCFunctionWithKeywords)(get), (obj), (PyObject*)(closure), NULL)
49+
#define descr_get_trampoline_call(get, obj, closure) \
50+
_PyEM_TrampolineCall(_PyCFunctionWithKeywords_CAST(get), (obj), \
51+
(PyObject*)(closure), NULL)
5152

5253

5354
#else // defined(__EMSCRIPTEN__) && defined(PY_CALL_TRAMPOLINE)

Include/methodobject.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,16 @@ typedef PyCFunctionFastWithKeywords _PyCFunctionFastWithKeywords;
4949
// used to prevent a compiler warning. If the function has a single parameter,
5050
// it triggers an undefined behavior when Python calls it with 2 parameters
5151
// (bpo-33012).
52-
#define _PyCFunction_CAST(func) \
53-
_Py_CAST(PyCFunction, _Py_CAST(void(*)(void), (func)))
52+
#define _PyCFunction_CAST(func) \
53+
_Py_FUNC_CAST(PyCFunction, func)
54+
// Other casts are given for semantic conveniences, allowing
55+
// users to see whether a cast to suppress a UB is necessary.
56+
#define _PyCFunctionFast_CAST(func) \
57+
_Py_FUNC_CAST(PyCFunctionFast, func)
58+
#define _PyCFunctionWithKeywords_CAST(func) \
59+
_Py_FUNC_CAST(PyCFunctionWithKeywords, func)
60+
#define _PyCFunctionFastWithKeywords_CAST(func) \
61+
_Py_FUNC_CAST(PyCFunctionFastWithKeywords, func)
5462

5563
PyAPI_FUNC(PyCFunction) PyCFunction_GetFunction(PyObject *);
5664
PyAPI_FUNC(PyObject *) PyCFunction_GetSelf(PyObject *);

Include/pyport.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#endif
3636
// Macro to use the more powerful/dangerous C-style cast even in C++.
3737
#define _Py_CAST(type, expr) ((type)(expr))
38+
#define _Py_FUNC_CAST(T, func) _Py_CAST(T, _Py_CAST(void(*)(void), (func)))
3839

3940
// Static inline functions should use _Py_NULL rather than using directly NULL
4041
// to prevent C++ compiler warnings. On C23 and newer and on C++11 and newer,

Objects/descrobject.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -519,7 +519,7 @@ wrapperdescr_raw_call(PyWrapperDescrObject *descr, PyObject *self,
519519
wrapperfunc wrapper = descr->d_base->wrapper;
520520

521521
if (descr->d_base->flags & PyWrapperFlag_KEYWORDS) {
522-
wrapperfunc_kwds wk = (wrapperfunc_kwds)(void(*)(void))wrapper;
522+
wrapperfunc_kwds wk = _Py_FUNC_CAST(wrapperfunc_kwds, wrapper);
523523
return (*wk)(self, args, descr->d_wrapped, kwds);
524524
}
525525

Objects/methodobject.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -563,7 +563,7 @@ cfunction_call(PyObject *func, PyObject *args, PyObject *kwargs)
563563
PyObject *result;
564564
if (flags & METH_KEYWORDS) {
565565
result = _PyCFunctionWithKeywords_TrampolineCall(
566-
(*(PyCFunctionWithKeywords)(void(*)(void))meth),
566+
*_PyCFunctionWithKeywords_CAST(meth),
567567
self, args, kwargs);
568568
}
569569
else {

Objects/typeobject.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10758,7 +10758,8 @@ static pytype_slotdef slotdefs[] = {
1075810758
"__repr__($self, /)\n--\n\nReturn repr(self)."),
1075910759
TPSLOT(__hash__, tp_hash, slot_tp_hash, wrap_hashfunc,
1076010760
"__hash__($self, /)\n--\n\nReturn hash(self)."),
10761-
FLSLOT(__call__, tp_call, slot_tp_call, (wrapperfunc)(void(*)(void))wrap_call,
10761+
FLSLOT(__call__, tp_call, slot_tp_call,
10762+
_Py_FUNC_CAST(wrapperfunc, wrap_call),
1076210763
"__call__($self, /, *args, **kwargs)\n--\n\nCall self as a function.",
1076310764
PyWrapperFlag_KEYWORDS),
1076410765
TPSLOT(__str__, tp_str, slot_tp_str, wrap_unaryfunc,
@@ -10795,7 +10796,8 @@ static pytype_slotdef slotdefs[] = {
1079510796
TPSLOT(__delete__, tp_descr_set, slot_tp_descr_set,
1079610797
wrap_descr_delete,
1079710798
"__delete__($self, instance, /)\n--\n\nDelete an attribute of instance."),
10798-
FLSLOT(__init__, tp_init, slot_tp_init, (wrapperfunc)(void(*)(void))wrap_init,
10799+
FLSLOT(__init__, tp_init, slot_tp_init,
10800+
_Py_FUNC_CAST(wrapperfunc, wrap_call),
1079910801
"__init__($self, /, *args, **kwargs)\n--\n\n"
1080010802
"Initialize self. See help(type(self)) for accurate signature.",
1080110803
PyWrapperFlag_KEYWORDS),

Python/bytecodes.c

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4117,7 +4117,7 @@ dummy_func(
41174117
DECREF_INPUTS();
41184118
ERROR_IF(true, error);
41194119
}
4120-
PyObject *res_o = ((PyCFunctionFast)(void(*)(void))cfunc)(
4120+
PyObject *res_o = _PyCFunctionFast_CAST(cfunc)(
41214121
PyCFunction_GET_SELF(callable_o),
41224122
args_o,
41234123
total_args);
@@ -4149,8 +4149,7 @@ dummy_func(
41494149
STAT_INC(CALL, hit);
41504150
/* res = func(self, arguments, nargs, kwnames) */
41514151
PyCFunctionFastWithKeywords cfunc =
4152-
(PyCFunctionFastWithKeywords)(void(*)(void))
4153-
PyCFunction_GET_FUNCTION(callable_o);
4152+
_PyCFunctionFastWithKeywords_CAST(PyCFunction_GET_FUNCTION(callable_o));
41544153

41554154
STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o);
41564155
if (CONVERSION_FAILED(args_o)) {
@@ -4318,7 +4317,7 @@ dummy_func(
43184317
ERROR_IF(true, error);
43194318
}
43204319
PyCFunctionFastWithKeywords cfunc =
4321-
(PyCFunctionFastWithKeywords)(void(*)(void))meth->ml_meth;
4320+
_PyCFunctionFastWithKeywords_CAST(meth->ml_met);
43224321
PyObject *res_o = cfunc(self, (args_o + 1), nargs, NULL);
43234322
STACKREFS_TO_PYOBJECTS_CLEANUP(args_o);
43244323
assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
@@ -4397,8 +4396,7 @@ dummy_func(
43974396
DECREF_INPUTS();
43984397
ERROR_IF(true, error);
43994398
}
4400-
PyCFunctionFast cfunc =
4401-
(PyCFunctionFast)(void(*)(void))meth->ml_meth;
4399+
PyCFunctionFast cfunc = _PyCFunctionFast_CAST(meth->ml_meth);
44024400
PyObject *res_o = cfunc(self, (args_o + 1), nargs);
44034401
STACKREFS_TO_PYOBJECTS_CLEANUP(args_o);
44044402
assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL));

Python/executor_cases.c.h

Lines changed: 4 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/generated_cases.c.h

Lines changed: 4 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)