On Wed, 29 Jan 2014, Richard Biener wrote:

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

testing reveals diagnostic regressions

FAIL: gcc.dg/call-diag-2.c abort (test for warnings, line 12)
FAIL: gcc.dg/call-diag-2.c abort (test for warnings, line 15)
FAIL: gcc.dg/invalid-call-1.c  (test for warnings, line 16)

which may be hard to preserve (didn't investigate thoroughly yet),
one is probably emitted via the call to require_complete_type
I remove.

Is it ok to adjust the testcases expectation for what is produced now?
Otherwise I'll dump this patch for now.

Thanks,
Richard.

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

-- 
Richard Biener <rguent...@suse.de>
SUSE / SUSE Labs
SUSE LINUX Products GmbH - Nuernberg - AG Nuernberg - HRB 16746
GF: Jeff Hawn, Jennifer Guild, Felix Imend"orffer

Reply via email to