invoke.texi: Document -Wcast-function-type.
authorBernd Edlinger <bernd.edlinger@hotmail.de>
Thu, 14 Dec 2017 18:59:24 +0000 (18:59 +0000)
committerBernd Edlinger <edlinger@gcc.gnu.org>
Thu, 14 Dec 2017 18:59:24 +0000 (18:59 +0000)
gcc:
2017-12-14  Bernd Edlinger  <bernd.edlinger@hotmail.de>

        * doc/invoke.texi: Document -Wcast-function-type.
        * recog.h (stored_funcptr): Change signature.
        * tree-dump.c (dump_node): Avoid warning.
        * typed-splay-tree.h (typed_splay_tree): Avoid warning.

libcpp:
2017-12-14  Bernd Edlinger  <bernd.edlinger@hotmail.de>

        * internal.h (maybe_print_line): Change signature.

c-family:
2017-12-14  Bernd Edlinger  <bernd.edlinger@hotmail.de>

        * c.opt (Wcast-function-type): New warning option.
        * c-lex.c (get_fileinfo): Avoid warning.
        * c-ppoutput.c (scan_translation_unit_directives_only): Remove cast.

c:
2017-12-14  Bernd Edlinger  <bernd.edlinger@hotmail.de>

        * c-typeck.c (c_safe_arg_type_equiv_p,
        c_safe_function_type_cast_p): New function.
        (build_c_cast): Implement -Wcast-function-type.

cp:
2017-12-14  Bernd Edlinger  <bernd.edlinger@hotmail.de>

        * decl2.c (start_static_storage_duration_function): Avoid warning.
        * typeck.c (cxx_safe_arg_type_equiv_p,
        cxx_safe_function_type_cast_p): New function.
        (build_reinterpret_cast_1): Implement -Wcast-function-type.

testsuite:
2017-12-14  Bernd Edlinger  <bernd.edlinger@hotmail.de>

        * c-c++-common/Wcast-function-type.c: New test.
        * g++.dg/Wcast-function-type.C: New test.

From-SVN: r255661

19 files changed:
gcc/ChangeLog
gcc/c-family/ChangeLog
gcc/c-family/c-lex.c
gcc/c-family/c-ppoutput.c
gcc/c-family/c.opt
gcc/c/ChangeLog
gcc/c/c-typeck.c
gcc/cp/ChangeLog
gcc/cp/decl2.c
gcc/cp/typeck.c
gcc/doc/invoke.texi
gcc/recog.h
gcc/testsuite/ChangeLog
gcc/testsuite/c-c++-common/Wcast-function-type.c [new file with mode: 0644]
gcc/testsuite/g++.dg/Wcast-function-type.C [new file with mode: 0644]
gcc/tree-dump.c
gcc/typed-splay-tree.h
libcpp/ChangeLog
libcpp/internal.h

index 0192d672823c2814637e92c6d128c8d89ed7a631..d57e06b0f0e7fb6a0045f261f8b44e83e69c2035 100644 (file)
@@ -1,3 +1,10 @@
+2017-12-14  Bernd Edlinger  <bernd.edlinger@hotmail.de>
+
+       * doc/invoke.texi: Document -Wcast-function-type.
+       * recog.h (stored_funcptr): Change signature.
+       * tree-dump.c (dump_node): Avoid warning.
+       * typed-splay-tree.h (typed_splay_tree): Avoid warning.
+
 2017-12-14  Qing Zhao  <qing.zhao@oracle.com>
 
        PR middle_end/79538
index abe53019aa669e0bfbcb1436c3d575f6df7b450b..9f87d008382c60574408a5493e238fbb337b0f0b 100644 (file)
@@ -1,3 +1,9 @@
+2017-12-14  Bernd Edlinger  <bernd.edlinger@hotmail.de>
+
+       * c.opt (Wcast-function-type): New warning option.
+       * c-lex.c (get_fileinfo): Avoid warning.
+       * c-ppoutput.c (scan_translation_unit_directives_only): Remove cast.
+
 2017-12-14  Qing Zhao  <qing.zhao@oracle.com>
 
        PR middle_end/79538 
