From 5a47aa2c8c36571a51552e46f3d971c107d5bf88 Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Thu, 28 Sep 2017 16:00:57 +0000 Subject: [PATCH] jit: handle equality of function pointer types 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 | 10 ++ gcc/jit/jit-recording.c | 47 ++++++++++ gcc/jit/jit-recording.h | 9 +- gcc/testsuite/ChangeLog | 10 ++ ...r-mismatching-types-in-assignment-fn-ptr.c | 92 +++++++++++++++++++ .../jit.dg/test-returning-function-ptr.c | 33 +++++-- 6 files changed, 193 insertions(+), 8 deletions(-) create mode 100644 gcc/testsuite/jit.dg/test-error-mismatching-types-in-assignment-fn-ptr.c diff --git a/gcc/jit/ChangeLog b/gcc/jit/ChangeLog index 7f14b4f706f..b5e2ed7868f 100644 --- a/gcc/jit/ChangeLog +++ b/gcc/jit/ChangeLog @@ -1,3 +1,13 @@ +2017-09-28 David Malcolm + + * 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 * docs/cp/topics/expressions.rst (Function pointers): New section. diff --git a/gcc/jit/jit-recording.c b/gcc/jit/jit-recording.c index 84812806e72..6d7dc80049b 100644 --- a/gcc/jit/jit-recording.c +++ b/gcc/jit/jit-recording.c @@ -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. */ diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h index 89181248c7f..91236455a9b 100644 --- a/gcc/jit/jit-recording.h +++ b/gcc/jit/jit-recording.h @@ -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; } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index f2a44809c79..1fff0be9db0 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,13 @@ +2017-09-28 David Malcolm + + * 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 * 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 index 00000000000..4faa3b41d5f --- /dev/null +++ b/gcc/testsuite/jit.dg/test-error-mismatching-types-in-assignment-fn-ptr.c @@ -0,0 +1,92 @@ +#include +#include + +#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))"); +} + diff --git a/gcc/testsuite/jit.dg/test-returning-function-ptr.c b/gcc/testsuite/jit.dg/test-returning-function-ptr.c index 2d4f01e2f28..f96079c45f7 100644 --- a/gcc/testsuite/jit.dg/test-returning-function-ptr.c +++ b/gcc/testsuite/jit.dg/test-returning-function-ptr.c @@ -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]; -- 2.30.2