diff mbox series

[PATCHv3] Add a warning for invalid function casts

Message ID AM5PR0701MB26573F24B606519E3CA56997E4390@AM5PR0701MB2657.eurprd07.prod.outlook.com
State New
Headers show
Series [PATCHv3] Add a warning for invalid function casts | expand

Commit Message

Bernd Edlinger Dec. 1, 2017, 12:42 p.m. UTC
Hi,

this version of the patch improves the heuristic check to take the
target hook into account, to handle cases correctly when both or only
one parameter is _not_ promoted to int.

Both C and C++ FE should of course use the same logic here.


Bootstrapped and reg-tested on x86_64-pc-linux-gnu.
Is it OK for trunk?


Thanks
Bernd.
gcc:
2017-10-06  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-10-06  Bernd Edlinger  <bernd.edlinger@hotmail.de>

	* internal.h (maybe_print_line): Change signature.
	
c-family:
2017-10-06  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-10-06  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-10-06  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-10-06  Bernd Edlinger  <bernd.edlinger@hotmail.de>

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

Comments

Jason Merrill Dec. 6, 2017, 10:35 p.m. UTC | #1
On Fri, Dec 1, 2017 at 7:42 AM, Bernd Edlinger
<bernd.edlinger@hotmail.de> wrote:
> this version of the patch improves the heuristic check to take the
> target hook into account, to handle cases correctly when both or only
> one parameter is _not_ promoted to int.

In looking at this, I discovered that the argument to
promote_prototypes should be the function type, not the parameter
type; the existing uses in the C++ front end were wrong.

Jason
Bernd Edlinger Dec. 7, 2017, 8:48 p.m. UTC | #2
On 12/06/17 23:35, Jason Merrill wrote:
> On Fri, Dec 1, 2017 at 7:42 AM, Bernd Edlinger

> <bernd.edlinger@hotmail.de> wrote:

>> this version of the patch improves the heuristic check to take the

>> target hook into account, to handle cases correctly when both or only

>> one parameter is _not_ promoted to int.

> 

> In looking at this, I discovered that the argument to

> promote_prototypes should be the function type, not the parameter

> type; the existing uses in the C++ front end were wrong.

> 


Bah, sorry.

Yes, it looks like there are at least two more target hooks that change
the type promotion rules later-on: targetm.calls.promote_function_mode
and PROMOTE_MODE.

In the ada FE we pass NULL_TREE to promote_prototypes which seems to
mean if the target wants type promotion in principle.  So it returns
true if some function may promote, and false if no function promotes.
At least this is how the sh-target handles this parameter.
This is BTW the only target that uses the argument of this callback.

So I would think for the purpose of this warning the following check
should be sufficient:

   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)))


What do you think?
Is the patch OK with this change?


Thanks
Bernd.
Bernd Edlinger Dec. 14, 2017, 6:35 p.m. UTC | #3
On 12/07/17 21:48, Bernd Edlinger wrote:
> On 12/06/17 23:35, Jason Merrill wrote:

>> On Fri, Dec 1, 2017 at 7:42 AM, Bernd Edlinger

>> <bernd.edlinger@hotmail.de> wrote:

>>> this version of the patch improves the heuristic check to take the

>>> target hook into account, to handle cases correctly when both or only

>>> one parameter is _not_ promoted to int.

>>

>> In looking at this, I discovered that the argument to

>> promote_prototypes should be the function type, not the parameter

>> type; the existing uses in the C++ front end were wrong.

>>

> 

> Bah, sorry.

> 

> Yes, it looks like there are at least two more target hooks that change

> the type promotion rules later-on: targetm.calls.promote_function_mode

> and PROMOTE_MODE.

> 

> In the ada FE we pass NULL_TREE to promote_prototypes which seems to

> mean if the target wants type promotion in principle.  So it returns

> true if some function may promote, and false if no function promotes.

> At least this is how the sh-target handles this parameter.

> This is BTW the only target that uses the argument of this callback.

> 

> So I would think for the purpose of this warning the following check

> should be sufficient:

> 

>    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)))

> 

> 

> What do you think?

> Is the patch OK with this change?

> 


So, is the simplified heuristic using only promote_prototypes (NULL)
OK?


