OSDN Git Service

PR c/12085
authorebotcazou <ebotcazou@138bc75d-0d04-0410-961f-82ee72b054a4>
Sat, 20 Dec 2003 07:12:39 +0000 (07:12 +0000)
committerebotcazou <ebotcazou@138bc75d-0d04-0410-961f-82ee72b054a4>
Sat, 20 Dec 2003 07:12:39 +0000 (07:12 +0000)
* 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.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@74874 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/c-typeck.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/cast-function-1.c [new file with mode: 0644]

index af9d6d4..a61b493 100644 (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
index 9747a8c..eee6d55 100644 (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.  */
 
index bb7bce6..c62be7e 100644 (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
diff --git a/gcc/testsuite/gcc.dg/cast-function-1.c b/gcc/testsuite/gcc.dg/cast-function-1.c
new file mode 100644 (file)
index 0000000..44cb183
--- /dev/null
@@ -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;
+}