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);
/* 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. */
--- /dev/null
+/* 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;
+}