[PATCH, committed] jit: New API entrypoint: gcc_jit_context_get_last_error
David Malcolm
dmalcolm@redhat.com
Thu Jan 8 21:55:00 GMT 2015
This is of use when writing bindings for higher-level languages that
support exception-handling.
An example of using this is:
https://bitbucket.org/pypy/pypy/commits/6b48e7ef126a50f0bd181f59a827244e0b3e2a00
where I use it in my experimental PyPy backend in order to raise
meaningful RPython exceptions whenever I do something bogus that leads
to a NULL back from the libgccjit API.
This makes it *much* easier to track down problems when developing
client code that uses libgccjit.
Committed to trunk as r219363.
gcc/jit/ChangeLog:
* docs/topics/contexts.rst (Error-handling): Document new
entrypoint gcc_jit_context_get_last_error.
* docs/_build/texinfo/libgccjit.texi: Regenerate.
* jit-recording.c (gcc::jit::recording::context::context):
Initialize new fields "m_last_error_str" and
"m_owns_last_error_str".
(gcc::jit::recording::context::~context): Clean up
m_last_error_str, if needed.
(gcc::jit::recording::context::add_error_va): Update
m_last_error_str and m_owns_last_error_str, freeing the old
value if appropriate.
(gcc::jit::recording::context::get_last_error): New function.
* jit-recording.h (gcc::jit::recording::context::get_last_error):
New function.
(gcc::jit::recording::context): New fields m_last_error_str and
m_owns_last_error_str.
* libgccjit.c (gcc_jit_context_get_last_error): New function.
* libgccjit.h (gcc_jit_context_get_last_error): New declaration.
* libgccjit.map (gcc_jit_context_get_last_error): New function.
gcc/testsuite/ChangeLog:
* jit.dg/test-error-block-in-wrong-function.c (verify_code):
Verify the result of gcc_jit_context_get_last_error.
* jit.dg/test-error-null-passed-to-api.c (verify_code): Likewise.
---
gcc/jit/docs/topics/contexts.rst | 18 ++++++++++++++-
gcc/jit/jit-recording.c | 27 +++++++++++++++++++---
gcc/jit/jit-recording.h | 6 +++++
gcc/jit/libgccjit.c | 14 +++++++++++
gcc/jit/libgccjit.h | 10 ++++++++
gcc/jit/libgccjit.map | 1 +
.../jit.dg/test-error-block-in-wrong-function.c | 3 +++
.../jit.dg/test-error-null-passed-to-api.c | 2 ++
8 files changed, 77 insertions(+), 4 deletions(-)
diff --git a/gcc/jit/docs/topics/contexts.rst b/gcc/jit/docs/topics/contexts.rst
index 6099c69..3dc313c 100644
--- a/gcc/jit/docs/topics/contexts.rst
+++ b/gcc/jit/docs/topics/contexts.rst
@@ -123,7 +123,9 @@ In general, if an error occurs when using an API entrypoint, the
entrypoint returns NULL. You don't have to check everywhere for NULL
results, since the API handles a NULL being passed in for any
argument by issuing another error. This typically leads to a cascade of
-followup error messages, but is safe (albeit verbose).
+followup error messages, but is safe (albeit verbose). The first error
+message is usually the one to pay attention to, since it is likely to
+be responsible for all of the rest:
.. function:: const char *\
gcc_jit_context_get_first_error (gcc_jit_context *ctxt)
@@ -135,6 +137,20 @@ followup error messages, but is safe (albeit verbose).
If no errors occurred, this will be NULL.
+If you are wrapping the C API for a higher-level language that supports
+exception-handling, you may instead by interested in the last error that
+occurred on the context, so that you can embed this in an exception:
+
+.. function:: const char *\
+ gcc_jit_context_get_last_error (gcc_jit_context *ctxt)
+
+ Returns the last 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.
+
Debugging
---------
diff --git a/gcc/jit/jit-recording.c b/gcc/jit/jit-recording.c
index a872063..a9ff300 100644
--- a/gcc/jit/jit-recording.c
+++ b/gcc/jit/jit-recording.c
@@ -175,6 +175,8 @@ recording::context::context (context *parent_ctxt)
m_error_count (0),
m_first_error_str (NULL),
m_owns_first_error_str (false),
+ m_last_error_str (NULL),
+ m_owns_last_error_str (false),
m_mementos (),
m_compound_types (),
m_functions (),
@@ -230,6 +232,10 @@ recording::context::~context ()
if (m_owns_first_error_str)
free (m_first_error_str);
+
+ if (m_owns_last_error_str)
+ if (m_last_error_str != m_first_error_str)
+ free (m_last_error_str);
}
/* Add the given mememto to the list of those tracked by this
@@ -984,9 +990,12 @@ recording::context::add_error_va (location *loc, const char *fmt, va_list ap)
m_first_error_str = const_cast <char *> (errmsg);
m_owns_first_error_str = has_ownership;
}
- else
- if (has_ownership)
- free (malloced_msg);
+
+ if (m_owns_last_error_str)
+ if (m_last_error_str != m_first_error_str)
+ free (m_last_error_str);
+ m_last_error_str = const_cast <char *> (errmsg);
+ m_owns_last_error_str = has_ownership;
m_error_count++;
}
@@ -1003,6 +1012,18 @@ recording::context::get_first_error () const
return m_first_error_str;
}
+/* Get the message for the last error that occurred on this context, or
+ NULL if no errors have occurred on it.
+
+ Implements the post-error-checking part of
+ gcc_jit_context_get_last_error. */
+
+const char *
+recording::context::get_last_error () const
+{
+ return m_last_error_str;
+}
+
/* Lazily generate and record a recording::type representing an opaque
struct named "FILE".
diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h
index dddf0db..9417993 100644
--- a/gcc/jit/jit-recording.h
+++ b/gcc/jit/jit-recording.h
@@ -235,6 +235,9 @@ public:
const char *
get_first_error () const;
+ const char *
+ get_last_error () const;
+
bool errors_occurred () const
{
if (m_parent_ctxt)
@@ -261,6 +264,9 @@ private:
char *m_first_error_str;
bool m_owns_first_error_str;
+ char *m_last_error_str;
+ bool m_owns_last_error_str;
+
char *m_str_options[GCC_JIT_NUM_STR_OPTIONS];
int m_int_options[GCC_JIT_NUM_INT_OPTIONS];
bool m_bool_options[GCC_JIT_NUM_BOOL_OPTIONS];
diff --git a/gcc/jit/libgccjit.c b/gcc/jit/libgccjit.c
index c043961..34f201e 100644
--- a/gcc/jit/libgccjit.c
+++ b/gcc/jit/libgccjit.c
@@ -2164,6 +2164,20 @@ gcc_jit_context_get_first_error (gcc_jit_context *ctxt)
/* Public entrypoint. See description in libgccjit.h.
After error-checking, the real work is done by the
+ gcc::jit::recording::context::get_last_error method in
+ jit-recording.c. */
+
+const char *
+gcc_jit_context_get_last_error (gcc_jit_context *ctxt)
+{
+ RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+
+ return ctxt->get_last_error ();
+}
+
+/* Public entrypoint. See description in libgccjit.h.
+
+ After error-checking, the real work is done by the
gcc::jit::result::get_code method in jit-result.c. */
void *
diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h
index 91ca409..953c665 100644
--- a/gcc/jit/libgccjit.h
+++ b/gcc/jit/libgccjit.h
@@ -279,6 +279,16 @@ gcc_jit_context_set_logfile (gcc_jit_context *ctxt,
extern const char *
gcc_jit_context_get_first_error (gcc_jit_context *ctxt);
+/* To be called after a compile, this gives the last 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_last_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
correct type before it can be called. */
diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map
index 267898c..dc2fa6f 100644
--- a/gcc/jit/libgccjit.map
+++ b/gcc/jit/libgccjit.map
@@ -36,6 +36,7 @@
gcc_jit_context_enable_dump;
gcc_jit_context_get_builtin_function;
gcc_jit_context_get_first_error;
+ gcc_jit_context_get_last_error;
gcc_jit_context_get_type;
gcc_jit_context_get_int_type;
gcc_jit_context_new_array_access;
diff --git a/gcc/testsuite/jit.dg/test-error-block-in-wrong-function.c b/gcc/testsuite/jit.dg/test-error-block-in-wrong-function.c
index b7342a3..285fcb0 100644
--- a/gcc/testsuite/jit.dg/test-error-block-in-wrong-function.c
+++ b/gcc/testsuite/jit.dg/test-error-block-in-wrong-function.c
@@ -62,4 +62,7 @@ verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
" source block initial is in function test_fn"
" whereas target block block_within_other_fn"
" is in function other_fn");
+ /* Example of a testcase in which the last error != first error. */
+ CHECK_STRING_VALUE (gcc_jit_context_get_last_error (ctxt),
+ "unterminated block in other_fn: block_within_other_fn");
}
diff --git a/gcc/testsuite/jit.dg/test-error-null-passed-to-api.c b/gcc/testsuite/jit.dg/test-error-null-passed-to-api.c
index ea4390b..2fab453 100644
--- a/gcc/testsuite/jit.dg/test-error-null-passed-to-api.c
+++ b/gcc/testsuite/jit.dg/test-error-null-passed-to-api.c
@@ -27,5 +27,7 @@ verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
/* 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");
+ CHECK_STRING_VALUE (gcc_jit_context_get_last_error (ctxt),
+ "gcc_jit_context_new_function: NULL return_type");
}
--
1.8.5.3
More information about the Gcc-patches
mailing list