jit: handle equality of function pointer types
authorDavid Malcolm <dmalcolm@redhat.com>
Thu, 28 Sep 2017 16:00:57 +0000 (16:00 +0000)
committerDavid Malcolm <dmalcolm@gcc.gnu.org>
Thu, 28 Sep 2017 16:00:57 +0000 (16:00 +0000)
gcc/jit/ChangeLog:
* jit-recording.c
(gcc::jit::recording::function_type::is_same_type_as): New function.
* jit-recording.h: In namespace gcc::jit::recording::
(type::accepts_writes_from): Use is_same_type_as rather than pointer
equality.
(type::is_same_type_as): New virtual function.
(function_type::is_same_type_as): New override.

gcc/testsuite/ChangeLog:
* jit.dg/test-error-mismatching-types-in-assignment-fn-ptr.c: New
test case.
* jit.dg/test-returning-function-ptr.c (create_code): Update to
create a function pointer type independently of the call to
gcc_jit_function_get_address, and assign the pointer to a local
before returning it, to exercise the function pointer type
comparison code.

From-SVN: r253255

gcc/jit/ChangeLog
gcc/jit/jit-recording.c
gcc/jit/jit-recording.h
gcc/testsuite/ChangeLog
gcc/testsuite/jit.dg/test-error-mismatching-types-in-assignment-fn-ptr.c [new file with mode: 0644]
gcc/testsuite/jit.dg/test-returning-function-ptr.c

index 7f14b4f..b5e2ed7 100644 (file)
@@ -1,3 +1,13 @@
+2017-09-28  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit-recording.c
+       (gcc::jit::recording::function_type::is_same_type_as): New function.
+       * jit-recording.h: In namespace gcc::jit::recording::
+       (type::accepts_writes_from): Use is_same_type_as rather than pointer
+       equality.
+       (type::is_same_type_as): New virtual function.
+       (function_type::is_same_type_as): New override.
+
 2017-09-27  David Malcolm  <dmalcolm@redhat.com>
 
        * docs/cp/topics/expressions.rst (Function pointers): New section.
index 8481280..6d7dc80 100644 (file)
@@ -2643,6 +2643,53 @@ recording::function_type::dereference ()
   return NULL;
 }
 
+/* Implementation of virtual hook recording::type::is_same_type_as for
+   recording::function_type.
+
+   We override this to avoid requiring identity of function pointer types,
+   so that if client code has obtained the same signature in
+   different ways (e.g. via gcc_jit_context_new_function_ptr_type
+   vs gcc_jit_function_get_address), the different function_type
+   instances are treated as compatible.
+
+   We can't use type::accepts_writes_from for this as we need a stronger
+   notion of "sameness": if we have a fn_ptr type that has args that are
+   themselves fn_ptr types, then those args still need to match exactly.
+
+   Alternatively, we could consolidate attempts to create identical
+   function_type instances so that pointer equality works, but that runs
+   into issues about the lifetimes of the cache (w.r.t. nested contexts).  */
+
+bool
+recording::function_type::is_same_type_as (type *other)
+{
+  gcc_assert (other);
+
+  function_type *other_fn_type = other->dyn_cast_function_type ();
+  if (!other_fn_type)
+    return false;
+
+  /* Everything must match.  */
+
+  if (!m_return_type->is_same_type_as (other_fn_type->m_return_type))
+    return false;
+
+  if (m_param_types.length () != other_fn_type->m_param_types.length ())
+    return false;
+
+  unsigned i;
+  type *param_type;
+  FOR_EACH_VEC_ELT (m_param_types, i, param_type)
+    if (!param_type->is_same_type_as (other_fn_type->m_param_types[i]))
+      return false;
+
+  if (m_is_variadic != other_fn_type->m_is_variadic)
+    return false;
+
+  /* Passed all tests.  */
+  return true;
+}
+
 /* Implementation of pure virtual hook recording::memento::replay_into
    for recording::function_type.  */
 
index 8918124..9123645 100644 (file)
@@ -491,7 +491,12 @@ public:
   virtual bool accepts_writes_from (type *rtype)
   {
     gcc_assert (rtype);
-    return this->unqualified () == rtype->unqualified ();
+    return this->unqualified ()->is_same_type_as (rtype->unqualified ());
+  }
+
+  virtual bool is_same_type_as (type *other)
+  {
+    return this == other;
   }
 
   /* Strip off "const" etc */
@@ -751,6 +756,8 @@ public:
   function_type *dyn_cast_function_type () FINAL OVERRIDE { return this; }
   function_type *as_a_function_type () FINAL OVERRIDE { return this; }
 
+  bool is_same_type_as (type *other) FINAL OVERRIDE;
+
   bool is_int () const FINAL OVERRIDE { return false; }
   bool is_float () const FINAL OVERRIDE { return false; }
   bool is_bool () const FINAL OVERRIDE { return false; }
index f2a4480..1fff0be 100644 (file)
@@ -1,3 +1,13 @@
+2017-09-28  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/test-error-mismatching-types-in-assignment-fn-ptr.c: New
+       test case.
+       * jit.dg/test-returning-function-ptr.c (create_code): Update to
+       create a function pointer type independently of the call to
+       gcc_jit_function_get_address, and assign the pointer to a local
+       before returning it, to exercise the function pointer type
+       comparison code.
+
 2017-09-27  David Malcolm  <dmalcolm@redhat.com>
 
        * jit.dg/all-non-failing-tests.h: Add
