From c96f4f736a59db9dc34b776392576d4832914689 Mon Sep 17 00:00:00 2001 From: Eric Botcazou Date: Sat, 20 Dec 2003 08:12:39 +0100 Subject: [PATCH] re PR c/12085 (Internal compiler error in convert_move, at expr.c:504 with -O3 flag) PR c/12085 * c-typeck.c (build_function_call): Issue a warning if a function is called through an incompatible prototype and replace the call by a trap in this case. From-SVN: r74874 --- gcc/ChangeLog | 7 ++++ gcc/c-typeck.c | 42 ++++++++++++++++++++++ gcc/testsuite/ChangeLog | 4 +++ gcc/testsuite/gcc.dg/cast-function-1.c | 49 ++++++++++++++++++++++++++ 4 files changed, 102 insertions(+) create mode 100644 gcc/testsuite/gcc.dg/cast-function-1.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index af9d6d4f703..a61b4935d39 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +2003-12-20 Eric Botcazou + + PR c/12085 + * c-typeck.c (build_function_call): Issue a warning if a + function is called through an incompatible prototype and + replace the call by a trap in this case. + 2003-12-19 James E Wilson * install.texi (ia64-*-linux): Document minimum libunwind version diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c index 9747a8c064d..eee6d551783 100644 --- a/gcc/c-typeck.c +++ b/gcc/c-typeck.c @@ -1645,6 +1645,7 @@ build_function_call (tree function, tree params) tree fntype, fundecl = 0; tree coerced_params; tree name = NULL_TREE, result; + tree tem; /* Strip NON_LVALUE_EXPRs, etc., since we aren't using as an lvalue. */ STRIP_TYPE_NOPS (function); @@ -1684,6 +1685,47 @@ build_function_call (tree function, tree params) /* fntype now gets the type of function pointed to. */ fntype = TREE_TYPE (fntype); + /* 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. + + ??? This doesn't work for Objective-C because objc_comptypes + refuses to compare function prototypes, yet the compiler appears + to build calls that are flagged as invalid by C's comptypes. */ + if (! c_dialect_objc () + && TREE_CODE (function) == NOP_EXPR + && TREE_CODE (tem = TREE_OPERAND (function, 0)) == ADDR_EXPR + && TREE_CODE (tem = TREE_OPERAND (tem, 0)) == FUNCTION_DECL + && ! comptypes (fntype, TREE_TYPE (tem), COMPARE_STRICT)) + { + tree return_type = TREE_TYPE (fntype); + tree trap = build_function_call (built_in_decls[BUILT_IN_TRAP], + NULL_TREE); + + /* 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 ("function called through a non-compatible type"); + + if (VOID_TYPE_P (return_type)) + return trap; + else + { + tree rhs; + + if (AGGREGATE_TYPE_P (return_type)) + rhs = build_compound_literal (return_type, + build_constructor (return_type, + NULL_TREE)); + else + rhs = fold (build1 (NOP_EXPR, return_type, integer_zero_node)); + + return build (COMPOUND_EXPR, return_type, trap, rhs); + } + } + /* Convert the parameters to the types declared in the function prototype, or apply default promotions. */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index bb7bce642a7..c62be7e4ba2 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2003-12-20 Eric Botcazou + + * gcc.dg/cast-function-1.c: New test. + 2003-12-19 Joseph S. Myers * gcc.dg/format/ext-1.c: Allow 'I' flag on floating point decimal diff --git a/gcc/testsuite/gcc.dg/cast-function-1.c b/gcc/testsuite/gcc.dg/cast-function-1.c new file mode 100644 index 00000000000..44cb1839623 --- /dev/null +++ b/gcc/testsuite/gcc.dg/cast-function-1.c @@ -0,0 +1,49 @@ +/* PR c/12085 */ +/* Origin: David Hollenberg */ + +/* Verify that the compiler doesn't inline a function at + a calling point where it is viewed with a different + prototype than the actual one. */ + +/* { dg-do compile } */ +/* { dg-options "-O3" } */ + +int foo1(int); +int foo2(); + +typedef struct { + double d; + int a; +} str_t; + +void bar(void) +{ + double d; + int i; + str_t s; + + d = ((double (*) (int)) foo1) (i); /* { dg-warning "non-compatible" } */ + i = ((int (*) (double)) foo1) (d); /* { dg-warning "non-compatible" } */ + s = ((str_t (*) (int)) foo1) (i); /* { dg-warning "non-compatible" } */ + ((void (*) (int)) foo1) (d); /* { dg-warning "non-compatible" } */ + i = ((int (*) (int)) foo1) (i); /* { dg-bogus "non-compatible" } */ + (void) foo1 (i); /* { dg-bogus "non-compatible" } */ + + d = ((double (*) (int)) foo2) (i); /* { dg-warning "non-compatible" } */ + i = ((int (*) (double)) foo2) (d); /* { dg-bogus "non-compatible" } */ + s = ((str_t (*) (int)) foo2) (i); /* { dg-warning "non-compatible" } */ + ((void (*) (int)) foo2) (d); /* { dg-warning "non-compatible" } */ + i = ((int (*) (int)) foo2) (i); /* { dg-bogus "non-compatible" } */ + (void) foo2 (i); /* { dg-bogus "non-compatible" } */ +} + +int foo1(int arg) +{ + return arg; +} + +int foo2(arg) + int arg; +{ + return arg; +} -- 2.30.2