Libraries like gtk/glib[1] and python[2] use functions with common argument subsets to register callbacks. The working idea behind it is to have a flag in the structure (or some other pre-determined method) that specifies how the callback is cast and called.
Fix this by not throwing a warning when functions with different argument list lengths (of M and N where M < N) have compatible argument types for the first M arguments. Tested and bootstrapped on x86_64. Siddhesh [1] I haven't checked gtk/glib lately, but I remember the G_CALLBACK interface does similar things [2] python has the PyCFunction type member ml_meth in PyMethodDef which is designed to accept a PyCFunctionWithKeywords (3 void * arguments instead of 2 in PyCFunction) and ml_meth is then cast internally to either based on flags in the ml_flags member in PyMethodDef. gcc/c: * c-typcheck.c (c_safe_function_type_cast_p): Don't warn on unequal number of arguments as long as the common argument types match. gcc/cp: * c-typcheck.c (c_safe_function_type_cast_p): Don't warn on unequal number of arguments as long as the common argument types match. gcc/testsuite: * c-c++-common/Wcast-function-type.c: New test cases. --- gcc/c/c-typeck.c | 9 +++++++- gcc/cp/typeck.c | 9 +++++++- gcc/testsuite/c-c++-common/Wcast-function-type.c | 29 ++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index 1eae4ea849c..16887cd3ac4 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -5520,7 +5520,14 @@ c_safe_function_type_cast_p (tree t1, tree t2) t1 && t2; t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2)) if (!c_safe_arg_type_equiv_p (TREE_VALUE (t1), TREE_VALUE (t2))) - return false; + { + /* Don't warn on unequal number of arguments as long as the common + argument types match. This is a common idiom for callbacks. */ + if (t1 == void_list_node || t2 == void_list_node) + return true; + + return false; + } return true; } diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 0e7c63dd197..f35dca3a05e 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -1221,7 +1221,14 @@ cxx_safe_function_type_cast_p (tree t1, tree t2) t1 && t2; t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2)) if (!cxx_safe_arg_type_equiv_p (TREE_VALUE (t1), TREE_VALUE (t2))) - return false; + { + /* Don't warn on unequal number of arguments as long as the common + argument types match. This is a common idiom for callbacks. */ + if (t1 == void_list_node || t2 == void_list_node) + return true; + + return false; + } return true; } diff --git a/gcc/testsuite/c-c++-common/Wcast-function-type.c b/gcc/testsuite/c-c++-common/Wcast-function-type.c index 81105762ef7..f38ad3fe73d 100644 --- a/gcc/testsuite/c-c++-common/Wcast-function-type.c +++ b/gcc/testsuite/c-c++-common/Wcast-function-type.c @@ -2,6 +2,8 @@ /* { dg-options "-Wcast-function-type" } */ int f(long); +int g(long, double); +int h(long, double, double, int); typedef int (f1)(long); typedef int (f2)(void*); @@ -14,11 +16,26 @@ typedef void (f4)(); #endif typedef void (f5)(void); +typedef int (f6)(long, void *); +typedef int (f7)(long, double, double); +typedef int (f8)(long, void *, double); + f1 *a; f2 *b; f3 *c; f4 *d; f5 *e; +f6 *i; +f7 *j; +f8 *k; + +f6 *l; +f7 *m; +f8 *n; + +f6 *o; +f7 *p; +f8 *q; void foo (void) @@ -28,4 +45,16 @@ foo (void) c = (f3 *) f; /* { dg-bogus "incompatible function types" } */ d = (f4 *) f; /* { dg-warning "incompatible function types" } */ e = (f5 *) f; /* { dg-bogus "incompatible function types" } */ + + i = (f6 *) f; /* { dg-bogus "incompatible function types" } */ + j = (f7 *) f; /* { dg-bogus "incompatible function types" } */ + k = (f8 *) f; /* { dg-bogus "incompatible function types" } */ + + l = (f6 *) g; /* { dg-warning "incompatible function types" } */ + m = (f7 *) g; /* { dg-bogus "incompatible function types" } */ + n = (f8 *) g; /* { dg-warning "incompatible function types" } */ + + o = (f6 *) h; /* { dg-warning "incompatible function types" } */ + p = (f7 *) h; /* { dg-bogus "incompatible function types" } */ + q = (f8 *) h; /* { dg-warning "incompatible function types" } */ } -- 2.14.3