Skip to content

Commit f0bc694

Browse files
authored
bpo-47164: Add _PyCFunction_CAST() macro (GH-32192)
Use the macro in C files of the Python/ directory.
1 parent c14d7e4 commit f0bc694

File tree

8 files changed

+57
-36
lines changed

8 files changed

+57
-36
lines changed

Doc/c-api/structures.rst

+3
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,9 @@ There are these calling conventions:
342342
hold a reference to the module or object instance. In all cases the second
343343
parameter will be ``NULL``.
344344
345+
The function must have 2 parameters. Since the second parameter is unused,
346+
:c:macro:`Py_UNUSED` can be used to prevent a compiler warning.
347+
345348
346349
.. data:: METH_O
347350

Include/methodobject.h

+18
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,24 @@ typedef PyObject *(*_PyCFunctionFastWithKeywords) (PyObject *,
2626
typedef PyObject *(*PyCMethod)(PyObject *, PyTypeObject *, PyObject *const *,
2727
size_t, PyObject *);
2828

29+
// Cast an function to the PyCFunction type to use it with PyMethodDef.
30+
//
31+
// This macro can be used to prevent compiler warnings if the first parameter
32+
// uses a different pointer type than PyObject* (ex: METH_VARARGS and METH_O
33+
// calling conventions).
34+
//
35+
// The macro can also be used for METH_FASTCALL and METH_VARARGS|METH_KEYWORDS
36+
// calling conventions to avoid compiler warnings because the function has more
37+
// than 2 parameters. The macro first casts the function to the
38+
// "void func(void)" type to prevent compiler warnings.
39+
//
40+
// If a function is declared with the METH_NOARGS calling convention, it must
41+
// have 2 parameters. Since the second parameter is unused, Py_UNUSED() can be
42+
// used to prevent a compiler warning. If the function has a single parameter,
43+
// it triggers an undefined behavior when Python calls it with 2 parameters
44+
// (bpo-33012).
45+
#define _PyCFunction_CAST(func) ((PyCFunction)(void(*)(void))(func))
46+
2947
PyAPI_FUNC(PyCFunction) PyCFunction_GetFunction(PyObject *);
3048
PyAPI_FUNC(PyObject *) PyCFunction_GetSelf(PyObject *);
3149
PyAPI_FUNC(int) PyCFunction_GetFlags(PyObject *);

Python/_warnings.c

+3-3
Original file line numberDiff line numberDiff line change
@@ -1078,7 +1078,7 @@ warnings_warn_explicit(PyObject *self, PyObject *args, PyObject *kwds)
10781078
}
10791079

