[PATCH][C] Fix PR59905, remove code replacing calls with abort

Richard Biener rguenther@suse.de
Wed Jan 29 11:28:00 GMT 2014


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



More information about the Gcc-patches mailing list