Committed to branch dmalcolm/jit: gcc/jit/ * internal-api.c (gcc::jit::recording::type::get_pointer): Ensure that repeated calls yield the same type. (gcc::jit::recording::memento_of_get_pointer:: accepts_writes_from): New. (gcc::jit::recording::context::new_call): Move the existing argument checking to...
* libgccjit.c (gcc_jit_context_new_call): ...here, and add checking of the types of the arguments against the function. (RETURN_VAL_IF_FAIL_PRINTF6): New. (RETURN_NULL_IF_FAIL_PRINTF6): New. * internal-api.h (gcc::jit::recording::type): New field m_pointer_to_this_type, for use by get_pointer method. (gcc::jit::recording::memento_of_get_pointer:: accepts_writes_from): New. (gcc::jit::recording::function::get_param): New. * TODO.rst (argument checking of gcc_jit_context_new_call): Done. gcc/testsuite/ * jit.dg/test-error-call-with-mismatching-args.c: New test case. --- gcc/jit/ChangeLog.jit | 22 ++++++ gcc/jit/TODO.rst | 2 - gcc/jit/internal-api.c | 37 ++++------ gcc/jit/internal-api.h | 9 ++- gcc/jit/libgccjit.c | 51 +++++++++++++ gcc/testsuite/ChangeLog.jit | 4 + .../jit.dg/test-error-call-with-mismatching-args.c | 85 ++++++++++++++++++++++ 7 files changed, 184 insertions(+), 26 deletions(-) create mode 100644 gcc/testsuite/jit.dg/test-error-call-with-mismatching-args.c diff --git a/gcc/jit/ChangeLog.jit b/gcc/jit/ChangeLog.jit index de92fbe..58e82eb 100644 --- a/gcc/jit/ChangeLog.jit +++ b/gcc/jit/ChangeLog.jit @@ -1,5 +1,27 @@ 2014-01-30 David Malcolm <dmalc...@redhat.com> + * internal-api.c (gcc::jit::recording::type::get_pointer): + Ensure that repeated calls yield the same type. + (gcc::jit::recording::memento_of_get_pointer:: + accepts_writes_from): New. + (gcc::jit::recording::context::new_call): Move + the existing argument checking to... + + * libgccjit.c (gcc_jit_context_new_call): ...here, and add + checking of the types of the arguments against the function. + (RETURN_VAL_IF_FAIL_PRINTF6): New. + (RETURN_NULL_IF_FAIL_PRINTF6): New. + + * internal-api.h (gcc::jit::recording::type): New field + m_pointer_to_this_type, for use by get_pointer method. + (gcc::jit::recording::memento_of_get_pointer:: + accepts_writes_from): New. + (gcc::jit::recording::function::get_param): New. + + * TODO.rst (argument checking of gcc_jit_context_new_call): Done. + +2014-01-30 David Malcolm <dmalc...@redhat.com> + * TODO.rst: begin a list of error-checking we could do that this commit *doesn't* cover. diff --git a/gcc/jit/TODO.rst b/gcc/jit/TODO.rst index 79b4efa..4f16ae4 100644 --- a/gcc/jit/TODO.rst +++ b/gcc/jit/TODO.rst @@ -118,8 +118,6 @@ Initial Release * gcc_jit_context_new_comparison: must be numeric or pointer types - * gcc_jit_context_new_call: check the types of the args - * gcc_jit_context_new_array_lookup: "ptr" must be of pointer type; "index" must be of numeric type. diff --git a/gcc/jit/internal-api.c b/gcc/jit/internal-api.c index 5e72e62..58495ac 100644 --- a/gcc/jit/internal-api.c +++ b/gcc/jit/internal-api.c @@ -355,26 +355,6 @@ recording::context::new_call (recording::location *loc, function *func, int numargs , recording::rvalue **args) { - int min_num_params = func->get_params ().length (); - bool is_variadic = func->is_variadic (); - if (numargs < min_num_params) - { - add_error (("gcc_jit_context_new_call: " - "not enough arguments to function \"%s\"" - " (got %i args, expected %i)"), - func->get_name ()->c_str (), - numargs, min_num_params); - return NULL; - } - if (numargs > min_num_params && !is_variadic) - { - add_error (("gcc_jit_context_new_call: " - "too many arguments to function \"%s\"" - " (got %i args, expected %i)"), - func->get_name ()->c_str (), - numargs, min_num_params); - return NULL; - } recording::rvalue *result = new call (this, loc, func, numargs, args); record (result); return result; @@ -590,9 +570,12 @@ recording::location::make_debug_string () recording::type * recording::type::get_pointer () { - recording::type *result = new memento_of_get_pointer (this); - m_ctxt->record (result); - return result; + if (!m_pointer_to_this_type) + { + m_pointer_to_this_type = new memento_of_get_pointer (this); + m_ctxt->record (m_pointer_to_this_type); + } + return m_pointer_to_this_type; } recording::type * @@ -692,6 +675,14 @@ recording::memento_of_get_type::make_debug_string () } /* gcc::jit::recording::memento_of_get_pointer:: */ +bool +recording::memento_of_get_pointer::accepts_writes_from (type *rtype) +{ + /* It's OK to assign to a (const T *) from a (T *). */ + return m_other_type->unqualified () + ->accepts_writes_from (rtype->dereference ()); +} + void recording::memento_of_get_pointer::replay_into (replayer *) { diff --git a/gcc/jit/internal-api.h b/gcc/jit/internal-api.h index a2848a8..fce6927 100644 --- a/gcc/jit/internal-api.h +++ b/gcc/jit/internal-api.h @@ -408,8 +408,12 @@ public: protected: type (context *ctxt) - : memento (ctxt) {} + : memento (ctxt), + m_pointer_to_this_type (NULL) + {} +private: + type *m_pointer_to_this_type; }; /* Result of "gcc_jit_type_get_type". */ @@ -456,6 +460,8 @@ public: type *dereference () { return m_other_type; } + bool accepts_writes_from (type *rtype); + void replay_into (replayer *r); private: @@ -718,6 +724,7 @@ public: type *get_return_type () const { return m_return_type; } string * get_name () const { return m_name; } vec<param *> get_params () const { return m_params; } + param *get_param (int i) const { return m_params[i]; } bool is_variadic () const { return m_is_variadic; } private: diff --git a/gcc/jit/libgccjit.c b/gcc/jit/libgccjit.c index 58037e1..345f74b 100644 --- a/gcc/jit/libgccjit.c +++ b/gcc/jit/libgccjit.c @@ -96,6 +96,16 @@ struct gcc_jit_loop : public gcc::jit::recording::loop } \ JIT_END_STMT +#define RETURN_VAL_IF_FAIL_PRINTF6(TEST_EXPR, RETURN_EXPR, CTXT, ERR_FMT, A0, A1, A2, A3, A4, A5) \ + JIT_BEGIN_STMT \ + if (!(TEST_EXPR)) \ + { \ + jit_error ((CTXT), "%s: " ERR_FMT, \ + __func__, (A0), (A1), (A2), (A3), (A4), (A5)); \ + return (RETURN_EXPR); \ + } \ + JIT_END_STMT + #define RETURN_NULL_IF_FAIL(TEST_EXPR, CTXT, ERR_MSG) \ RETURN_VAL_IF_FAIL ((TEST_EXPR), NULL, (CTXT), (ERR_MSG)) @@ -105,6 +115,9 @@ struct gcc_jit_loop : public gcc::jit::recording::loop #define RETURN_NULL_IF_FAIL_PRINTF3(TEST_EXPR, CTXT, ERR_FMT, A0, A1, A2) \ RETURN_VAL_IF_FAIL_PRINTF3 (TEST_EXPR, NULL, CTXT, ERR_FMT, A0, A1, A2) +#define RETURN_NULL_IF_FAIL_PRINTF6(TEST_EXPR, CTXT, ERR_FMT, A0, A1, A2, A3, A4, A5) \ + RETURN_VAL_IF_FAIL_PRINTF6 (TEST_EXPR, NULL, CTXT, ERR_FMT, A0, A1, A2, A3, A4, A5) + #define RETURN_IF_FAIL(TEST_EXPR, CTXT, ERR_MSG) \ JIT_BEGIN_STMT \ if (!(TEST_EXPR)) \ @@ -476,6 +489,44 @@ gcc_jit_context_new_call (gcc_jit_context *ctxt, if (numargs) RETURN_NULL_IF_FAIL (args, ctxt, "NULL args"); + int min_num_params = func->get_params ().length (); + bool is_variadic = func->is_variadic (); + + RETURN_NULL_IF_FAIL_PRINTF3 ( + numargs >= min_num_params, + ctxt, + "not enough arguments to function \"%s\"" + " (got %i args, expected %i)", + func->get_name ()->c_str (), + numargs, min_num_params); + + RETURN_NULL_IF_FAIL_PRINTF3 ( + (numargs == min_num_params || is_variadic), + ctxt, + "too many arguments to function \"%s\"" + " (got %i args, expected %i)", + func->get_name ()->c_str (), + numargs, min_num_params); + + for (int i = 0; i < min_num_params; i++) + { + gcc::jit::recording::param *param = func->get_param (i); + gcc_jit_rvalue *arg = args[i]; + + RETURN_NULL_IF_FAIL_PRINTF6 ( + compatible_types (param->get_type (), + arg->get_type ()), + ctxt, + "mismatching types for argument %d of function \"%s\":" + " assignment to param %s (type: %s) from %s (type: %s)", + i + 1, + func->get_name ()->c_str (), + param->get_debug_string (), + param->get_type ()->get_debug_string (), + arg->get_debug_string (), + arg->get_type ()->get_debug_string ()); + } + return (gcc_jit_rvalue *)ctxt->new_call (loc, func, numargs, diff --git a/gcc/testsuite/ChangeLog.jit b/gcc/testsuite/ChangeLog.jit index bd20f8c..b1ab250 100644 --- a/gcc/testsuite/ChangeLog.jit +++ b/gcc/testsuite/ChangeLog.jit @@ -1,5 +1,9 @@ 2014-01-30 David Malcolm <dmalc...@redhat.com> + * jit.dg/test-error-call-with-mismatching-args.c: New test case. + +2014-01-30 David Malcolm <dmalc...@redhat.com> + * jit.dg/test-error-accessing-field-in-other-struct.c: New test case. * jit.dg/test-error-dereference-field-of-non-pointer.c: Likewise. diff --git a/gcc/testsuite/jit.dg/test-error-call-with-mismatching-args.c b/gcc/testsuite/jit.dg/test-error-call-with-mismatching-args.c new file mode 100644 index 0000000..4f0b105 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-error-call-with-mismatching-args.c @@ -0,0 +1,85 @@ +#include <stdlib.h> +#include <stdio.h> + +#include "libgccjit.h" + +#include "harness.h" + +#ifdef __cplusplus +extern "C" { +#endif + + extern void + called_function (void *ptr); + +#ifdef __cplusplus +} +#endif + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Let's try to inject the equivalent of: + extern void called_function (void *ptr); + + void + test_fn () + { + called_function (42); + } + + and verify that the API complains about the mismatching argument + type ("int" vs "void *"). */ + gcc_jit_type *void_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID); + gcc_jit_type *void_ptr_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID_PTR); + gcc_jit_type *int_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + + /* Declare the imported function. */ + gcc_jit_param *param = + gcc_jit_context_new_param (ctxt, NULL, void_ptr_type, "ptr"); + gcc_jit_function *called_fn = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_IMPORTED, + void_type, + "called_function", + 1, ¶m, + 0); + + /* Build the test_fn. */ + gcc_jit_function *test_fn = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + void_type, + "test_fn", + 0, NULL, + 0); + /* called_function (42); */ + gcc_jit_rvalue *arg = + gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 42); + + gcc_jit_function_add_eval ( + test_fn, NULL, + gcc_jit_context_new_call (ctxt, + NULL, + called_fn, + 1, &arg)); + /* the above has the wrong type for argument 1. */ +} + +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_context_new_call:" + " mismatching types for argument 1" + " of function \"called_function\":" + " assignment to param ptr (type: void *)" + " from (int)42 (type: int)")); +} + -- 1.7.11.7