+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
+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
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)
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);
}
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.
+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
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. */
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);
+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
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
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
&& 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)))
{
-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
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
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
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); }
+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
--- /dev/null
+/* { 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" } */
+}
--- /dev/null
+/* { 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" } */
+}
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);
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>. */
+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
{
/* 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 *,