index 8342800303a335b7991d3571154200ac593a8e72..d45dc4b68402127b8b59e099c6039b26cfbec2e8 100644 (file)
@@ -101,9 +101,11 @@ get_fileinfo (const char *name)
   struct c_fileinfo *fi;
 
   if (!file_info_tree)
-    file_info_tree = splay_tree_new ((splay_tree_compare_fn) strcmp,
+    file_info_tree = splay_tree_new ((splay_tree_compare_fn)
+                                    (void (*) (void)) strcmp,
                                     0,
-                                    (splay_tree_delete_value_fn) free);
+                                    (splay_tree_delete_value_fn)
+                                    (void (*) (void)) free);
 
   n = splay_tree_lookup (file_info_tree, (splay_tree_key) name);
   if (n)
index d1c92379f62fee4fe3bd2a9d156c2ff623806d29..32176ed122e1c9c542bdcd15b3a7b39bbacaafc4 100644 (file)
@@ -299,7 +299,7 @@ scan_translation_unit_directives_only (cpp_reader *pfile)
   struct _cpp_dir_only_callbacks cb;
 
   cb.print_lines = print_lines_directives_only;
-  cb.maybe_print_line = (void (*) (source_location)) maybe_print_line;
+  cb.maybe_print_line = maybe_print_line;
 
   _cpp_preprocess_dir_only (pfile, &cb);
 }
index b25481057365a59e9ce49aa0a8b3d52726550cd6..31b50ee56c9aa9b61d6db702019dbd77a0bd60c9 100644 (file)
@@ -384,6 +384,10 @@ Wc++17-compat
 C++ ObjC++ Var(warn_cxx17_compat) Warning LangEnabledBy(C++ ObjC++,Wall)
 Warn about C++ constructs whose meaning differs between ISO C++ 2014 and ISO C++ 2017.
 
+Wcast-function-type
+C ObjC C++ ObjC++ Var(warn_cast_function_type) Warning EnabledBy(Wextra)
+Warn about casts between incompatible function types.
+
 Wcast-qual
 C ObjC C++ ObjC++ Var(warn_cast_qual) Warning
 Warn about casts which discard qualifiers.
index 3f5414bc18de3153fdd007a2631882629a99d62a..d486018e3a2b00701de96ded8fe42609e2988018 100644 (file)
@@ -1,3 +1,9 @@
+2017-12-14  Bernd Edlinger  <bernd.edlinger@hotmail.de>
+
+       * c-typeck.c (c_safe_arg_type_equiv_p,
+       c_safe_function_type_cast_p): New function.
+       (build_c_cast): Implement -Wcast-function-type.
+
 2017-12-14  Richard Biener  <rguenther@suse.de>
 
        PR c/83415
index 13b26845d97a8be17504a11f35fc3a2733ea1e4c..541fb61ef08b035606ddd7b191b58736b7158ac3 100644 (file)
@@ -5472,6 +5472,59 @@ handle_warn_cast_qual (location_t loc, tree type, tree otype)
   while (TREE_CODE (in_type) == POINTER_TYPE);
 }
 
