This removes the code that tries to avoid ICEs in the middle-end when facing calls through an incompatible type. The middle-end can now happily deal with those mismatches (and we rely on that). Also the code only detects the most primitive cases like
((bar_get_x_func*) foo_get_x) (x) but does not touch bar_get_x_func* fn = foo_get_x; fn (x); I preserved the warning (so I didn't have to remove the cast-function-1.c testcase) and fixed the testcase to be not optimized to nothing by the very first DCE pass and thus get non-empty assembler output with some calls and some inlines (yes, we _can_ inline some mismatches, esp. those refered to in the PR which is about void * vs some struct * type). Bootstrap / regtest running on x86_64-unknown-linux-gnu - ok for trunk? Thanks, Richard. 2014-01-29 Richard Biener <rguent...@suse.de> PR c/59905 * c-typeck.c (build_function_call_vec): Do not replace calls to a function via an incompatible type with a runtime abort. * gcc.dg/cast-function-1.c: Adjust to survive DCE. Index: gcc/c/c-typeck.c =================================================================== *** gcc/c/c-typeck.c (revision 207194) --- gcc/c/c-typeck.c (working copy) *************** build_function_call_vec (location_t loc, *** 2907,2962 **** return error_mark_node; /* Check that the function is called through a compatible prototype. ! If it is not, replace the call by a trap, wrapped up in a compound ! expression if necessary. This has the nice side-effect to prevent ! the tree-inliner from generating invalid assignment trees which may ! blow up in the RTL expander later. */ if (CONVERT_EXPR_P (function) && TREE_CODE (tem = TREE_OPERAND (function, 0)) == ADDR_EXPR && TREE_CODE (tem = TREE_OPERAND (tem, 0)) == FUNCTION_DECL && !comptypes (fntype, TREE_TYPE (tem))) { tree return_type = TREE_TYPE (fntype); - tree trap = build_function_call (loc, - builtin_decl_explicit (BUILT_IN_TRAP), - NULL_TREE); - int i; /* This situation leads to run-time undefined behavior. We can't, therefore, simply error unless we can prove that all possible executions of the program must execute the code. */ ! if (warning_at (loc, 0, "function called through a non-compatible type")) ! /* We can, however, treat "undefined" any way we please. ! Call abort to encourage the user to fix the program. */ ! inform (loc, "if this code is reached, the program will abort"); ! /* Before the abort, allow the function arguments to exit or ! call longjmp. */ ! for (i = 0; i < nargs; i++) ! trap = build2 (COMPOUND_EXPR, void_type_node, (*params)[i], trap); ! if (VOID_TYPE_P (return_type)) ! { ! if (TYPE_QUALS (return_type) != TYPE_UNQUALIFIED) ! pedwarn (loc, 0, ! "function with qualified void return type called"); ! return trap; ! } ! else ! { ! tree rhs; ! ! if (AGGREGATE_TYPE_P (return_type)) ! rhs = build_compound_literal (loc, return_type, ! build_constructor (return_type, ! NULL), ! false); ! else ! rhs = build_zero_cst (return_type); ! ! return require_complete_type (build2 (COMPOUND_EXPR, return_type, ! trap, rhs)); ! } ! } argarray = vec_safe_address (params); --- 2907,2930 ---- return error_mark_node; /* Check that the function is called through a compatible prototype. ! If it is not, warn. */ if (CONVERT_EXPR_P (function) && TREE_CODE (tem = TREE_OPERAND (function, 0)) == ADDR_EXPR && TREE_CODE (tem = TREE_OPERAND (tem, 0)) == FUNCTION_DECL && !comptypes (fntype, TREE_TYPE (tem))) { tree return_type = TREE_TYPE (fntype); /* This situation leads to run-time undefined behavior. We can't, therefore, simply error unless we can prove that all possible executions of the program must execute the code. */ ! warning_at (loc, 0, "function called through a non-compatible type"); ! if (VOID_TYPE_P (return_type) ! && TYPE_QUALS (return_type) != TYPE_UNQUALIFIED) ! pedwarn (loc, 0, ! "function with qualified void return type called"); ! } argarray = vec_safe_address (params); Index: gcc/testsuite/gcc.dg/cast-function-1.c =================================================================== *** gcc/testsuite/gcc.dg/cast-function-1.c (revision 207194) --- gcc/testsuite/gcc.dg/cast-function-1.c (working copy) *************** typedef struct { *** 16,27 **** int a; } str_t; ! void bar(void) { - double d; - int i; - str_t s; - d = ((double (*) (int)) foo1) (i); /* { dg-warning "33:non-compatible|abort" } */ i = ((int (*) (double)) foo1) (d); /* { dg-warning "33:non-compatible|abort" } */ s = ((str_t (*) (int)) foo1) (i); /* { dg-warning "32:non-compatible|abort" } */ --- 16,23 ---- int a; } str_t; ! void bar(double d, int i, str_t s) { d = ((double (*) (int)) foo1) (i); /* { dg-warning "33:non-compatible|abort" } */ i = ((int (*) (double)) foo1) (d); /* { dg-warning "33:non-compatible|abort" } */ s = ((str_t (*) (int)) foo1) (i); /* { dg-warning "32:non-compatible|abort" } */ *************** void bar(void) *** 39,49 **** --- 35,49 ---- int foo1(int arg) { + /* Prevent the function from becoming const and thus DCEd. */ + __asm volatile ("" : "+r" (arg)); return arg; } int foo2(arg) int arg; { + /* Prevent the function from becoming const and thus DCEd. */ + __asm volatile ("" : "+r" (arg)); return arg; }