gcc trunk throws a bogus warning about incompatible function cast when the cast target and the function have different argument lengths but the same arguments for the common subset. An example of this is the PyCFunction <-> PyCFunctionWithKeywords cast in python. Patch posted along with test case: https://gcc.gnu.org/ml/gcc-patches/2018-02/msg01315.html
The suggested wild-card function type for functions taking 2 or more parameters would be something like this: PyObject * (*) (PyObject *, PyObject *, ...); It is still necessary to cast it back to the correct type before calling.
There's also a PyCFunctionWithoutArgs that takes just one parameter so it'll have to be one arg onwards but I don't know the impact on it's API. I'm going to test that when I get back home tonight and propose a fix in Python. I kinda understand the rationale behind not diluting the warning, but I'd like to keep this open pending conclusion of the discussion on the ML.
Actually the warning on PyCFunctionWithoutArgs is _not_ a false positive: I am looking at Python-3.6.1 right now. What I see is that functions with no arguments have the signature "PyObject * (*)(PyObject *)" but on the call side the Call passes two arguments see Python-3.6.1/Objects/methodobject.c: case METH_NOARGS: size = PyTuple_GET_SIZE(args); if (size != 0) { PyErr_Format(PyExc_TypeError, "%.200s() takes no arguments (%zd given)", f->m_ml->ml_name, size); return NULL; } res = (*meth)(self, NULL);
Also these look like more like invalid casts than bogus warnings: ../Python-3.6.1/Objects/frameobject.c:586:5: Warnung: cast between incompatible function types from »void (*)(PyFrameObject *)« {alias »void (*)(struct _fra me *)«} to »int (*)(PyObject *)« {alias »int (*)(struct _object *)«} [-Wcast-function-type] (inquiry)frame_tp_clear, /* tp_clear */ ^ ../Python-3.6.1/Objects/funcobject.c:408:18: Warnung: cast between incompatible function types from »PyObject * (*)(PyFunctionObject *)« {alias »struct _obj ect * (*)(struct <anonym> *)«} to »PyObject * (*)(PyObject *, void *)« {alias »struct _object * (*)(struct _object *, void *)«} [-Wcast-function-type] {"__code__", (getter)func_get_code, (setter)func_set_code}, ^ ../Python-3.6.1/Objects/funcobject.c:408:41: Warnung: cast between incompatible function types from »int (*)(PyFunctionObject *, PyObject *)« {alias »int (* )(struct <anonym> *, struct _object *)«} to »int (*)(PyObject *, PyObject *, void *)« {alias »int (*)(struct _object *, struct _object *, void *)«} [-Wcast- function-type] {"__code__", (getter)func_get_code, (setter)func_set_code}, ^ And unfortunately the last two would be suppressed by the proposed patch.
Yeah that doesn't look good. I had not done a cpython build; I had started with a gem5 build (which builds python modules) and only superficially looked at cpython. I thought about this over the weekend and agree that silencing the warning will only hold us back indefinitely. I'll look at the cpython build a bit closer and try to fix it there when I have time for it. Thanks for looking into this.