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