diff --git a/gcc/testsuite/jit.dg/test-error-mismatching-types-in-assignment-fn-ptr.c b/gcc/testsuite/jit.dg/test-error-mismatching-types-in-assignment-fn-ptr.c
new file mode 100644 (file)
index 0000000..4faa3b4
--- /dev/null
@@ -0,0 +1,92 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to inject the equivalent of:
+
+     typedef void (*fn_ptr_iii) (int, int, int);
+     typedef void (*fn_ptr_ifi) (int, float, int);
+     void
+     test_fn (void)
+     {
+        fn_ptr_iii iii_ptr;
+        fn_ptr_ifi ifi_ptr;
+
+       iii_ptr = NULL;
+       ifi_ptr = iii_ptr;
+     }
+
+     and verify that the API complains about the mismatching types
+     in the second assignment (but not the first).
+  */
+  gcc_jit_type *void_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+  gcc_jit_type *float_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_FLOAT);
+
+  gcc_jit_type *iii_types[] = {int_type, int_type, int_type};
+  gcc_jit_type *fn_ptr_type_iii
+    = gcc_jit_context_new_function_ptr_type (ctxt, NULL,
+                                            void_type,
+                                            3, iii_types,
+                                            0);
+
+  gcc_jit_type *ifi_types[] = {int_type, float_type, int_type};
+  gcc_jit_type *fn_ptr_type_ifi
+    = gcc_jit_context_new_function_ptr_type (ctxt, NULL,
+                                            void_type,
+                                            3, ifi_types,
+                                            0);
+
+  gcc_jit_function *test_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                  GCC_JIT_FUNCTION_EXPORTED,
+                                  void_type,
+                                  "test_fn",
+                                  0, NULL,
+                                  0);
+  gcc_jit_lvalue *iii_ptr =
+    gcc_jit_function_new_local (
+      test_fn, NULL, fn_ptr_type_iii, "iii_ptr");
+  gcc_jit_lvalue *ifi_ptr =
+    gcc_jit_function_new_local (
+      test_fn, NULL, fn_ptr_type_ifi, "ifi_ptr");
+
+  gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
+
+  /* iii_ptr = NULL; */
+  gcc_jit_block_add_assignment (
+    block, NULL,
+    iii_ptr,
+    gcc_jit_context_null (ctxt, fn_ptr_type_iii));
+  /* ifi_ptr = iii_ptr; */
+  gcc_jit_block_add_assignment (
+    block, NULL,
+    ifi_ptr,
+    gcc_jit_lvalue_as_rvalue (iii_ptr));
+  gcc_jit_block_end_with_void_return (block, NULL);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  CHECK_VALUE (result, NULL);
+
+  /* Verify that the correct error message was emitted.  */
+  CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+                     "gcc_jit_block_add_assignment:"
+                     " mismatching types:"
+                     " assignment to ifi_ptr"
+                     " (type: void (*) (int, float, int))"
+                     " from iii_ptr"
+                     " (type: void (*) (int, int, int))");
+}
+
index 2d4f01e..f96079c 100644 (file)
@@ -28,10 +28,15 @@ create_code (gcc_jit_context *ctxt, void *user_data)
         internally_called_function (a * 3, a * 4, a * 5);
      }
 
-     void (*) (int)
+     typedef void (*fn_ptr_type) (int);
+
+     fn_ptr_type
      get_test_caller (void)
      {
-       return internal_test_caller;
+       // Verify that we can assign function pointers to variables
+       fn_ptr_type p;
+       p = internal_test_caller;
+       return p;
      }
   */
   int i;
@@ -87,11 +92,11 @@ create_code (gcc_jit_context *ctxt, void *user_data)
                              3, args));
   gcc_jit_block_end_with_void_return (block, NULL);
 
-  gcc_jit_rvalue *fn_ptr
-    = gcc_jit_function_get_address (test_caller, NULL);
-
   gcc_jit_type *fn_ptr_type
-    = gcc_jit_rvalue_get_type (fn_ptr);
+    = gcc_jit_context_new_function_ptr_type (ctxt, NULL,
+                                            void_type,
+                                            1, &int_type,
+                                            0);
 
   /* Build the get_test_caller fn.  */
   gcc_jit_function *get_test_caller =
@@ -102,7 +107,21 @@ create_code (gcc_jit_context *ctxt, void *user_data)
                                  0, NULL,
                                  0);
   block = gcc_jit_function_new_block (get_test_caller, NULL);
-  gcc_jit_block_end_with_return (block, NULL, fn_ptr);
+
+  /* fn_ptr_type p; */
+  gcc_jit_lvalue *local_p
+    = gcc_jit_function_new_local (get_test_caller, NULL,
+                                 fn_ptr_type, "p");
+
+  /* p = internal_test_caller; */
+  gcc_jit_block_add_assignment (block, NULL,
+                               local_p,
+                               gcc_jit_function_get_address (test_caller,
+                                                             NULL));
+
+  /* return p; */
+  gcc_jit_block_end_with_return (block, NULL,
+                                gcc_jit_lvalue_as_rvalue (local_p));
 }
 
 static int called_with[3];