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;
  }

Reply via email to