+/* Heuristic check if two parameter types can be considered ABI-equivalent.  */
+
+static bool
+c_safe_arg_type_equiv_p (tree t1, tree t2)
+{
+  t1 = TYPE_MAIN_VARIANT (t1);
+  t2 = TYPE_MAIN_VARIANT (t2);
+
+  if (TREE_CODE (t1) == POINTER_TYPE
+      && TREE_CODE (t2) == POINTER_TYPE)
+    return true;
+
+  /* The signedness of the parameter matters only when an integral
+     type smaller than int is promoted to int, otherwise only the
+     precision of the parameter matters.
+     This check should make sure that the callee does not see
+     undefined values in argument registers.  */
+  if (INTEGRAL_TYPE_P (t1)
+      && INTEGRAL_TYPE_P (t2)
+      && TYPE_PRECISION (t1) == TYPE_PRECISION (t2)
+      && (TYPE_UNSIGNED (t1) == TYPE_UNSIGNED (t2)
+         || !targetm.calls.promote_prototypes (NULL_TREE)
+         || TYPE_PRECISION (t1) >= TYPE_PRECISION (integer_type_node)))
+    return true;
+
+  return comptypes (t1, t2);
+}
+
+/* Check if a type cast between two function types can be considered safe.  */
+
+static bool
+c_safe_function_type_cast_p (tree t1, tree t2)
+{
+  if (TREE_TYPE (t1) == void_type_node &&
+      TYPE_ARG_TYPES (t1) == void_list_node)
+    return true;
+
+  if (TREE_TYPE (t2) == void_type_node &&
+      TYPE_ARG_TYPES (t2) == void_list_node)
+    return true;
+
+  if (!c_safe_arg_type_equiv_p (TREE_TYPE (t1), TREE_TYPE (t2)))
+    return false;
+
+  for (t1 = TYPE_ARG_TYPES (t1), t2 = TYPE_ARG_TYPES (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;
+
+  return true;
+}
+
 /* Build an expression representing a cast to type TYPE of expression EXPR.
    LOC is the location of the cast-- typically the open paren of the cast.  */
 
@@ -5665,6 +5718,16 @@ build_c_cast (location_t loc, tree type, tree expr)
        pedwarn (loc, OPT_Wpedantic, "ISO C forbids "
                 "conversion of object pointer to function pointer type");
 
+      if (TREE_CODE (type) == POINTER_TYPE
+         && TREE_CODE (otype) == POINTER_TYPE
+         && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE
+         && TREE_CODE (TREE_TYPE (otype)) == FUNCTION_TYPE
+         && !c_safe_function_type_cast_p (TREE_TYPE (type),
+                                          TREE_TYPE (otype)))
+       warning_at (loc, OPT_Wcast_function_type,
+                   "cast between incompatible function types"
+                   " from %qT to %qT", otype, type);
+
       ovalue = value;
       value = convert (type, value);
 
index ac6a8e1bfffea72c127ea06e592c044e15cc28bf..d7a1dde686f0a0ff050cb1e87a44c6c1ce4946f0 100644 (file)
@@ -1,3 +1,10 @@
+2017-12-14  Bernd Edlinger  <bernd.edlinger@hotmail.de>
+
+       * decl2.c (start_static_storage_duration_function): Avoid warning.
+       * typeck.c (cxx_safe_arg_type_equiv_p,
+       cxx_safe_function_type_cast_p): New function.
+       (build_reinterpret_cast_1): Implement -Wcast-function-type.
+
 2017-12-14  Jakub Jelinek  <jakub@redhat.com>
 
        PR c++/79650
index 5d30369e80fec6fa4f14b7d984496c2875ea7ad5..89a940ac3309aad13a67753136711ed2bc8147b5 100644 (file)
@@ -3558,7 +3558,8 @@ start_static_storage_duration_function (unsigned count)
       priority_info_map = splay_tree_new (splay_tree_compare_ints,
                                          /*delete_key_fn=*/0,
                                          /*delete_value_fn=*/
-                                         (splay_tree_delete_value_fn) &free);
+                                         (splay_tree_delete_value_fn)
+                                         (void (*) (void)) free);
 
       /* We always need to generate functions for the
         DEFAULT_INIT_PRIORITY so enter it now.  That way when we walk
index 8f3302f19334c5df2ff347be795b81aa004d2f22..390aa1580bd1f01b95943d7cf0693c560d16b9fd 100644 (file)
@@ -1173,6 +1173,59 @@ comp_template_parms_position (tree t1, tree t2)
   return true;
 }
 
+/* Heuristic check if two parameter types can be considered ABI-equivalent.  */
+
+static bool
+cxx_safe_arg_type_equiv_p (tree t1, tree t2)
+{
+  t1 = TYPE_MAIN_VARIANT (t1);
+  t2 = TYPE_MAIN_VARIANT (t2);
+
+  if (TREE_CODE (t1) == POINTER_TYPE
+      && TREE_CODE (t2) == POINTER_TYPE)
+    return true;
+
+  /* The signedness of the parameter matters only when an integral
+     type smaller than int is promoted to int, otherwise only the
+     precision of the parameter matters.
+     This check should make sure that the callee does not see
+     undefined values in argument registers.  */
+  if (INTEGRAL_TYPE_P (t1)
+      && INTEGRAL_TYPE_P (t2)
+      && TYPE_PRECISION (t1) == TYPE_PRECISION (t2)
+      && (TYPE_UNSIGNED (t1) == TYPE_UNSIGNED (t2)
+         || !targetm.calls.promote_prototypes (NULL_TREE)
+         || TYPE_PRECISION (t1) >= TYPE_PRECISION (integer_type_node)))
+    return true;
+
+  return same_type_p (t1, t2);
+}
+
+/* Check if a type cast between two function types can be considered safe.  */
+
+static bool
+cxx_safe_function_type_cast_p (tree t1, tree t2)
+{
+  if (TREE_TYPE (t1) == void_type_node &&
+      TYPE_ARG_TYPES (t1) == void_list_node)
+    return true;
+
+  if (TREE_TYPE (t2) == void_type_node &&
+      TYPE_ARG_TYPES (t2) == void_list_node)
+    return true;
+
+  if (!cxx_safe_arg_type_equiv_p (TREE_TYPE (t1), TREE_TYPE (t2)))
+    return false;
+
+  for (t1 = TYPE_ARG_TYPES (t1), t2 = TYPE_ARG_TYPES (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;
+
+  return true;
+}
+
 /* Subroutine in comptypes.  */
 
 static bool
@@ -7326,9 +7379,27 @@ build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p,
           && same_type_p (type, intype))
     /* DR 799 */
     return rvalue (expr);
-  else if ((TYPE_PTRFN_P (type) && TYPE_PTRFN_P (intype))
-          || (TYPE_PTRMEMFUNC_P (type) && TYPE_PTRMEMFUNC_P (intype)))
-    return build_nop (type, expr);
+  else if (TYPE_PTRFN_P (type) && TYPE_PTRFN_P (intype))
+    {
+      if ((complain & tf_warning)
+         && !cxx_safe_function_type_cast_p (TREE_TYPE (type),
+                                            TREE_TYPE (intype)))
+       warning (OPT_Wcast_function_type,
+                "cast between incompatible function types"
+                " from %qH to %qI", intype, type);
+      return build_nop (type, expr);
+    }
+  else if (TYPE_PTRMEMFUNC_P (type) && TYPE_PTRMEMFUNC_P (intype))
+    {
+      if ((complain & tf_warning)
+         && !cxx_safe_function_type_cast_p
+               (TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE_RAW (type)),
+                TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE_RAW (intype))))
+       warning (OPT_Wcast_function_type,
+                "cast between incompatible pointer to member types"
+                " from %qH to %qI", intype, type);
+      return build_nop (type, expr);
+    }
   else if ((TYPE_PTRDATAMEM_P (type) && TYPE_PTRDATAMEM_P (intype))
           || (TYPE_PTROBV_P (type) && TYPE_PTROBV_P (intype)))
     {
index 0d565b48f21e03ab2cae426d4735d078c3cc7518..001bbeae5770bbee314193c6d33c4b21c3fc2602 100644 (file)
@@ -267,7 +267,7 @@ Objective-C and Objective-C++ Dialects}.
 -Wno-builtin-declaration-mismatch @gol
 -Wno-builtin-macro-redefined  -Wc90-c99-compat  -Wc99-c11-compat @gol
 -Wc++-compat  -Wc++11-compat  -Wc++14-compat  @gol
