[PATCH] Fix bogus function cast warning for functions with common arg subset

Siddhesh Poyarekar siddhesh@sourceware.org
Fri Feb 23 03:40:00 GMT 2018


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



More information about the Gcc-patches mailing list