Committed to dmalcolm/jit: Add a way to query the first error message that occurred on a context.
I expect there often will be a cascade of followup errors: the first error will often lead to a NULL return from an API call, which will then erroneously (but safely) be used for further API calls. Under such circumstances I believe the first error message will be the one that the user cares about. gcc/jit/ * internal-api.c (gcc::jit::context::add_error_va): Record the first error that occurs on a context. (gcc::jit::context::get_first_error): New. * internal-api.h (gcc::jit::context::get_first_error): New. (gcc::jit::context::m_first_error_str): New. * libgccjit.c (gcc_jit_context_get_first_error): New. * libgccjit.h (gcc_jit_context_get_first_error): New. * libgccjit.map (gcc_jit_context_get_first_error): New. gcc/testsuite/ * jit.dg/harness.h (verify_code): Add context param so that test cases of failure can query errors on it. (CHECK_STRING_VALUE): New. (check_string_value): New. (test_jit): Add user_data param and pass it to the code factory. Pass context to verify_code, calling it before releasing said context. (main): Add NULL user_data to test_jit call. * jit.dg/test-accessing-struct.c (verify_code): Add context param. * jit.dg/test-calling-external-function.c (verify_code): Likewise. * jit.dg/test-combination.c (verify_code): Likewise. * jit.dg/test-dot-product.c (verify_code): Likewise. * jit.dg/test-expressions.c (verify_code): Likewise. * jit.dg/test-factorial.c (verify_code): Likewise. * jit.dg/test-failure.c (verify_code): Likewise. * jit.dg/test-fibonacci.c (verify_code): Likewise. * jit.dg/test-hello-world.c (verify_code): Likewise. * jit.dg/test-string-literal.c (verify_code): Likewise. * jit.dg/test-sum-of-squares.c (verify_code): Likewise. * jit.dg/test-types.c (verify_code): Likewise. * jit.dg/test-using-global.c (verify_code): Likewise. * jit.dg/test-null-passed-to-api.c (verify_code): Likewise; use context to verify that the library provides a sane error message to the client code. --- gcc/jit/ChangeLog.jit | 11 ++++++ gcc/jit/internal-api.c | 16 ++++++++ gcc/jit/internal-api.h | 6 ++- gcc/jit/libgccjit.c | 8 ++++ gcc/jit/libgccjit.h | 9 +++++ gcc/jit/libgccjit.map | 1 + gcc/testsuite/ChangeLog.jit | 29 ++++++++++++++ gcc/testsuite/jit.dg/harness.h | 45 ++++++++++++++++++---- gcc/testsuite/jit.dg/test-accessing-struct.c | 2 +- .../jit.dg/test-calling-external-function.c | 2 +- gcc/testsuite/jit.dg/test-combination.c | 24 ++++++------ gcc/testsuite/jit.dg/test-dot-product.c | 2 +- gcc/testsuite/jit.dg/test-expressions.c | 2 +- gcc/testsuite/jit.dg/test-factorial.c | 2 +- gcc/testsuite/jit.dg/test-failure.c | 2 +- gcc/testsuite/jit.dg/test-fibonacci.c | 2 +- gcc/testsuite/jit.dg/test-hello-world.c | 2 +- gcc/testsuite/jit.dg/test-null-passed-to-api.c | 6 ++- gcc/testsuite/jit.dg/test-string-literal.c | 2 +- gcc/testsuite/jit.dg/test-sum-of-squares.c | 2 +- gcc/testsuite/jit.dg/test-types.c | 2 +- gcc/testsuite/jit.dg/test-using-global.c | 2 +- 22 files changed, 146 insertions(+), 33 deletions(-) diff --git a/gcc/jit/ChangeLog.jit b/gcc/jit/ChangeLog.jit index 2cf5c8d..5e8d0f9 100644 --- a/gcc/jit/ChangeLog.jit +++ b/gcc/jit/ChangeLog.jit @@ -1,3 +1,14 @@ +2013-10-22 David Malcolm <dmalc...@redhat.com> + + * internal-api.c (gcc::jit::context::add_error_va): Record the + first error that occurs on a context. + (gcc::jit::context::get_first_error): New. + * internal-api.h (gcc::jit::context::get_first_error): New. + (gcc::jit::context::m_first_error_str): New. + * libgccjit.c (gcc_jit_context_get_first_error): New. + * libgccjit.h (gcc_jit_context_get_first_error): New. + * libgccjit.map (gcc_jit_context_get_first_error): New. + 2013-10-21 David Malcolm <dmalc...@redhat.com> * internal-api.c (gcc::jit::context::compile): Correctly cleanup diff --git a/gcc/jit/internal-api.c b/gcc/jit/internal-api.c index d90f001..639cd49 100644 --- a/gcc/jit/internal-api.c +++ b/gcc/jit/internal-api.c @@ -1478,9 +1478,25 @@ add_error_va (const char *fmt, va_list ap) error ("%s\n", buf); + if (!m_error_count) + { + strncpy (m_first_error_str, buf, sizeof(m_first_error_str)); + m_first_error_str[sizeof(m_first_error_str) - 1] = '\0'; + } + m_error_count++; } +const char * +gcc::jit::context:: +get_first_error () const +{ + if (m_error_count) + return m_first_error_str; + else + return NULL; +} + gcc::jit::result:: result(void *dso_handle) : m_dso_handle(dso_handle) diff --git a/gcc/jit/internal-api.h b/gcc/jit/internal-api.h index 1a8499f..01f0bb3 100644 --- a/gcc/jit/internal-api.h +++ b/gcc/jit/internal-api.h @@ -158,6 +158,9 @@ public: add_error_va (const char *fmt, va_list ap) GNU_PRINTF(2, 0); + const char * + get_first_error () const; + void set_tree_location (tree t, location *loc); @@ -193,6 +196,8 @@ private: void *m_user_data; int m_error_count; + char m_first_error_str[1024]; + int m_cb_result; /* Result from client-provided code factory. */ /* Allocated using xmalloc (by xstrdup). */ char *m_path_template; @@ -205,7 +210,6 @@ private: char *m_path_s_file; char *m_path_so_file; - int m_cb_result; /* Result from client-provided code factory. */ vec<function *> m_functions; const char *m_str_options[GCC_JIT_NUM_STR_OPTIONS]; int m_int_options[GCC_JIT_NUM_INT_OPTIONS]; diff --git a/gcc/jit/libgccjit.c b/gcc/jit/libgccjit.c index 40ac98d..3222144 100644 --- a/gcc/jit/libgccjit.c +++ b/gcc/jit/libgccjit.c @@ -726,6 +726,14 @@ gcc_jit_context_compile (gcc_jit_context *ctxt) return (gcc_jit_result *)ctxt->compile (); } +const char * +gcc_jit_context_get_first_error (gcc_jit_context *ctxt) +{ + RETURN_NULL_IF_FAIL (ctxt, NULL, "NULL context"); + + return ctxt->get_first_error (); +} + void * gcc_jit_result_get_code (gcc_jit_result *result, const char *fnname) diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h index 12a715d..f058162 100644 --- a/gcc/jit/libgccjit.h +++ b/gcc/jit/libgccjit.h @@ -216,6 +216,15 @@ gcc_jit_context_set_bool_option (gcc_jit_context *ctxt, extern gcc_jit_result * gcc_jit_context_compile (gcc_jit_context *ctxt); +/* To be called after a compile, this gives the first error message + that occurred on the context. + + The returned string is valid for the rest of the lifetime of the + context. + + If no errors occurred, this will be NULL. */ +extern const char * +gcc_jit_context_get_first_error (gcc_jit_context *ctxt); /* Locate a given function within the built machine code. This will need to be cast to a function pointer of the diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map index e2503e4..aaa2112 100644 --- a/gcc/jit/libgccjit.map +++ b/gcc/jit/libgccjit.map @@ -4,6 +4,7 @@ # Keep this list sorted alphabetically: gcc_jit_context_acquire; gcc_jit_context_compile; + gcc_jit_context_get_first_error; gcc_jit_context_get_type; gcc_jit_context_new_array_lookup; gcc_jit_context_new_binary_op; diff --git a/gcc/testsuite/ChangeLog.jit b/gcc/testsuite/ChangeLog.jit index 7190e09..0476507 100644 --- a/gcc/testsuite/ChangeLog.jit +++ b/gcc/testsuite/ChangeLog.jit @@ -1,3 +1,32 @@ +2013-10-22 David Malcolm <dmalc...@redhat.com> + + * jit.dg/harness.h (verify_code): Add context param so that + test cases of failure can query errors on it. + (CHECK_STRING_VALUE): New. + (check_string_value): New. + (test_jit): Add user_data param and pass it to the code factory. + Pass context to verify_code, calling it before releasing said + context. + (main): Add NULL user_data to test_jit call. + * jit.dg/test-accessing-struct.c (verify_code): Add context + param. + * jit.dg/test-calling-external-function.c (verify_code): + Likewise. + * jit.dg/test-combination.c (verify_code): Likewise. + * jit.dg/test-dot-product.c (verify_code): Likewise. + * jit.dg/test-expressions.c (verify_code): Likewise. + * jit.dg/test-factorial.c (verify_code): Likewise. + * jit.dg/test-failure.c (verify_code): Likewise. + * jit.dg/test-fibonacci.c (verify_code): Likewise. + * jit.dg/test-hello-world.c (verify_code): Likewise. + * jit.dg/test-string-literal.c (verify_code): Likewise. + * jit.dg/test-sum-of-squares.c (verify_code): Likewise. + * jit.dg/test-types.c (verify_code): Likewise. + * jit.dg/test-using-global.c (verify_code): Likewise. + * jit.dg/test-null-passed-to-api.c (verify_code): Likewise; + use context to verify that the library provides a sane error + message to the client code. + 2013-10-21 David Malcolm <dmalc...@redhat.com> * jit.dg/test-expressions.c (test_global): New. diff --git a/gcc/testsuite/jit.dg/harness.h b/gcc/testsuite/jit.dg/harness.h index 4ffbcbf..8e75924 100644 --- a/gcc/testsuite/jit.dg/harness.h +++ b/gcc/testsuite/jit.dg/harness.h @@ -8,7 +8,7 @@ code_making_callback (gcc_jit_context *ctxt, void * user_data); extern void - verify_code (gcc_jit_result *result); + verify_code (gcc_jit_context *ctxt, gcc_jit_result *result); */ #include <stdlib.h> @@ -47,12 +47,15 @@ static char test[1024]; } \ } while (0) +#define CHECK_STRING_VALUE(ACTUAL, EXPECTED) \ + check_string_value ((ACTUAL), (EXPECTED)); + /* Hooks that testcases should provide. */ extern int code_making_callback (gcc_jit_context *ctxt, void * user_data); extern void -verify_code (gcc_jit_result *result); +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result); /* Implement framework needed for turning the testcase hooks into an executable. test-combination.c combines multiple testcases into one @@ -60,9 +63,37 @@ verify_code (gcc_jit_result *result); off this part of harness.h. */ #ifndef TEST_COMBINATION +void check_string_value (const char *actual, const char *expected) +{ + if (actual && !expected) + { + fail ("%s: actual: \"%s\" != expected: NULL", test, actual); + fprintf (stderr, "incorrect value\n"); + abort (); + } + if (expected && !actual) + { + fail ("%s: actual: NULL != expected: \"%s\"", test, expected); + fprintf (stderr, "incorrect value\n"); + abort (); + } + if (actual && expected) + { + if (strcmp (actual, expected)) + { + fail ("%s: actual: \"%s\" != expected: \"%s\"", test, actual, expected); + fprintf (stderr, "incorrect valuen"); + abort (); + } + pass ("%s: actual: \"%s\" == expected: \"%s\"", test, actual, expected); + } + else + pass ("%s: actual: NULL == expected: NULL"); +} + /* Run one iteration of the test. */ static void -test_jit (const char *argv0) +test_jit (const char *argv0, void *user_data) { gcc_jit_context *ctxt; gcc_jit_result *result; @@ -70,7 +101,7 @@ test_jit (const char *argv0) ctxt = gcc_jit_context_acquire (); /* FIXME: error-handling */ - gcc_jit_context_set_code_factory (ctxt, code_making_callback, NULL); + gcc_jit_context_set_code_factory (ctxt, code_making_callback, user_data); /* Set up options. */ gcc_jit_context_set_str_option ( @@ -106,9 +137,9 @@ test_jit (const char *argv0) in a mutex for now. */ result = gcc_jit_context_compile (ctxt); - gcc_jit_context_release (ctxt); + verify_code (ctxt, result); - verify_code (result); + gcc_jit_context_release (ctxt); /* Once we're done with the code, this unloads the built .so file: */ gcc_jit_result_release (result); @@ -144,7 +175,7 @@ main (int argc, char **argv) i, 5); //printf ("ITERATION %d\n", i); - test_jit (argv[0]); + test_jit (argv[0], NULL); //printf ("\n"); } diff --git a/gcc/testsuite/jit.dg/test-accessing-struct.c b/gcc/testsuite/jit.dg/test-accessing-struct.c index 4e197c5..46c6f5b 100644 --- a/gcc/testsuite/jit.dg/test-accessing-struct.c +++ b/gcc/testsuite/jit.dg/test-accessing-struct.c @@ -88,7 +88,7 @@ code_making_callback (gcc_jit_context *ctxt, void *user_data) } void -verify_code (gcc_jit_result *result) +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) { typedef void (*fn_type) (struct foo *); CHECK_NON_NULL (result); diff --git a/gcc/testsuite/jit.dg/test-calling-external-function.c b/gcc/testsuite/jit.dg/test-calling-external-function.c index 6e5dd7d..bfc0641 100644 --- a/gcc/testsuite/jit.dg/test-calling-external-function.c +++ b/gcc/testsuite/jit.dg/test-calling-external-function.c @@ -95,7 +95,7 @@ called_function (int i, int j, int k) } void -verify_code (gcc_jit_result *result) +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) { typedef void (*fn_type) (int); CHECK_NON_NULL (result); diff --git a/gcc/testsuite/jit.dg/test-combination.c b/gcc/testsuite/jit.dg/test-combination.c index 3338d94..00fbee6 100644 --- a/gcc/testsuite/jit.dg/test-combination.c +++ b/gcc/testsuite/jit.dg/test-combination.c @@ -115,17 +115,17 @@ code_making_callback (gcc_jit_context *ctxt, void * user_data) } void -verify_code (gcc_jit_result *result) +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) { - verify_code_accessing_struct (result); - verify_code_calling_external_function (result); - verify_code_dot_product (result); - verify_code_expressions (result); - verify_code_factorial (result); - verify_code_fibonacci (result); - verify_code_hello_world (result); - verify_code_string_literal (result); - verify_code_sum_of_squares (result); - verify_code_types (result); - verify_code_using_global (result); + verify_code_accessing_struct (ctxt, result); + verify_code_calling_external_function (ctxt, result); + verify_code_dot_product (ctxt, result); + verify_code_expressions (ctxt, result); + verify_code_factorial (ctxt, result); + verify_code_fibonacci (ctxt, result); + verify_code_hello_world (ctxt, result); + verify_code_string_literal (ctxt, result); + verify_code_sum_of_squares (ctxt, result); + verify_code_types (ctxt, result); + verify_code_using_global (ctxt, result); } diff --git a/gcc/testsuite/jit.dg/test-dot-product.c b/gcc/testsuite/jit.dg/test-dot-product.c index 3a8a59a..dffccae 100644 --- a/gcc/testsuite/jit.dg/test-dot-product.c +++ b/gcc/testsuite/jit.dg/test-dot-product.c @@ -99,7 +99,7 @@ code_making_callback (gcc_jit_context *ctxt, void *user_data) } void -verify_code (gcc_jit_result *result) +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) { typedef double (*my_dot_product_fn_type) (int n, double *a, double *b); CHECK_NON_NULL (result); diff --git a/gcc/testsuite/jit.dg/test-expressions.c b/gcc/testsuite/jit.dg/test-expressions.c index aaaf394..c270082 100644 --- a/gcc/testsuite/jit.dg/test-expressions.c +++ b/gcc/testsuite/jit.dg/test-expressions.c @@ -560,7 +560,7 @@ code_making_callback (gcc_jit_context *ctxt, void *user_data) } void -verify_code (gcc_jit_result *result) +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) { CHECK_NON_NULL (result); diff --git a/gcc/testsuite/jit.dg/test-factorial.c b/gcc/testsuite/jit.dg/test-factorial.c index 5c3b237..758cd2d 100644 --- a/gcc/testsuite/jit.dg/test-factorial.c +++ b/gcc/testsuite/jit.dg/test-factorial.c @@ -92,7 +92,7 @@ code_making_callback (gcc_jit_context *ctxt, void *user_data) } void -verify_code (gcc_jit_result *result) +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) { typedef int (*my_factorial_fn_type) (int); CHECK_NON_NULL (result); diff --git a/gcc/testsuite/jit.dg/test-failure.c b/gcc/testsuite/jit.dg/test-failure.c index ac31964..4a7b788 100644 --- a/gcc/testsuite/jit.dg/test-failure.c +++ b/gcc/testsuite/jit.dg/test-failure.c @@ -12,7 +12,7 @@ code_making_callback (gcc_jit_context *ctxt, void *user_data) } void -verify_code (gcc_jit_result *result) +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) { CHECK_VALUE (result, NULL); } diff --git a/gcc/testsuite/jit.dg/test-fibonacci.c b/gcc/testsuite/jit.dg/test-fibonacci.c index 16d8a46..23903fa 100644 --- a/gcc/testsuite/jit.dg/test-fibonacci.c +++ b/gcc/testsuite/jit.dg/test-fibonacci.c @@ -132,7 +132,7 @@ FIRST_LINE + 7: } } void -verify_code (gcc_jit_result *result) +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) { typedef int (*my_fibonacci_fn_type) (int); CHECK_NON_NULL (result); diff --git a/gcc/testsuite/jit.dg/test-hello-world.c b/gcc/testsuite/jit.dg/test-hello-world.c index 0e3af81..1c18ce1b 100644 --- a/gcc/testsuite/jit.dg/test-hello-world.c +++ b/gcc/testsuite/jit.dg/test-hello-world.c @@ -53,7 +53,7 @@ code_making_callback (gcc_jit_context *ctxt, void *user_data) } extern void -verify_code (gcc_jit_result *result) +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) { typedef void (*fn_type) (const char *); CHECK_NON_NULL (result); diff --git a/gcc/testsuite/jit.dg/test-null-passed-to-api.c b/gcc/testsuite/jit.dg/test-null-passed-to-api.c index 245fde0..1e9d89c 100644 --- a/gcc/testsuite/jit.dg/test-null-passed-to-api.c +++ b/gcc/testsuite/jit.dg/test-null-passed-to-api.c @@ -21,10 +21,14 @@ code_making_callback (gcc_jit_context *ctxt, void *user_data) } void -verify_code (gcc_jit_result *result) +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) { /* Ensure that the bad API usage prevents the API giving a bogus result back. */ 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_function: NULL return_type"); } diff --git a/gcc/testsuite/jit.dg/test-string-literal.c b/gcc/testsuite/jit.dg/test-string-literal.c index cd373ad..b9ba895 100644 --- a/gcc/testsuite/jit.dg/test-string-literal.c +++ b/gcc/testsuite/jit.dg/test-string-literal.c @@ -37,7 +37,7 @@ code_making_callback (gcc_jit_context *ctxt, void *user_data) } void -verify_code (gcc_jit_result *result) +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) { typedef const char *(*fn_type) (void); CHECK_NON_NULL (result); diff --git a/gcc/testsuite/jit.dg/test-sum-of-squares.c b/gcc/testsuite/jit.dg/test-sum-of-squares.c index 48ac93f..934d58d 100644 --- a/gcc/testsuite/jit.dg/test-sum-of-squares.c +++ b/gcc/testsuite/jit.dg/test-sum-of-squares.c @@ -119,7 +119,7 @@ code_making_callback (gcc_jit_context *ctxt, void *user_data) } void -verify_code (gcc_jit_result *result) +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) { typedef int (*loop_test_fn_type) (int); CHECK_NON_NULL (result); diff --git a/gcc/testsuite/jit.dg/test-types.c b/gcc/testsuite/jit.dg/test-types.c index 819c40a..e4a042e 100644 --- a/gcc/testsuite/jit.dg/test-types.c +++ b/gcc/testsuite/jit.dg/test-types.c @@ -241,7 +241,7 @@ code_making_callback (gcc_jit_context *ctxt, void *user_data) } void -verify_code (gcc_jit_result *result) +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) { typedef void (*fn_type) (struct zoo *); CHECK_NON_NULL (result); diff --git a/gcc/testsuite/jit.dg/test-using-global.c b/gcc/testsuite/jit.dg/test-using-global.c index 8eabc31..f9390f8 100644 --- a/gcc/testsuite/jit.dg/test-using-global.c +++ b/gcc/testsuite/jit.dg/test-using-global.c @@ -53,7 +53,7 @@ code_making_callback (gcc_jit_context *ctxt, void *user_data) int the_global; void -verify_code (gcc_jit_result *result) +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) { typedef void (*fn_type) (void); CHECK_NON_NULL (result); -- 1.7.11.7