--Wcast-align  -Wcast-align=strict  -Wcast-qual  @gol
+-Wcast-align  -Wcast-align=strict  -Wcast-function-type  -Wcast-qual  @gol
 -Wchar-subscripts  -Wchkp  -Wcatch-value  -Wcatch-value=@var{n} @gol
 -Wclobbered  -Wcomment  -Wconditionally-supported @gol
 -Wconversion  -Wcoverage-mismatch  -Wno-cpp  -Wdangling-else  -Wdate-time @gol
@@ -3904,6 +3904,7 @@ This enables some extra warning flags that are not enabled by
 name is still supported, but the newer name is more descriptive.)
 
 @gccoptlist{-Wclobbered  @gol
+-Wcast-function-type  @gol
 -Wempty-body  @gol
 -Wignored-qualifiers @gol
 -Wimplicit-fallthrough=3 @gol
@@ -6041,6 +6042,21 @@ Warn whenever a pointer is cast such that the required alignment of the
 target is increased.  For example, warn if a @code{char *} is cast to
 an @code{int *} regardless of the target machine.
 
+@item -Wcast-function-type
+@opindex Wcast-function-type
+@opindex Wno-cast-function-type
+Warn when a function pointer is cast to an incompatible function pointer.
+In a cast involving function types with a variable argument list only
+the types of initial arguments that are provided are considered.
+Any parameter of pointer-type matches any other pointer-type.  Any benign
+differences in integral types are ignored, like @code{int} vs. @code{long}
+on ILP32 targets.  Likewise type qualifiers are ignored.  The function
+type @code{void (*) (void)} is special and matches everything, which can
+be used to suppress this warning.
+In a cast involving pointer to member types this warning warns whenever
+the type cast is changing the pointer to member type.
+This warning is enabled by @option{-Wextra}.
+
 @item -Wwrite-strings
 @opindex Wwrite-strings
 @opindex Wno-write-strings
index 07c60feffc692deb5d4af1e9630c18ed5da697e3..2ce979932a27e6f854f67c66dea4a92c873c2bf9 100644 (file)
@@ -294,7 +294,7 @@ struct insn_gen_fn
   typedef rtx_insn * (*f15) (rtx, rtx, rtx, rtx, rtx, rtx, rtx, rtx, rtx, rtx, rtx, rtx, rtx, rtx, rtx);
   typedef rtx_insn * (*f16) (rtx, rtx, rtx, rtx, rtx, rtx, rtx, rtx, rtx, rtx, rtx, rtx, rtx, rtx, rtx, rtx);
 
-  typedef f0 stored_funcptr;
+  typedef void (*stored_funcptr) (void);
 
   rtx_insn * operator () (void) const { return ((f0)func) (); }
   rtx_insn * operator () (rtx a0) const { return ((f1)func) (a0); }
index 6cedc130701225f2ae0efeeae144c35af88ddd73..f39da0bde0327810dd8fc176a8fe32e506c592a7 100644 (file)
@@ -1,3 +1,8 @@
+2017-12-14  Bernd Edlinger  <bernd.edlinger@hotmail.de>
+
+       * c-c++-common/Wcast-function-type.c: New test.
+       * g++.dg/Wcast-function-type.C: New test.
+
 2017-12-14  Qing Zhao  <qing.zhao@oracle.com>
 
        PR middle_end/79538
diff --git a/gcc/testsuite/c-c++-common/Wcast-function-type.c b/gcc/testsuite/c-c++-common/Wcast-function-type.c
new file mode 100644 (file)
index 0000000..8110576
--- /dev/null
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-Wcast-function-type" } */
+
+int f(long);
+
+typedef int (f1)(long);
+typedef int (f2)(void*);
+#ifdef __cplusplus
+typedef int (f3)(...);
+typedef void (f4)(...);
+#else
+typedef int (f3)();
+typedef void (f4)();
+#endif
+typedef void (f5)(void);
+
+f1 *a;
+f2 *b;
+f3 *c;
+f4 *d;
+f5 *e;
+
+void
+foo (void)
+{
+  a = (f1 *) f; /* { dg-bogus   "incompatible function types" } */
+  b = (f2 *) f; /* { dg-warning "incompatible function types" } */
+  c = (f3 *) f; /* { dg-bogus   "incompatible function types" } */
+  d = (f4 *) f; /* { dg-warning "incompatible function types" } */
+  e = (f5 *) f; /* { dg-bogus   "incompatible function types" } */
+}
diff --git a/gcc/testsuite/g++.dg/Wcast-function-type.C b/gcc/testsuite/g++.dg/Wcast-function-type.C
new file mode 100644 (file)
index 0000000..c649405
--- /dev/null
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-Wcast-function-type" } */
+
+struct S
+{
+  void foo (int*);
+  void bar (int);
+};
+
+typedef void (S::*MF)(int);
+
+void
+foo (void)
+{
+  MF p1 = (MF)&S::foo; /* { dg-warning "pointer to member" } */
+  MF p2 = (MF)&S::bar; /* { dg-bogus   "pointer to member" } */
+}
index d691278bbb2c1f3d58eb4b5f449cc5bd7ae3b2e6..74813303a526013f482b966b5b2352582421bfce 100644 (file)
@@ -736,7 +736,8 @@ dump_node (const_tree t, dump_flags_t flags, FILE *stream)
   di.flags = flags;
   di.node = t;
   di.nodes = splay_tree_new (splay_tree_compare_pointers, 0,
-                            (splay_tree_delete_value_fn) &free);
+                            (splay_tree_delete_value_fn)
+                            (void (*) (void)) free);
 
   /* Queue up the first node.  */
   queue (&di, t, DUMP_NONE);
