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
This commit is contained in:
Eric Botcazou 2003-12-20 08:12:39 +01:00 committed by Eric Botcazou
parent bcd11e5e45
commit c96f4f736a
4 changed files with 102 additions and 0 deletions

View File

@ -1,3 +1,10 @@
2003-12-20 Eric Botcazou <ebotcazou@libertysurf.fr>
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 <wilson@specifixinc.com>
* install.texi (ia64-*-linux): Document minimum libunwind version

View File

@ -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. */

View File

@ -1,3 +1,7 @@
2003-12-20 Eric Botcazou <ebotcazou@libertysurf.fr>
* gcc.dg/cast-function-1.c: New test.
2003-12-19 Joseph S. Myers <jsm@polyomino.org.uk>
* gcc.dg/format/ext-1.c: Allow 'I' flag on floating point decimal

View File

@ -0,0 +1,49 @@
/* PR c/12085 */
/* Origin: David Hollenberg <dhollen@mosis.org> */
/* 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;
}