10801080
static PyObject *
1081-
warnings_filters_mutated(PyObject *self, PyObject *args)
1081+
warnings_filters_mutated(PyObject *self, PyObject *Py_UNUSED(args))
10821082
{
10831083
PyInterpreterState *interp = get_current_interp();
10841084
if (interp == NULL) {
@@ -1353,9 +1353,9 @@ PyDoc_STRVAR(warn_explicit_doc,
13531353

13541354
static PyMethodDef warnings_functions[] = {
13551355
WARNINGS_WARN_METHODDEF
1356-
{"warn_explicit", (PyCFunction)(void(*)(void))warnings_warn_explicit,
1356+
{"warn_explicit", _PyCFunction_CAST(warnings_warn_explicit),
13571357
METH_VARARGS | METH_KEYWORDS, warn_explicit_doc},
1358-
{"_filters_mutated", (PyCFunction)warnings_filters_mutated, METH_NOARGS,
1358+
{"_filters_mutated", _PyCFunction_CAST(warnings_filters_mutated), METH_NOARGS,
13591359
NULL},
13601360
/* XXX(brett.cannon): add showwarning? */
13611361
/* XXX(brett.cannon): Reasonable to add formatwarning? */

Python/bltinmodule.c

+13-13
Original file line numberDiff line numberDiff line change
@@ -613,7 +613,7 @@ filter_reduce(filterobject *lz, PyObject *Py_UNUSED(ignored))
613613
PyDoc_STRVAR(reduce_doc, "Return state information for pickling.");
614614

615615
static PyMethodDef filter_methods[] = {
616-
{"__reduce__", (PyCFunction)filter_reduce, METH_NOARGS, reduce_doc},
616+
{"__reduce__", _PyCFunction_CAST(filter_reduce), METH_NOARGS, reduce_doc},
617617
{NULL, NULL} /* sentinel */
618618
};
619619

@@ -1354,7 +1354,7 @@ map_reduce(mapobject *lz, PyObject *Py_UNUSED(ignored))
13541354
}
13551355

13561356
static PyMethodDef map_methods[] = {
1357-
{"__reduce__", (PyCFunction)map_reduce, METH_NOARGS, reduce_doc},
1357+
{"__reduce__", _PyCFunction_CAST(map_reduce), METH_NOARGS, reduce_doc},
13581358
{NULL, NULL} /* sentinel */
13591359
};
13601360

@@ -2321,7 +2321,7 @@ PyDoc_STRVAR(builtin_sorted__doc__,
23212321
"reverse flag can be set to request the result in descending order.");
23222322

23232323
#define BUILTIN_SORTED_METHODDEF \
2324-
{"sorted", (PyCFunction)(void(*)(void))builtin_sorted, METH_FASTCALL | METH_KEYWORDS, builtin_sorted__doc__},
2324+
{"sorted", _PyCFunction_CAST(builtin_sorted), METH_FASTCALL | METH_KEYWORDS, builtin_sorted__doc__},
23252325

23262326
static PyObject *
23272327
builtin_sorted(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
@@ -2839,8 +2839,8 @@ zip_setstate(zipobject *lz, PyObject *state)
28392839
}
28402840

28412841
static PyMethodDef zip_methods[] = {
2842-
{"__reduce__", (PyCFunction)zip_reduce, METH_NOARGS, reduce_doc},
2843-
{"__setstate__", (PyCFunction)zip_setstate, METH_O, setstate_doc},
2842+
{"__reduce__", _PyCFunction_CAST(zip_reduce), METH_NOARGS, reduce_doc},
2843+
{"__setstate__", _PyCFunction_CAST(zip_setstate), METH_O, setstate_doc},
28442844
{NULL} /* sentinel */
28452845
};
28462846

@@ -2904,25 +2904,25 @@ PyTypeObject PyZip_Type = {
29042904

29052905

29062906
static PyMethodDef builtin_methods[] = {
2907-
{"__build_class__", (PyCFunction)(void(*)(void))builtin___build_class__,
2907+
{"__build_class__", _PyCFunction_CAST(builtin___build_class__),
29082908
METH_FASTCALL | METH_KEYWORDS, build_class_doc},
29092909
BUILTIN___IMPORT___METHODDEF
29102910
BUILTIN_ABS_METHODDEF
29112911
BUILTIN_ALL_METHODDEF
29122912
BUILTIN_ANY_METHODDEF
29132913
BUILTIN_ASCII_METHODDEF
29142914
BUILTIN_BIN_METHODDEF
2915-
{"breakpoint", (PyCFunction)(void(*)(void))builtin_breakpoint, METH_FASTCALL | METH_KEYWORDS, breakpoint_doc},
2915+
{"breakpoint", _PyCFunction_CAST(builtin_breakpoint), METH_FASTCALL | METH_KEYWORDS, breakpoint_doc},
29162916
BUILTIN_CALLABLE_METHODDEF
29172917
BUILTIN_CHR_METHODDEF
29182918
BUILTIN_COMPILE_METHODDEF
29192919
BUILTIN_DELATTR_METHODDEF
2920-
{"dir", builtin_dir, METH_VARARGS, dir_doc},
2920+
{"dir", builtin_dir, METH_VARARGS, dir_doc},
29212921
BUILTIN_DIVMOD_METHODDEF
29222922
BUILTIN_EVAL_METHODDEF
29232923
BUILTIN_EXEC_METHODDEF
29242924
BUILTIN_FORMAT_METHODDEF
2925-
{"getattr", (PyCFunction)(void(*)(void))builtin_getattr, METH_FASTCALL, getattr_doc},
2925+
{"getattr", _PyCFunction_CAST(builtin_getattr), METH_FASTCALL, getattr_doc},
29262926
BUILTIN_GLOBALS_METHODDEF
29272927
BUILTIN_HASATTR_METHODDEF
29282928
BUILTIN_HASH_METHODDEF
@@ -2931,13 +2931,13 @@ static PyMethodDef builtin_methods[] = {
29312931
BUILTIN_INPUT_METHODDEF
29322932
BUILTIN_ISINSTANCE_METHODDEF
29332933
BUILTIN_ISSUBCLASS_METHODDEF
2934-
{"iter", (PyCFunction)(void(*)(void))builtin_iter, METH_FASTCALL, iter_doc},
2934+
{"iter", _PyCFunction_CAST(builtin_iter), METH_FASTCALL, iter_doc},
29352935
BUILTIN_AITER_METHODDEF
29362936
BUILTIN_LEN_METHODDEF
29372937
BUILTIN_LOCALS_METHODDEF
2938-
{"max", (PyCFunction)(void(*)(void))builtin_max, METH_VARARGS | METH_KEYWORDS, max_doc},
2939-
{"min", (PyCFunction)(void(*)(void))builtin_min, METH_VARARGS | METH_KEYWORDS, min_doc},
2940-
{"next", (PyCFunction)(void(*)(void))builtin_next, METH_FASTCALL, next_doc},
2938+
{"max", _PyCFunction_CAST(builtin_max), METH_VARARGS | METH_KEYWORDS, max_doc},
2939+
{"min", _PyCFunction_CAST(builtin_min), METH_VARARGS | METH_KEYWORDS, min_doc},
2940+
{"next", _PyCFunction_CAST(builtin_next), METH_FASTCALL, next_doc},
29412941
BUILTIN_ANEXT_METHODDEF
29422942
BUILTIN_OCT_METHODDEF
29432943
BUILTIN_ORD_METHODDEF

Python/context.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -685,7 +685,7 @@ static PyMethodDef PyContext_methods[] = {
685685
_CONTEXTVARS_CONTEXT_KEYS_METHODDEF
686686
_CONTEXTVARS_CONTEXT_VALUES_METHODDEF
687687
_CONTEXTVARS_CONTEXT_COPY_METHODDEF
688-
{"run", (PyCFunction)(void(*)(void))context_run, METH_FASTCALL | METH_KEYWORDS, NULL},
688+
{"run", _PyCFunction_CAST(context_run), METH_FASTCALL | METH_KEYWORDS, NULL},
689689
{NULL, NULL}
690690
};
691691

Python/hamt.c

+9-9
Original file line numberDiff line numberDiff line change
@@ -2845,29 +2845,29 @@ hamt_py_values(PyHamtObject *self, PyObject *args)
28452845
}
28462846

28472847
static PyObject *
2848-
hamt_py_keys(PyHamtObject *self, PyObject *args)
2848+
hamt_py_keys(PyHamtObject *self, PyObject *Py_UNUSED(args))
28492849
{
28502850
return _PyHamt_NewIterKeys(self);
28512851
}
28522852

28532853
#ifdef Py_DEBUG
28542854
static PyObject *
2855-
hamt_py_dump(PyHamtObject *self, PyObject *args)
2855+
hamt_py_dump(PyHamtObject *self, PyObject *Py_UNUSED(args))
28562856
{
28572857
return hamt_dump(self);
28582858
}
28592859
#endif
28602860

28612861

28622862
static PyMethodDef PyHamt_methods[] = {
2863-
{"set", (PyCFunction)hamt_py_set, METH_VARARGS, NULL},
2864-
{"get", (PyCFunction)hamt_py_get, METH_VARARGS, NULL},
2865-
{"delete", (PyCFunction)hamt_py_delete, METH_O, NULL},
2866-
{"items", (PyCFunction)hamt_py_items, METH_NOARGS, NULL},
2867-
{"keys", (PyCFunction)hamt_py_keys, METH_NOARGS, NULL},
2868-
{"values", (PyCFunction)hamt_py_values, METH_NOARGS, NULL},
2863+
{"set", _PyCFunction_CAST(hamt_py_set), METH_VARARGS, NULL},
2864+
{"get", _PyCFunction_CAST(hamt_py_get), METH_VARARGS, NULL},
2865+
{"delete", _PyCFunction_CAST(hamt_py_delete), METH_O, NULL},
2866+
{"items", _PyCFunction_CAST(hamt_py_items), METH_NOARGS, NULL},
2867+
{"keys", _PyCFunction_CAST(hamt_py_keys), METH_NOARGS, NULL},
2868+
{"values", _PyCFunction_CAST(hamt_py_values), METH_NOARGS, NULL},
28692869
#ifdef Py_DEBUG
2870-
{"__dump__", (PyCFunction)hamt_py_dump, METH_NOARGS, NULL},
2870+
{"__dump__", _PyCFunction_CAST(hamt_py_dump), METH_NOARGS, NULL},
28712871
#endif
28722872
{NULL, NULL}
28732873
};

Python/sysmodule.c

+9-9
Original file line numberDiff line numberDiff line change
@@ -1929,8 +1929,8 @@ sys_getandroidapilevel_impl(PyObject *module)
19291929
static PyMethodDef sys_methods[] = {
19301930
/* Might as well keep this in alphabetic order */
19311931
SYS_ADDAUDITHOOK_METHODDEF
1932-
{"audit", (PyCFunction)(void(*)(void))sys_audit, METH_FASTCALL, audit_doc },
1933-
{"breakpointhook", (PyCFunction)(void(*)(void))sys_breakpointhook,
1932+
{"audit", _PyCFunction_CAST(sys_audit), METH_FASTCALL, audit_doc },
1933+
{"breakpointhook", _PyCFunction_CAST(sys_breakpointhook),
19341934
METH_FASTCALL | METH_KEYWORDS, breakpointhook_doc},
19351935
SYS__CLEAR_TYPE_CACHE_METHODDEF
19361936
SYS__CURRENT_FRAMES_METHODDEF
@@ -1944,18 +1944,18 @@ static PyMethodDef sys_methods[] = {
19441944
SYS_GETDLOPENFLAGS_METHODDEF
19451945
SYS_GETALLOCATEDBLOCKS_METHODDEF
19461946
#ifdef Py_STATS
1947-
{"getdxp", _Py_GetDXProfile, METH_VARARGS},
1947+
{"getdxp", _Py_GetDXProfile, METH_VARARGS},
19481948
#endif
19491949
SYS_GETFILESYSTEMENCODING_METHODDEF
19501950
SYS_GETFILESYSTEMENCODEERRORS_METHODDEF
19511951
SYS__GETQUICKENEDCOUNT_METHODDEF
19521952
#ifdef Py_TRACE_REFS
1953-
{"getobjects", _Py_GetObjects, METH_VARARGS},
1953+
{"getobjects", _Py_GetObjects, METH_VARARGS},
19541954
#endif
19551955
SYS_GETTOTALREFCOUNT_METHODDEF
19561956
SYS_GETREFCOUNT_METHODDEF
19571957
SYS_GETRECURSIONLIMIT_METHODDEF
1958-
{"getsizeof", (PyCFunction)(void(*)(void))sys_getsizeof,
1958+
{"getsizeof", _PyCFunction_CAST(sys_getsizeof),
19591959
METH_VARARGS | METH_KEYWORDS, getsizeof_doc},
19601960
SYS__GETFRAME_METHODDEF
19611961
SYS_GETWINDOWSVERSION_METHODDEF
@@ -1966,21 +1966,21 @@ static PyMethodDef sys_methods[] = {
19661966
SYS_SETSWITCHINTERVAL_METHODDEF
19671967
SYS_GETSWITCHINTERVAL_METHODDEF
19681968
SYS_SETDLOPENFLAGS_METHODDEF
1969-
{"setprofile", sys_setprofile, METH_O, setprofile_doc},
1969+
{"setprofile", sys_setprofile, METH_O, setprofile_doc},
19701970
SYS_GETPROFILE_METHODDEF
19711971
SYS_SETRECURSIONLIMIT_METHODDEF
1972-
{"settrace", sys_settrace, METH_O, settrace_doc},
1972+
{"settrace", sys_settrace, METH_O, settrace_doc},
19731973
SYS_GETTRACE_METHODDEF
19741974
SYS_CALL_TRACING_METHODDEF
19751975
SYS__DEBUGMALLOCSTATS_METHODDEF
19761976
SYS_SET_COROUTINE_ORIGIN_TRACKING_DEPTH_METHODDEF
19771977
SYS_GET_COROUTINE_ORIGIN_TRACKING_DEPTH_METHODDEF
1978-
{"set_asyncgen_hooks", (PyCFunction)(void(*)(void))sys_set_asyncgen_hooks,
1978+
{"set_asyncgen_hooks", _PyCFunction_CAST(sys_set_asyncgen_hooks),
19791979
METH_VARARGS | METH_KEYWORDS, set_asyncgen_hooks_doc},
19801980
SYS_GET_ASYNCGEN_HOOKS_METHODDEF
19811981
SYS_GETANDROIDAPILEVEL_METHODDEF
19821982
SYS_UNRAISABLEHOOK_METHODDEF
1983-
{NULL, NULL} /* sentinel */
1983+
{NULL, NULL} // sentinel
19841984
};
19851985

19861986

Python/traceback.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ tb_next_set(PyTracebackObject *self, PyObject *new_next, void *Py_UNUSED(_))
149149

150150

151151
static PyMethodDef tb_methods[] = {
152-
{"__dir__", (PyCFunction)tb_dir, METH_NOARGS},
152+
{"__dir__", _PyCFunction_CAST(tb_dir), METH_NOARGS},
153153
{NULL, NULL, 0, NULL},
154154
};
155155

0 commit comments

Comments
 (0)