index b41ff7ae6454d6828d82d9c6c7d0ad910d659d98..032ae4fd9d63b32fe761025004243abc52fe987b 100644 (file)
@@ -75,9 +75,12 @@ inline typed_splay_tree<KEY_TYPE, VALUE_TYPE>::
                    delete_key_fn delete_key_fn,
                    delete_value_fn delete_value_fn)
 {
-  m_inner = splay_tree_new ((splay_tree_compare_fn)compare_fn,
-                           (splay_tree_delete_key_fn)delete_key_fn,
-                           (splay_tree_delete_value_fn)delete_value_fn);
+  m_inner = splay_tree_new ((splay_tree_compare_fn)
+                           (void (*) (void)) compare_fn,
+                           (splay_tree_delete_key_fn)
+                           (void (*) (void)) delete_key_fn,
+                           (splay_tree_delete_value_fn)
+                           (void (*) (void)) delete_value_fn);
 }
 
 /* Destructor for typed_splay_tree <K, V>.  */
index 76f10fb2af75a713a38c949690c884b52b37a5f9..5a41cf4b5f510c2508ebb2445e4add282c5cf6a3 100644 (file)
@@ -1,3 +1,7 @@
+2017-12-14  Bernd Edlinger  <bernd.edlinger@hotmail.de>
+
+       * internal.h (maybe_print_line): Change signature.
+       
 2017-12-05  Jakub Jelinek  <jakub@redhat.com>
 
        PR c++/79228
index 0a33abafd43f34daadd4339387a112c199536672..ee47a53c33e969238641d985729bb58dd3260a6d 100644 (file)
@@ -709,7 +709,7 @@ struct _cpp_dir_only_callbacks
 {
   /* Called to print a block of lines. */
   void (*print_lines) (int, const void *, size_t);
-  void (*maybe_print_line) (source_location);
+  bool (*maybe_print_line) (source_location);
 };
 
 extern void _cpp_preprocess_dir_only (cpp_reader *,