Thanks
Bernd.
Jason Merrill Dec. 14, 2017, 6:49 p.m. UTC | #4
On Thu, Dec 7, 2017 at 3:48 PM, Bernd Edlinger
<bernd.edlinger@hotmail.de> wrote:
> On 12/06/17 23:35, Jason Merrill wrote:
>> On Fri, Dec 1, 2017 at 7:42 AM, Bernd Edlinger
>> <bernd.edlinger@hotmail.de> wrote:
>>> this version of the patch improves the heuristic check to take the
>>> target hook into account, to handle cases correctly when both or only
>>> one parameter is _not_ promoted to int.
>>
>> In looking at this, I discovered that the argument to
>> promote_prototypes should be the function type, not the parameter
>> type; the existing uses in the C++ front end were wrong.
>>
>
> Bah, sorry.
>
> Yes, it looks like there are at least two more target hooks that change
> the type promotion rules later-on: targetm.calls.promote_function_mode
> and PROMOTE_MODE.
>
> In the ada FE we pass NULL_TREE to promote_prototypes which seems to
> mean if the target wants type promotion in principle.  So it returns
> true if some function may promote, and false if no function promotes.
> At least this is how the sh-target handles this parameter.
> This is BTW the only target that uses the argument of this callback.
>
> So I would think for the purpose of this warning the following check
> should be sufficient:
>
>    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)))
>
>
> What do you think?
> Is the patch OK with this change?

Yes.

Jason
diff mbox series

Patch

Index: gcc/c/c-typeck.c
===================================================================
--- gcc/c/c-typeck.c	(revision 255270)
+++ gcc/c/c-typeck.c	(working copy)
@@ -5452,6 +5452,62 @@  handle_warn_cast_qual (location_t loc, tree type,
   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)
+      && (targetm.calls.promote_prototypes (t1)
+	  == targetm.calls.promote_prototypes (t2)
+	  || TYPE_PRECISION (t1) >= TYPE_PRECISION (integer_type_node))
+      && (TYPE_UNSIGNED (t1) == TYPE_UNSIGNED (t2)
+	  || !targetm.calls.promote_prototypes (t1)
+	  || 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.  */
 
@@ -5645,6 +5701,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: gcc/c-family/c-lex.c
===================================================================
--- gcc/c-family/c-lex.c	(revision 255270)
+++ gcc/c-family/c-lex.c	(working copy)
@@ -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: gcc/c-family/c-ppoutput.c
===================================================================
--- gcc/c-family/c-ppoutput.c	(revision 255270)
+++ gcc/c-family/c-ppoutput.c	(working copy)
@@ -299,7 +299,7 @@  scan_translation_unit_directives_only (cpp_reader
   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: gcc/c-family/c.opt
===================================================================
--- gcc/c-family/c.opt	(revision 255270)
+++ gcc/c-family/c.opt	(working copy)
@@ -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: gcc/cp/decl2.c
===================================================================
--- gcc/cp/decl2.c	(revision 255270)
+++ gcc/cp/decl2.c	(working copy)
@@ -3525,7 +3525,8 @@  start_static_storage_duration_function (unsigned c
       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: gcc/cp/typeck.c
===================================================================
--- gcc/cp/typeck.c	(revision 255270)
+++ gcc/cp/typeck.c	(working copy)
@@ -1173,6 +1173,62 @@  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)
+      && (targetm.calls.promote_prototypes (t1)
+	  == targetm.calls.promote_prototypes (t2)
+	  || TYPE_PRECISION (t1) >= TYPE_PRECISION (integer_type_node))
+      && (TYPE_UNSIGNED (t1) == TYPE_UNSIGNED (t2)
+	  || !targetm.calls.promote_prototypes (t1)
+	  || 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
@@ -7297,9 +7353,27 @@  build_reinterpret_cast_1 (tree type, tree expr, bo
 	   && 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: gcc/doc/invoke.texi
===================================================================
--- gcc/doc/invoke.texi	(revision 255270)
+++ gcc/doc/invoke.texi	(working copy)
@@ -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
 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
@@ -6033,6 +6034,21 @@  Warn whenever a pointer is cast such that the requ
 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: gcc/recog.h
===================================================================
--- gcc/recog.h	(revision 255270)
+++ gcc/recog.h	(working copy)
@@ -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: gcc/testsuite/c-c++-common/Wcast-function-type.c
===================================================================
--- gcc/testsuite/c-c++-common/Wcast-function-type.c	(revision 0)
+++ gcc/testsuite/c-c++-common/Wcast-function-type.c	(working copy)
@@ -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" } */
+}
Index: gcc/testsuite/g++.dg/Wcast-function-type.C
===================================================================
--- gcc/testsuite/g++.dg/Wcast-function-type.C	(revision 0)
+++ gcc/testsuite/g++.dg/Wcast-function-type.C	(working copy)
@@ -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: gcc/tree-dump.c
===================================================================
--- gcc/tree-dump.c	(revision 255270)
+++ gcc/tree-dump.c	(working copy)
@@ -736,7 +736,8 @@  dump_node (const_tree t, dump_flags_t flags, FILE
   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: gcc/typed-splay-tree.h
===================================================================
--- gcc/typed-splay-tree.h	(revision 255270)
+++ gcc/typed-splay-tree.h	(working copy)
@@ -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: libcpp/internal.h
===================================================================
--- libcpp/internal.h	(revision 255270)
+++ libcpp/internal.h	(working copy)
@@ -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 *,