[jit] Add type-checking and strings to help with debugging

David Malcolm dmalcolm@redhat.com
Thu Jan 30 16:59:00 GMT 2014


Committed to branch dmalcolm/jit:

Writing a JIT-compiler is fiddly, and the developer is likely to make
mistakes along the way.

As noted in 994cf9d5f311ff1633e0a9a267cfe6ad60247de3, there was almost no
type-checking within libgccjit - if client code uses the API in such a
way as to request the generation of bogus code, this was likely to violate
assumptions made later on within GCC proper, leading to errors deep inside
GCC e.g. with "internal compiler error", or segmentation faults.

The API will be more developer-friendly if we catch such type errors
at the API boundary (similar to how the other language frontends enforce
these assumptions).

In addition, we should issue good error messages if the client code
misuses the API, so the developer can more easily track down the issues.

The following commit adds type-checking to parts of the API, together
with a way of generating string dumps of the API entities on demand.

The gcc_jit_rvalue type (aka recording::rvalue internally) gains a
type attribute, which is checked at the API boundary in various places
(though this is a work-in-progress: see the TODO.rst file).

In order to generate suitably-descriptive error messages, we need
to be able to "stringify" the entities exposed by the API.

Hence in this commit the various memento objects (such as rvalues, types,
functions, etc) gain an optional m_debug_string attribute.  This string is
non-trivial to generate, via a virtual function call which can lead to
further calls to walk the internal tree of mementos.  Hence it's
lazily generated, and only when an error occurs (or if you want to do
detailed debug logging).  The debug strings are contextual objects, and
hence live for the lifetime of the underlying context.

As an extra quality-of-life benefit, this means that when debugging
libgccjit you can request a stringification of a recording object (although
irritatingly, for some reason on this box when within libgccjit.c I
currently need to cast to the base class to get the debugger to recognize
the method).

For example, when debugging test-quadratic.c:

  (gdb) p ((gcc::jit::recording::memento *)lvalue)->get_debug_string()
  $8 = 0x6a0a70 "q->discriminant"
  (gdb) p ((gcc::jit::recording::memento *)rvalue)->get_debug_string()
  $9 = 0x669b50 "q->b * q->b - (double)4 * q->a * q->c"

With this commit, test-fuzzer.c now runs to completion on this box (albeit
with only 6 of the 200 attempts successfully completing compilation, mostly
due to the randomly-generated code attempting assignments that violate
the type rules).

gcc/jit/

	* TODO.rst: begin a list of error-checking we could do that this
	commit *doesn't* cover.

	* libgccjit.h (gcc_jit_field): Add note that fields can't be
	shared between structs.
	(GCC_JIT_BINARY_OP_MODULO): Fix typo in comment.

	* libgccjit.c: (RETURN_VAL_IF_FAIL_PRINTF2): New.
	(RETURN_VAL_IF_FAIL_PRINTF3): New.
	(RETURN_NULL_IF_FAIL_PRINTF2): New.
	(RETURN_NULL_IF_FAIL_PRINTF3): New.
	(RETURN_IF_FAIL_PRINTF4): New.

	(jit_error): Take a gcc::jit::recording::context rather than
	a gcc_jit_context so that we pass in contexts from the inner
	layer.

	(compatible_types): New, for use in type-checking.

	(gcc_jit_context_new_struct_type): Check each field to ensure that
	it isn't already in use by another struct.

	(gcc_jit_rvalue_dereference_field): Check that ptr is of a pointer
	type and that the field is within the correct struct, using new
	get_debug_string hooks to generate error messages.

	(gcc_jit_rvalue_dereference): Check that rvalue is of a pointer
	type.

	(gcc_jit_function_add_assignment): Use the function's context when
	reporting on NULL lvalue or rvalue.  Verify that the lvalue and
	rvalue have compatible types.

	(gcc_jit_function_add_return): Use the function's context when
	reporting on NULL rvalue.  Verify that the rvalue is of an
	appropriate type given the function's return type.

	* internal-api.h (NUM_GCC_JIT_TYPES): New.
	(gcc::jit::recording::context::record): Move from here to
	internal-api.c.
	(gcc::jit::recording::context::get_opaque_FILE_type): New.
	(gcc::jit::recording::context::m_basic_types): New field.
	(gcc::jit::recording::context::m_FILE_type): New field.

	(gcc::jit::recording::memento::get_debug_string): New method.
	(gcc::jit::recording::memento::memento): Initialize new field
	m_debug_string, and verify context is non-NULL.
	(gcc::jit::recording::memento::make_debug_string): New
	pure-virtual function lazily used by get_debug_string.
	(gcc::jit::recording::memento::m_debug_string): New field, for
	get_debug_string to use as a cache.

	(gcc::jit::recording::string): Rename field m_copy to m_buffer.
	(gcc::jit::recording::from_printf): New factory function.
	(gcc::jit::recording::make_debug_string): New.

	(gcc::jit::recording::location::make_debug_string): New.

	(gcc::jit::recording::type::dereference): New pure-virtual
	function.
	(gcc::jit::recording::type::accepts_writes_from): New virtual
	function.
	(gcc::jit::recording::type::unqualified): New virtual function.

	(gcc::jit::recording::memento_of_get_type::dereference): New.
	(gcc::jit::recording::memento_of_get_type::
	accepts_writes_from): New.
	(gcc::jit::recording::memento_of_get_type::make_debug_string):
	New.

	(gcc::jit::recording::memento_of_get_pointer::make_debug_string):
	New.
	(gcc::jit::recording::memento_of_get_pointer::dereference): New.
	New.

	(gcc::jit::recording::memento_of_get_const::make_debug_string):
	New.
	(gcc::jit::recording::memento_of_get_const::dereference): New.
	New.
	(gcc::jit::recording::memento_of_get_const::accepts_writes_from):
	New.
	(gcc::jit::recording::memento_of_get_const::unqualified): New.

	(gcc::jit::recording::field): New field m_container, for the
	containing struct (or union, if we implement that).
	(gcc::jit::recording::field::get_type): New.
	(gcc::jit::recording::field::get_container): New.
	(gcc::jit::recording::field:set_container): New.
	(gcc::jit::recording::field::make_debug_string): New.

	(gcc::jit::recording::struct_::struct_): Move ctor implementation
	from here into internal-api.c.
	(gcc::jit::recording::struct_::dereference): New.
	(gcc::jit::recording::struct_::make_debug_string): New.

	(gcc::jit::recording::rvalue::m_type): New field.
	(gcc::jit::recording::rvalue::rvalue): Require a non-NULL type for
	new rvalue instances.
	(gcc::jit::recording::rvalue::get_type): New accessor.

	(gcc::jit::recording::lvalue): Eliminate field m_type in favor of
	that within the rvalue base class.

	(gcc::jit::recording::param::make_debug_string): New.

	(gcc::jit::recording::function::get_return_type): New accessor.
	(gcc::jit::recording::function::make_debug_string): New.

	(gcc::jit::recording::label::make_debug_string): New.

	(gcc::jit::recording::global): Eliminate field m_type in favor of
	that within the rvalue ultimate base class (via lvalue).
	(gcc::jit::recording::make_debug_string): New.

	(gcc::jit::recording::memento_of_new_rvalue_from_int): Eliminate
	field m_type in favor of that within the rvalue base class.
	(gcc::jit::recording::memento_of_new_rvalue_from_int::
	make_debug_string): New.

	(gcc::jit::recording::memento_of_new_rvalue_from_double): Eliminate
	field m_type in favor of that within the rvalue base class.
	(gcc::jit::recording::memento_of_new_rvalue_from_double::
	make_debug_string): New.

	(gcc::jit::recording::memento_of_new_rvalue_from_ptr): Eliminate
	field m_type in favor of that within the rvalue base class.
	(gcc::jit::recording::memento_of_new_rvalue_from_ptr::
	make_debug_string): New.

	(gcc::jit::recording::memento_of_new_string_literal::
	memento_of_new_string_literal): Initialize type.
	(gcc::jit::recording::memento_of_new_string_literal::
	make_debug_string): New.

	(gcc::jit::recording::unary_op): Eliminate field m_result_type in
	favor of m_type within the rvalue base class.
	(gcc::jit::recording::unary_op::make_debug_string): New.

	(gcc::jit::recording::binary_op): Eliminate field m_result_type in
	favor of m_type within the rvalue base class.
	(gcc::jit::recording::binary_op::make_debug_string): New.

	(gcc::jit::recording::comparison): Eliminate field m_result_type
	in favor of m_type within the rvalue base class.
	(gcc::jit::recording::comparison::make_debug_string): New.

	(gcc::jit::recording::make_debug_string): New.

	(gcc::jit::recording::array_lookup::array_lookup): Initialize type
	by dereferencing the type of the pointer.
	(gcc::jit::recording::array_lookup::make_debug_string): New.

	(gcc::jit::recording::access_field_of_lvalue::
	access_field_of_lvalue): Initialize type from that of the field.
	(gcc::jit::recording::access_field_of_lvalue::
	make_debug_string): New.

	(gcc::jit::recording::access_field_rvalue::
	access_field_of_rvalue): Initialize type from that of the field.
	(gcc::jit::recording::access_field_rvalue::make_debug_string):
	New.

	(gcc::jit::recording::dereference_field_rvalue::
	dereference_field_rvalue): Initialize type from that of the field.
	(gcc::jit::recording::dereference_field_rvalue::
	make_debug_string): New.

	(gcc::jit::recording::dereference_rvalue::dereference_rvalue):
	Initialize type by dereferencing the type of the pointer.
	(gcc::jit::recording::dereference_rvalue::make_debug_string): New.

	(gcc::jit::recording::get_address_of_lvalue::
	get_address_of_lvalue):  Initialize type by dereferencing the type
	of the pointer.
	(gcc::jit::recording::get_address_of_lvalue::make_debug_string):
	New.

	(gcc::jit::recording::local): Eliminate field m_type in favor of
	that within the rvalue ultimate base class (via lvalue).
	(gcc::jit::recording::make_debug_string): New.

	(gcc::jit::recording::eval::make_debug_string): New.
	(gcc::jit::recording::assignment::make_debug_string): New.
	(gcc::jit::recording::assignment_op::make_debug_string): New.
	(gcc::jit::recording::comment::make_debug_string): New.
	(gcc::jit::recording::conditional::make_debug_string): New.
	(gcc::jit::recording::place_label::make_debug_string): New.
	(gcc::jit::recording::jump::make_debug_string): New.
	(gcc::jit::recording::return_::make_debug_string): New.
	(gcc::jit::recording::loop::make_debug_string): New.
	(gcc::jit::recording::loop_end::make_debug_string): New.

	* internal-api.c (gcc::jit::recording::context::context):
	Initialize m_FILE_type and m_basic_types.
	(gcc::jit::recording::context::record): Move here from
	internal-api.h.
	(gcc::jit::recording::context::replay_into): Add a disabled way to
	log everything during a replay, exercising the stringification
	machinery.
	(gcc::jit::recording::context::get_type): Cache and reuse the
	types, so that repeated calls on the context give the same object.
	(gcc::jit::recording::context::get_opaque_FILE_type): New, for
	the result of dereferencing (FILE*), mostly so that fuzz-testing
	that tries this gets something sane back.
	(gcc::jit::recording::memento::get_debug_string): New method,
	giving a way to easily get a descriptive (const char *) for
	an API entity.  Internally, it lazily calls the make_debug_string
	virtual function, storing the result in m_debug_string.

	(gcc::jit::recording::string::string): Rename field m_copy to m_buffer.
	(gcc::jit::recording::string::~string): Likewise.
	(gcc::jit::recording::string::from_printf): New factory function,
	to make it easy to implement the make_debug_string hooks.

	(gcc::jit::recording::string::make_debug_string): New.

	(gcc::jit::recording::location::make_debug_string): New.

	(gcc::jit::recording::memento_of_get_type::dereference): New.

	(get_type_strings): New table of strings, for use by...
	(gcc::jit::recording::memento_of_get_type::make_debug_string): New.

	(gcc::jit::recording::memento_of_get_pointer::make_debug_string): New.

	(gcc::jit::recording::memento_of_get_const::make_debug_string): New.

	(gcc::jit::recording::field::make_debug_string): New.

	(gcc::jit::recording::struct_::struct_): Move here from
	internal-api.h.  Mark all fields as belonging to the new struct.

	(gcc::jit::recording::struct_::dereference): New.
	(gcc::jit::recording::struct_::make_debug_string): New.

	(gcc::jit::recording::function::make_debug_string): New.

	(gcc::jit::recording::label::make_debug_string): New.

	(gcc::jit::recording::memento_of_new_rvalue_from_int::
	make_debug_string): New.
	(gcc::jit::recording::memento_of_new_rvalue_from_double::
	make_debug_string): New.
	(gcc::jit::recording::memento_of_new_rvalue_from_ptr::
	make_debug_string): New.
	(gcc::jit::recording::memento_of_new_string_literal::
	make_debug_string): New.

	(gcc::jit::recording::unary_op::replay_into): Use get_type ()
	rather than the now-defunct m_result_type.
	(gcc::jit::recording::binary_op::replay_into): Likewise.

	(unary_op_strings): New table of strings for use by...
	(gcc::jit::recording::unary_op::make_debug_string): New.

	(binary_op_strings): New table of strings for use by...
	(gcc::jit::recording::binary_op::make_debug_string): New.

	(comparison_strings): New table of strings for use by...
	(gcc::jit::recording::comparison::make_debug_string): New.

	(gcc::jit::recording::call::call): Initialize the type.
	(gcc::jit::recording::call::make_debug_string): New.

	(gcc::jit::recording::array_lookup::make_debug_string): New.
	(gcc::jit::recording::access_field_of_lvalue::
	make_debug_string): New.
	(gcc::jit::recording::access_field_rvalue::
	make_debug_string): New.
	(gcc::jit::recording::dereference_field_rvalue::
	make_debug_string): New.
	(gcc::jit::recording::dereference_rvalue::make_debug_string): New.
	(gcc::jit::recording::get_address_of_lvalue::
	make_debug_string): New.
	(gcc::jit::recording::eval::make_debug_string): New.
	(gcc::jit::recording::assignment::make_debug_string): New.
	(gcc::jit::recording::assignment_op::make_debug_string): New.
	(gcc::jit::recording::comment::make_debug_string): New.
	(gcc::jit::recording::conditional::make_debug_string): New.
	(gcc::jit::recording::place_label::make_debug_string): New.
	(gcc::jit::recording::jump::make_debug_string): New.
	(gcc::jit::recording::return_::make_debug_string): New.
	(gcc::jit::recording::loop::make_debug_string): New.
	(gcc::jit::recording::loop_end::make_debug_string): New.

gcc/testsuite/
	* jit.dg/test-error-accessing-field-in-other-struct.c: New test
	case.
	* jit.dg/test-error-dereference-field-of-non-pointer.c: Likewise.
	* jit.dg/test-error-dereference-read-of-non-pointer.c: Likewise.
	* jit.dg/test-error-mismatching-types-in-assignment.c: Likewise.
	* jit.dg/test-error-return-within-void-function.c: Likewise.
---
 gcc/jit/ChangeLog.jit                              | 287 +++++++++++
 gcc/jit/TODO.rst                                   |  46 ++
 gcc/jit/internal-api.c                             | 554 ++++++++++++++++++++-
 gcc/jit/internal-api.h                             | 279 +++++++++--
 gcc/jit/libgccjit.c                                | 110 +++-
 gcc/jit/libgccjit.h                                |   5 +-
 gcc/testsuite/ChangeLog.jit                        |   9 +
 .../test-error-accessing-field-in-other-struct.c   | 113 +++++
 .../test-error-dereference-field-of-non-pointer.c  |  89 ++++
 .../test-error-dereference-read-of-non-pointer.c   |  54 ++
 .../test-error-mismatching-types-in-assignment.c   |  58 +++
 .../test-error-return-within-void-function.c       |  52 ++
 12 files changed, 1584 insertions(+), 72 deletions(-)
 create mode 100644 gcc/testsuite/jit.dg/test-error-accessing-field-in-other-struct.c
 create mode 100644 gcc/testsuite/jit.dg/test-error-dereference-field-of-non-pointer.c
 create mode 100644 gcc/testsuite/jit.dg/test-error-dereference-read-of-non-pointer.c
 create mode 100644 gcc/testsuite/jit.dg/test-error-mismatching-types-in-assignment.c
 create mode 100644 gcc/testsuite/jit.dg/test-error-return-within-void-function.c

diff --git a/gcc/jit/ChangeLog.jit b/gcc/jit/ChangeLog.jit
index 36e69e4..de92fbe 100644
--- a/gcc/jit/ChangeLog.jit
+++ b/gcc/jit/ChangeLog.jit
@@ -1,3 +1,290 @@
+2014-01-30  David Malcolm  <dmalcolm@redhat.com>
+
+	* TODO.rst: begin a list of error-checking we could do that this
+	commit *doesn't* cover.
+
+	* libgccjit.h (gcc_jit_field): Add note that fields can't be
+	shared between structs.
+	(GCC_JIT_BINARY_OP_MODULO): Fix typo in comment.
+
+	* libgccjit.c: (RETURN_VAL_IF_FAIL_PRINTF2): New.
+	(RETURN_VAL_IF_FAIL_PRINTF3): New.
+	(RETURN_NULL_IF_FAIL_PRINTF2): New.
+	(RETURN_NULL_IF_FAIL_PRINTF3): New.
+	(RETURN_IF_FAIL_PRINTF4): New.
+
+	(jit_error): Take a gcc::jit::recording::context rather than
+	a gcc_jit_context so that we pass in contexts from the inner
+	layer.
+
+	(compatible_types): New, for use in type-checking.
+
+	(gcc_jit_context_new_struct_type): Check each field to ensure that
+	it isn't already in use by another struct.
+
+	(gcc_jit_rvalue_dereference_field): Check that ptr is of a pointer
+	type and that the field is within the correct struct, using new
+	get_debug_string hooks to generate error messages.
+
+	(gcc_jit_rvalue_dereference): Check that rvalue is of a pointer
+	type.
+
+	(gcc_jit_function_add_assignment): Use the function's context when
+	reporting on NULL lvalue or rvalue.  Verify that the lvalue and
+	rvalue have compatible types.
+
+	(gcc_jit_function_add_return): Use the function's context when
+	reporting on NULL rvalue.  Verify that the rvalue is of an
+	appropriate type given the function's return type.
+
+	* internal-api.h (NUM_GCC_JIT_TYPES): New.
+	(gcc::jit::recording::context::record): Move from here to
+	internal-api.c.
+	(gcc::jit::recording::context::get_opaque_FILE_type): New.
+	(gcc::jit::recording::context::m_basic_types): New field.
+	(gcc::jit::recording::context::m_FILE_type): New field.
+
+	(gcc::jit::recording::memento::get_debug_string): New method.
+	(gcc::jit::recording::memento::memento): Initialize new field
+	m_debug_string, and verify context is non-NULL.
+	(gcc::jit::recording::memento::make_debug_string): New
+	pure-virtual function lazily used by get_debug_string.
+	(gcc::jit::recording::memento::m_debug_string): New field, for
+	get_debug_string to use as a cache.
+
+	(gcc::jit::recording::string): Rename field m_copy to m_buffer.
+	(gcc::jit::recording::from_printf): New factory function.
+	(gcc::jit::recording::make_debug_string): New.
+
+	(gcc::jit::recording::location::make_debug_string): New.
+
+	(gcc::jit::recording::type::dereference): New pure-virtual
+	function.
+	(gcc::jit::recording::type::accepts_writes_from): New virtual
+	function.
+	(gcc::jit::recording::type::unqualified): New virtual function.
+
+	(gcc::jit::recording::memento_of_get_type::dereference): New.
+	(gcc::jit::recording::memento_of_get_type::
+	accepts_writes_from): New.
+	(gcc::jit::recording::memento_of_get_type::make_debug_string):
+	New.
+
+	(gcc::jit::recording::memento_of_get_pointer::make_debug_string):
+	New.
+	(gcc::jit::recording::memento_of_get_pointer::dereference): New.
+	New.
+
+	(gcc::jit::recording::memento_of_get_const::make_debug_string):
+	New.
+	(gcc::jit::recording::memento_of_get_const::dereference): New.
+	New.
+	(gcc::jit::recording::memento_of_get_const::accepts_writes_from):
+	New.
+	(gcc::jit::recording::memento_of_get_const::unqualified): New.
+
+	(gcc::jit::recording::field): New field m_container, for the
+	containing struct (or union, if we implement that).
+	(gcc::jit::recording::field::get_type): New.
+	(gcc::jit::recording::field::get_container): New.
+	(gcc::jit::recording::field:set_container): New.
+	(gcc::jit::recording::field::make_debug_string): New.
+
+	(gcc::jit::recording::struct_::struct_): Move ctor implementation
+	from here into internal-api.c.
+	(gcc::jit::recording::struct_::dereference): New.
+	(gcc::jit::recording::struct_::make_debug_string): New.
+
+	(gcc::jit::recording::rvalue::m_type): New field.
+	(gcc::jit::recording::rvalue::rvalue): Require a non-NULL type for
+	new rvalue instances.
+	(gcc::jit::recording::rvalue::get_type): New accessor.
+
+	(gcc::jit::recording::lvalue): Eliminate field m_type in favor of
+	that within the rvalue base class.
+
+	(gcc::jit::recording::param::make_debug_string): New.
+
+	(gcc::jit::recording::function::get_return_type): New accessor.
+	(gcc::jit::recording::function::make_debug_string): New.
+
+	(gcc::jit::recording::label::make_debug_string): New.
+
+	(gcc::jit::recording::global): Eliminate field m_type in favor of
+	that within the rvalue ultimate base class (via lvalue).
+	(gcc::jit::recording::make_debug_string): New.
+
+	(gcc::jit::recording::memento_of_new_rvalue_from_int): Eliminate
+	field m_type in favor of that within the rvalue base class.
+	(gcc::jit::recording::memento_of_new_rvalue_from_int::
+	make_debug_string): New.
+
+	(gcc::jit::recording::memento_of_new_rvalue_from_double): Eliminate
+	field m_type in favor of that within the rvalue base class.
+	(gcc::jit::recording::memento_of_new_rvalue_from_double::
+	make_debug_string): New.
+
+	(gcc::jit::recording::memento_of_new_rvalue_from_ptr): Eliminate
+	field m_type in favor of that within the rvalue base class.
+	(gcc::jit::recording::memento_of_new_rvalue_from_ptr::
+	make_debug_string): New.
+
+	(gcc::jit::recording::memento_of_new_string_literal::
+	memento_of_new_string_literal): Initialize type.
+	(gcc::jit::recording::memento_of_new_string_literal::
+	make_debug_string): New.
+
+	(gcc::jit::recording::unary_op): Eliminate field m_result_type in
+	favor of m_type within the rvalue base class.
+	(gcc::jit::recording::unary_op::make_debug_string): New.
+
+	(gcc::jit::recording::binary_op): Eliminate field m_result_type in
+	favor of m_type within the rvalue base class.
+	(gcc::jit::recording::binary_op::make_debug_string): New.
+
+	(gcc::jit::recording::comparison): Eliminate field m_result_type
+	in favor of m_type within the rvalue base class.
+	(gcc::jit::recording::comparison::make_debug_string): New.
+
+	(gcc::jit::recording::make_debug_string): New.
+
+	(gcc::jit::recording::array_lookup::array_lookup): Initialize type
+	by dereferencing the type of the pointer.
+	(gcc::jit::recording::array_lookup::make_debug_string): New.
+
+	(gcc::jit::recording::access_field_of_lvalue::
+	access_field_of_lvalue): Initialize type from that of the field.
+	(gcc::jit::recording::access_field_of_lvalue::
+	make_debug_string): New.
+
+	(gcc::jit::recording::access_field_rvalue::
+	access_field_of_rvalue): Initialize type from that of the field.
+	(gcc::jit::recording::access_field_rvalue::make_debug_string):
+	New.
+
+	(gcc::jit::recording::dereference_field_rvalue::
+	dereference_field_rvalue): Initialize type from that of the field.
+	(gcc::jit::recording::dereference_field_rvalue::
+	make_debug_string): New.
+
+	(gcc::jit::recording::dereference_rvalue::dereference_rvalue):
+	Initialize type by dereferencing the type of the pointer.
+	(gcc::jit::recording::dereference_rvalue::make_debug_string): New.
+
+	(gcc::jit::recording::get_address_of_lvalue::
+	get_address_of_lvalue):  Initialize type by dereferencing the type
+	of the pointer.
+	(gcc::jit::recording::get_address_of_lvalue::make_debug_string):
+	New.
+
+	(gcc::jit::recording::local): Eliminate field m_type in favor of
+	that within the rvalue ultimate base class (via lvalue).
+	(gcc::jit::recording::make_debug_string): New.
+
+	(gcc::jit::recording::eval::make_debug_string): New.
+	(gcc::jit::recording::assignment::make_debug_string): New.
+	(gcc::jit::recording::assignment_op::make_debug_string): New.
+	(gcc::jit::recording::comment::make_debug_string): New.
+	(gcc::jit::recording::conditional::make_debug_string): New.
+	(gcc::jit::recording::place_label::make_debug_string): New.
+	(gcc::jit::recording::jump::make_debug_string): New.
+	(gcc::jit::recording::return_::make_debug_string): New.
+	(gcc::jit::recording::loop::make_debug_string): New.
+	(gcc::jit::recording::loop_end::make_debug_string): New.
+
+	* internal-api.c (gcc::jit::recording::context::context):
+	Initialize m_FILE_type and m_basic_types.
+	(gcc::jit::recording::context::record): Move here from
+	internal-api.h.
+	(gcc::jit::recording::context::replay_into): Add a disabled way to
+	log everything during a replay, exercising the stringification
+	machinery.
+	(gcc::jit::recording::context::get_type): Cache and reuse the
+	types, so that repeated calls on the context give the same object.
+	(gcc::jit::recording::context::get_opaque_FILE_type): New, for
+	the result of dereferencing (FILE*), mostly so that fuzz-testing
+	that tries this gets something sane back.
+	(gcc::jit::recording::memento::get_debug_string): New method,
+	giving a way to easily get a descriptive (const char *) for
+	an API entity.  Internally, it lazily calls the make_debug_string
+	virtual function, storing the result in m_debug_string.
+
+	(gcc::jit::recording::string::string): Rename field m_copy to m_buffer.
+	(gcc::jit::recording::string::~string): Likewise.
+	(gcc::jit::recording::string::from_printf): New factory function,
+	to make it easy to implement the make_debug_string hooks.
+
+	(gcc::jit::recording::string::make_debug_string): New.
+
+	(gcc::jit::recording::location::make_debug_string): New.
+
+	(gcc::jit::recording::memento_of_get_type::dereference): New.
+
+	(get_type_strings): New table of strings, for use by...
+	(gcc::jit::recording::memento_of_get_type::make_debug_string): New.
+
+	(gcc::jit::recording::memento_of_get_pointer::make_debug_string): New.
+
+	(gcc::jit::recording::memento_of_get_const::make_debug_string): New.
+
+	(gcc::jit::recording::field::make_debug_string): New.
+
+	(gcc::jit::recording::struct_::struct_): Move here from
+	internal-api.h.  Mark all fields as belonging to the new struct.
+
+	(gcc::jit::recording::struct_::dereference): New.
+	(gcc::jit::recording::struct_::make_debug_string): New.
+
+	(gcc::jit::recording::function::make_debug_string): New.
+
+	(gcc::jit::recording::label::make_debug_string): New.
+
+	(gcc::jit::recording::memento_of_new_rvalue_from_int::
+	make_debug_string): New.
+	(gcc::jit::recording::memento_of_new_rvalue_from_double::
+	make_debug_string): New.
+	(gcc::jit::recording::memento_of_new_rvalue_from_ptr::
+	make_debug_string): New.
+	(gcc::jit::recording::memento_of_new_string_literal::
+	make_debug_string): New.
+
+	(gcc::jit::recording::unary_op::replay_into): Use get_type ()
+	rather than the now-defunct m_result_type.
+	(gcc::jit::recording::binary_op::replay_into): Likewise.
+
+	(unary_op_strings): New table of strings for use by...
+	(gcc::jit::recording::unary_op::make_debug_string): New.
+
+	(binary_op_strings): New table of strings for use by...
+	(gcc::jit::recording::binary_op::make_debug_string): New.
+
+	(comparison_strings): New table of strings for use by...
+	(gcc::jit::recording::comparison::make_debug_string): New.
+
+	(gcc::jit::recording::call::call): Initialize the type.
+	(gcc::jit::recording::call::make_debug_string): New.
+
+	(gcc::jit::recording::array_lookup::make_debug_string): New.
+	(gcc::jit::recording::access_field_of_lvalue::
+	make_debug_string): New.
+	(gcc::jit::recording::access_field_rvalue::
+	make_debug_string): New.
+	(gcc::jit::recording::dereference_field_rvalue::
+	make_debug_string): New.
+	(gcc::jit::recording::dereference_rvalue::make_debug_string): New.
+	(gcc::jit::recording::get_address_of_lvalue::
+	make_debug_string): New.
+	(gcc::jit::recording::eval::make_debug_string): New.
+	(gcc::jit::recording::assignment::make_debug_string): New.
+	(gcc::jit::recording::assignment_op::make_debug_string): New.
+	(gcc::jit::recording::comment::make_debug_string): New.
+	(gcc::jit::recording::conditional::make_debug_string): New.
+	(gcc::jit::recording::place_label::make_debug_string): New.
+	(gcc::jit::recording::jump::make_debug_string): New.
+	(gcc::jit::recording::return_::make_debug_string): New.
+	(gcc::jit::recording::loop::make_debug_string): New.
+	(gcc::jit::recording::loop_end::make_debug_string): New.
+
 2014-01-29  David Malcolm  <dmalcolm@redhat.com>
 
 	* libgccjit.h (gcc_jit_lvalue_access_field): Require
diff --git a/gcc/jit/TODO.rst b/gcc/jit/TODO.rst
index d89b5ab..79b4efa 100644
--- a/gcc/jit/TODO.rst
+++ b/gcc/jit/TODO.rst
@@ -94,6 +94,52 @@ Initial Release
 
 * are we missing any ops?
 
+* error-checking:
+
+    * gcc_jit_context_new_field: type must not be void
+
+    * gcc_jit_context_new_param: type must not be void
+
+    * gcc_jit_context_new_global: type must not be void
+
+    * gcc_jit_context_new_rvalue_from_int: must be a numeric type
+
+    * gcc_jit_context_zero: must be a numeric type
+
+    * gcc_jit_context_one: must be a numeric type
+
+    * gcc_jit_context_new_rvalue_from_double: must be a numeric type
+
+    * gcc_jit_context_new_rvalue_from_ptr: must be a pointer type
+
+    * gcc_jit_context_new_unary_op: various checks needed
+
+    * gcc_jit_context_new_binary_op: various checks needed
+
+    * 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.
+
+    * gcc_jit_lvalue_access_field: must be field of correct struct
+
+    * gcc_jit_rvalue_access_field: must be field of correct struct
+
+    * gcc_jit_function_new_local: type must not be void
+
+    * gcc_jit_function_place_forward_label: must not already have been
+      placed
+
+    * gcc_jit_function_add_assignment_op: check the types
+
+    * gcc_jit_function_add_conditional: boolval must be of numeric type
+
+    * gcc_jit_loop_end: verify that loops are validly nested?
+
+    * verify that all used labels have been placed when attempting to
+      compile
 
 Future milestones
 =================
diff --git a/gcc/jit/internal-api.c b/gcc/jit/internal-api.c
index 39d434f..5e72e62 100644
--- a/gcc/jit/internal-api.c
+++ b/gcc/jit/internal-api.c
@@ -60,7 +60,8 @@ recording::playback_label (recording::label *lab)
 recording::context::context (context *parent_ctxt)
   : m_parent_ctxt (parent_ctxt),
     m_error_count (0),
-    m_mementos ()
+    m_mementos (),
+    m_FILE_type (NULL)
 {
   m_first_error_str[0] = '\0';
 
@@ -84,6 +85,8 @@ recording::context::context (context *parent_ctxt)
       memset (m_int_options, 0, sizeof (m_int_options));
       memset (m_bool_options, 0, sizeof (m_bool_options));
     }
+
+  memset (m_basic_types, 0, sizeof (m_basic_types));
 }
 
 recording::context::~context ()
@@ -97,6 +100,14 @@ recording::context::~context ()
 }
 
 void
+recording::context::record (memento *m)
+{
+  gcc_assert (m);
+
+  m_mementos.safe_push (m);
+}
+
+void
 recording::context::replay_into (replayer *r)
 {
   int i;
@@ -123,6 +134,16 @@ recording::context::replay_into (replayer *r)
   /* Replay this context's saved operations into r.  */
   FOR_EACH_VEC_ELT (m_mementos, i, m)
     {
+      /* Disabled low-level debugging, here if we need it: print what
+	 we're replaying.
+	 Note that the calls to get_debug_string might lead to more
+	 mementos being created for the strings.
+	 This can also be used to exercise the debug_string
+	 machinery.  */
+      if (0)
+	printf ("context %p replaying (%p): %s\n",
+		(void *)this, (void *)m, m->get_debug_string ());
+
       m->replay_into (r);
     }
 }
@@ -175,9 +196,16 @@ recording::context::new_location (const char *filename,
 recording::type *
 recording::context::get_type (enum gcc_jit_types kind)
 {
-  recording::type *result = new memento_of_get_type (this, kind);
-  record (result);
-  return result;
+  /* Cache and reuse the types, so that repeated calls on the context
+     give the same object.  */
+  if (!m_basic_types[kind])
+    {
+      recording::type *result = new memento_of_get_type (this, kind);
+      record (result);
+      m_basic_types[kind] = result;
+    }
+
+  return m_basic_types[kind];
 }
 
 recording::field *
@@ -460,21 +488,87 @@ recording::context::get_first_error () const
     return NULL;
 }
 
+recording::type *
+recording::context::get_opaque_FILE_type ()
+{
+  if (!m_FILE_type)
+    m_FILE_type = new_struct_type (NULL, "FILE", 0, NULL);
+  return m_FILE_type;
+}
+
+/* gcc::jit::recording::memento:: */
+
+const char *
+recording::memento::get_debug_string ()
+{
+  if (!m_debug_string)
+    m_debug_string = make_debug_string ();
+  return m_debug_string->c_str ();
+}
+
 /* gcc::jit::recording::string:: */
 recording::string::string (context *ctxt, const char *text)
   : memento (ctxt)
 {
-  m_len = strlen (text) ;
-  m_copy = new char[m_len + 1];
-  strcpy (m_copy, text);
+  m_len = strlen (text);
+  m_buffer = new char[m_len + 1];
+  strcpy (m_buffer, text);
 }
 
 recording::string::~string ()
 {
-  delete[] m_copy;
+  delete[] m_buffer;
+}
+
+recording::string *
+recording::string::from_printf (context *ctxt, const char *fmt, ...)
+{
+  char buf[4096];
+  va_list ap;
+  va_start (ap, fmt);
+
+  vsnprintf (buf, sizeof (buf), fmt, ap);
+
+  va_end (ap);
+
+  return ctxt->new_string (buf);
 }
 
+recording::string *
+recording::string::make_debug_string ()
+{
+  /* Hack to avoid infinite recursion into strings when logging all
+     mementos: don't re-escape strings:  */
+  if (m_buffer[0] == '"')
+    return this;
+
+  /* Wrap in quotes and do escaping etc */
+
+  size_t sz = (1 /* opening quote */
+	       + (m_len * 2) /* each char might get escaped */
+	       + 1 /* closing quote */
+	       + 1); /* nil termintator */
+  char *tmp = new char[sz];
+  size_t len = 0;
+
+#define APPEND(CH)  do { gcc_assert (len < sz); tmp[len++] = (CH); } while (0)
+  APPEND('"'); /* opening quote */
+  for (size_t i = 0; i < m_len ; i++)
+    {
+      char ch = m_buffer[i];
+      if (ch == '\t' || ch == '\n' || ch == '\\' || ch == '"')
+	APPEND('\\');
+      APPEND(ch);
+    }
+  APPEND('"'); /* closing quote */
+#undef APPEND
+  tmp[len] = '\0'; /* nil termintator */
+
+  string *result = m_ctxt->new_string (tmp);
 
+  delete[] tmp;
+  return result;
+}
 
 /* gcc::jit::recording::location:: */
 void
@@ -483,6 +577,14 @@ recording::location::replay_into (replayer *r)
   m_playback_obj = r->new_location (m_filename->c_str (), m_line, m_column);
 }
 
+recording::string *
+recording::location::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "%s:%i:%i",
+			      m_filename->c_str (), m_line, m_column);
+}
+
 /* gcc::jit::recording::type:: */
 
 recording::type *
@@ -501,13 +603,94 @@ recording::type::get_const ()
   return result;
 }
 
-/* gcc::jit::recording::memento_of_get_type:: */
+recording::type *
+recording::memento_of_get_type::dereference ()
+{
+  switch (m_kind)
+    {
+    default: gcc_unreachable ();
+
+    case GCC_JIT_TYPE_VOID:
+      return NULL;
+
+    case GCC_JIT_TYPE_VOID_PTR:
+      return m_ctxt->get_type (GCC_JIT_TYPE_VOID);
+
+    case GCC_JIT_TYPE_CHAR:
+    case GCC_JIT_TYPE_SIGNED_CHAR:
+    case GCC_JIT_TYPE_UNSIGNED_CHAR:
+    case GCC_JIT_TYPE_SHORT:
+    case GCC_JIT_TYPE_UNSIGNED_SHORT:
+    case GCC_JIT_TYPE_INT:
+    case GCC_JIT_TYPE_UNSIGNED_INT:
+    case GCC_JIT_TYPE_LONG:
+    case GCC_JIT_TYPE_UNSIGNED_LONG:
+    case GCC_JIT_TYPE_LONG_LONG:
+    case GCC_JIT_TYPE_UNSIGNED_LONG_LONG:
+    case GCC_JIT_TYPE_FLOAT:
+    case GCC_JIT_TYPE_DOUBLE:
+    case GCC_JIT_TYPE_LONG_DOUBLE:
+      /* Not a pointer: */
+      return NULL;
+
+    case GCC_JIT_TYPE_CONST_CHAR_PTR:
+      return m_ctxt->get_type (GCC_JIT_TYPE_CHAR)->get_const ();
+
+    case GCC_JIT_TYPE_SIZE_T:
+      /* Not a pointer: */
+      return NULL;
+
+    case GCC_JIT_TYPE_FILE_PTR:
+      /* Give the client code back an opaque "struct FILE".  */
+      return m_ctxt->get_opaque_FILE_type ();
+    }
+}
+
 void
 recording::memento_of_get_type::replay_into (replayer *r)
 {
   set_playback_obj (r->get_type (m_kind));
 }
 
+/* gcc::jit::recording::memento_of_get_type:: */
+static const char * const get_type_strings[] = {
+  "void",    /* GCC_JIT_TYPE_VOID */
+  "void *",  /* GCC_JIT_TYPE_VOID_PTR */
+
+  "char",           /* GCC_JIT_TYPE_CHAR */
+  "signed char",    /* GCC_JIT_TYPE_SIGNED_CHAR */
+  "unsigned char",  /* GCC_JIT_TYPE_UNSIGNED_CHAR */
+
+  "short",           /* GCC_JIT_TYPE_SHORT */
+  "unsigned short",  /* GCC_JIT_TYPE_UNSIGNED_SHORT */
+
+  "int",           /* GCC_JIT_TYPE_INT */
+  "unsigned int",  /* GCC_JIT_TYPE_UNSIGNED_INT */
+
+  "long",           /* GCC_JIT_TYPE_LONG  */
+  "unsigned long",  /* GCC_JIT_TYPE_UNSIGNED_LONG, */
+
+  "long long",           /* GCC_JIT_TYPE_LONG_LONG */
+  "unsigned long long",  /* GCC_JIT_TYPE_UNSIGNED_LONG_LONG */
+
+  "float",        /* GCC_JIT_TYPE_FLOAT */
+  "double",       /* GCC_JIT_TYPE_DOUBLE */
+  "long double",  /* GCC_JIT_TYPE_LONG_DOUBLE */
+
+  "const char *",  /* GCC_JIT_TYPE_CONST_CHAR_PTR */
+
+  "size_t",  /* GCC_JIT_TYPE_SIZE_T */
+
+  "FILE *"  /* GCC_JIT_TYPE_FILE_PTR */
+
+};
+
+recording::string *
+recording::memento_of_get_type::make_debug_string ()
+{
+  return m_ctxt->new_string (get_type_strings[m_kind]);
+}
+
 /* gcc::jit::recording::memento_of_get_pointer:: */
 void
 recording::memento_of_get_pointer::replay_into (replayer *)
@@ -515,6 +698,13 @@ recording::memento_of_get_pointer::replay_into (replayer *)
   set_playback_obj (m_other_type->playback_type ()->get_pointer ());
 }
 
+recording::string *
+recording::memento_of_get_pointer::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "%s *", m_other_type->get_debug_string ());
+}
+
 /* gcc::jit::recording::memento_of_get_const:: */
 
 void
@@ -523,6 +713,13 @@ recording::memento_of_get_const::replay_into (replayer *)
   set_playback_obj (m_other_type->playback_type ()->get_const ());
 }
 
+recording::string *
+recording::memento_of_get_const::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "const %s", m_other_type->get_debug_string ());
+}
+
 /* gcc::jit::recording::field:: */
 void
 recording::field::replay_into (replayer *r)
@@ -532,7 +729,36 @@ recording::field::replay_into (replayer *r)
 				  playback_string (m_name)));
 }
 
+recording::string *
+recording::field::make_debug_string ()
+{
+  return m_name;
+}
+
 /* gcc::jit::recording::struct_:: */
+recording::struct_::struct_ (context *ctxt,
+			     location *loc,
+			     string *name,
+			     vec<field *> fields)
+: type (ctxt),
+  m_loc (loc),
+  m_name (name),
+  m_fields (fields)
+{
+  /* Mark all fields as belonging to the new struct: */
+  for (unsigned i = 0; i < fields.length (); i++)
+    {
+      gcc_assert (m_fields[i]->get_container () == NULL);
+      m_fields[i]->set_container (this);
+    }
+}
+
+recording::type *
+recording::struct_::dereference ()
+{
+  return NULL; /* not a pointer */
+}
+
 void
 recording::struct_::replay_into (replayer *r)
 {
@@ -547,6 +773,12 @@ recording::struct_::replay_into (replayer *r)
 			&playback_fields));
 }
 
+recording::string *
+recording::struct_::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "struct %s", m_name->c_str ());
+}
 
 /* gcc::jit::recording::rvalue:: */
 
@@ -757,6 +989,12 @@ recording::function::new_loop (recording::location *loc,
   return result;
 }
 
+recording::string *
+recording::function::make_debug_string ()
+{
+  return m_name;
+}
+
 /* gcc::jit::recording::label:: */
 
 void
@@ -766,6 +1004,17 @@ recording::label::replay_into (replayer *)
 		      ->new_forward_label (playback_string (m_name)));
 }
 
+recording::string *
+recording::label::make_debug_string ()
+{
+  if (m_name)
+    return m_name;
+  else
+    return string::from_printf (m_ctxt,
+				"<UNNAMED LABEL %p>",
+				(void *)this);
+}
+
 /* gcc::jit::recording::global:: */
 void
 recording::global::replay_into (replayer *r)
@@ -783,6 +1032,15 @@ recording::memento_of_new_rvalue_from_int::replay_into (replayer *r)
 					    m_value));
 }
 
+recording::string *
+recording::memento_of_new_rvalue_from_int::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "(%s)%i",
+			      m_type->get_debug_string (),
+			      m_value);
+}
+
 /* gcc::jit::recording::memento_of_new_rvalue_from_double:: */
 void
 recording::memento_of_new_rvalue_from_double::replay_into (replayer *r)
@@ -791,6 +1049,15 @@ recording::memento_of_new_rvalue_from_double::replay_into (replayer *r)
 					       m_value));
 }
 
+recording::string *
+recording::memento_of_new_rvalue_from_double::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "(%s)%f",
+			      m_type->get_debug_string (),
+			      m_value);
+}
+
 /* gcc::jit::recording::memento_of_new_rvalue_from_ptr:: */
 void
 recording::memento_of_new_rvalue_from_ptr::replay_into (replayer *r)
@@ -799,6 +1066,19 @@ recording::memento_of_new_rvalue_from_ptr::replay_into (replayer *r)
 					    m_value));
 }
 
+recording::string *
+recording::memento_of_new_rvalue_from_ptr::make_debug_string ()
+{
+  if (m_value != NULL)
+    return string::from_printf (m_ctxt,
+				"(%s)%p",
+				m_type->get_debug_string (), m_value);
+  else
+    return string::from_printf (m_ctxt,
+				"(%s)NULL",
+				m_type->get_debug_string ());
+}
+
 /* gcc::jit::recording::memento_of_new_string_literal:: */
 void
 recording::memento_of_new_string_literal::replay_into (replayer *r)
@@ -806,16 +1086,37 @@ recording::memento_of_new_string_literal::replay_into (replayer *r)
   set_playback_obj (r->new_string_literal (m_value->c_str ()));
 }
 
+recording::string *
+recording::memento_of_new_string_literal::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      m_value->get_debug_string ());
+}
+
 /* gcc::jit::recording::unary_op:: */
 void
 recording::unary_op::replay_into (replayer *r)
 {
   set_playback_obj (r->new_unary_op (playback_location (m_loc),
 				     m_op,
-				     m_result_type->playback_type (),
+				     get_type ()->playback_type (),
 				     m_a->playback_rvalue ()));
 }
 
+static const char * const unary_op_strings[] = {
+  "-", /* GCC_JIT_UNARY_OP_MINUS */
+  "~", /* GCC_JIT_UNARY_OP_BITWISE_NEGATE */
+  "!", /* GCC_JIT_UNARY_OP_LOGICAL_NEGATE */
+};
+
+recording::string *
+recording::unary_op::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "%s(%s)",
+			      unary_op_strings[m_op],
+			      m_a->get_debug_string ());
+}
 
 /* gcc::jit::recording::binary_op:: */
 void
@@ -823,11 +1124,55 @@ recording::binary_op::replay_into (replayer *r)
 {
   set_playback_obj (r->new_binary_op (playback_location (m_loc),
 				      m_op,
-				      m_result_type->playback_type (),
+				      get_type ()->playback_type (),
 				      m_a->playback_rvalue (),
 				      m_b->playback_rvalue ()));
 }
 
+static const char * const binary_op_strings[] = {
+  "+", /* GCC_JIT_BINARY_OP_PLUS */
+  "-", /* GCC_JIT_BINARY_OP_MINUS */
+  "*", /* GCC_JIT_BINARY_OP_MULT */
+  "/", /* GCC_JIT_BINARY_OP_DIVIDE */
+  "%", /* GCC_JIT_BINARY_OP_MODULO */
+  "&", /* GCC_JIT_BINARY_OP_BITWISE_AND */
+  "^", /* GCC_JIT_BINARY_OP_BITWISE_XOR */
+  "|", /* GCC_JIT_BINARY_OP_BITWISE_OR */
+  "&&", /* GCC_JIT_BINARY_OP_LOGICAL_AND */
+  "||" /* GCC_JIT_BINARY_OP_LOGICAL_OR */
+};
+
+recording::string *
+recording::binary_op::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "%s %s %s",
+			      m_a->get_debug_string (),
+			      binary_op_strings[m_op],
+			      m_b->get_debug_string ());
+}
+
+/* gcc::jit::recording::comparison:: */
+static const char * const comparison_strings[] =
+{
+  "==", /* GCC_JIT_COMPARISON_EQ */
+  "!=", /* GCC_JIT_COMPARISON_NE */
+  "<",  /* GCC_JIT_COMPARISON_LT */
+  "<=", /* GCC_JIT_COMPARISON_LE */
+  ">",  /* GCC_JIT_COMPARISON_GT */
+  ">=", /* GCC_JIT_COMPARISON_GE */
+};
+
+recording::string *
+recording::comparison::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "%s %s %s",
+			      m_a->get_debug_string (),
+			      comparison_strings[m_op],
+			      m_b->get_debug_string ());
+}
+
 void
 recording::comparison::replay_into (replayer *r)
 {
@@ -842,7 +1187,7 @@ recording::call::call (recording::context *ctxt,
 		       recording::function *func,
 		       int numargs,
 		       rvalue **args)
-: rvalue (ctxt, loc),
+: rvalue (ctxt, loc, func->get_return_type ()),
   m_func (func),
   m_args ()
 {
@@ -863,6 +1208,45 @@ recording::call::replay_into (replayer *r)
 				 playback_args));
 }
 
+recording::string *
+recording::call::make_debug_string ()
+{
+  /* First, build a buffer for the arguments.  */
+  /* Calculate length of said buffer.  */
+  size_t sz = 1; /* nil terminator */
+  for (unsigned i = 0; i< m_args.length (); i++)
+    {
+      sz += strlen (m_args[i]->get_debug_string ());
+      sz += 2; /* ", " separator */
+    }
+
+  /* Now allocate and populate the buffer.  */
+  char *argbuf = new char[sz];
+  size_t len = 0;
+
+  for (unsigned i = 0; i< m_args.length (); i++)
+    {
+      strcpy (argbuf + len, m_args[i]->get_debug_string ());
+      len += strlen (m_args[i]->get_debug_string ());
+      if (i + 1 < m_args.length ())
+	{
+	  strcpy (argbuf + len, ", ");
+	  len += 2;
+	}
+    }
+  argbuf[len] = '\0';
+
+  /* ...and use it to get the string for the call as a whole.  */
+  string *result = string::from_printf (m_ctxt,
+					"%s (%s)",
+					m_func->get_debug_string (),
+					argbuf);
+
+  delete[] argbuf;
+
+  return result;
+}
+
 void
 recording::array_lookup::replay_into (replayer *r)
 {
@@ -872,6 +1256,15 @@ recording::array_lookup::replay_into (replayer *r)
 			 m_index->playback_rvalue ()));
 }
 
+recording::string *
+recording::array_lookup::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "%s[%s]",
+			      m_ptr->get_debug_string (),
+			      m_index->get_debug_string ());
+}
+
 void
 recording::access_field_of_lvalue::replay_into (replayer *)
 {
@@ -882,6 +1275,15 @@ recording::access_field_of_lvalue::replay_into (replayer *)
 
 }
 
+recording::string *
+recording::access_field_of_lvalue::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "%s.%s",
+			      m_lvalue->get_debug_string (),
+			      m_field->get_debug_string ());
+}
+
 void
 recording::access_field_rvalue::replay_into (replayer *)
 {
@@ -891,6 +1293,15 @@ recording::access_field_rvalue::replay_into (replayer *)
 		      m_field->playback_field ()));
 }
 
+recording::string *
+recording::access_field_rvalue::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "%s.%s",
+			      m_rvalue->get_debug_string (),
+			      m_field->get_debug_string ());
+}
+
 void
 recording::dereference_field_rvalue::replay_into (replayer *)
 {
@@ -900,6 +1311,15 @@ recording::dereference_field_rvalue::replay_into (replayer *)
 			 m_field->playback_field ()));
 }
 
+recording::string *
+recording::dereference_field_rvalue::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "%s->%s",
+			      m_rvalue->get_debug_string (),
+			      m_field->get_debug_string ());
+}
+
 void
 recording::dereference_rvalue::replay_into (replayer *)
 {
@@ -908,6 +1328,14 @@ recording::dereference_rvalue::replay_into (replayer *)
       dereference (playback_location (m_loc)));
 }
 
+recording::string *
+recording::dereference_rvalue::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "*%s",
+			      m_rvalue->get_debug_string ());
+}
+
 void
 recording::get_address_of_lvalue::replay_into (replayer *)
 {
@@ -916,6 +1344,14 @@ recording::get_address_of_lvalue::replay_into (replayer *)
       get_address (playback_location (m_loc)));
 }
 
+recording::string *
+recording::get_address_of_lvalue::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "&%s",
+			      m_lvalue->get_debug_string ());
+}
+
 void
 recording::local::replay_into (replayer *)
 {
@@ -934,6 +1370,14 @@ recording::eval::replay_into (replayer *)
 		m_rvalue->playback_rvalue ());
 }
 
+recording::string *
+recording::eval::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "(void)%s;",
+			      m_rvalue->get_debug_string ());
+}
+
 void
 recording::assignment::replay_into (replayer *)
 {
@@ -943,6 +1387,15 @@ recording::assignment::replay_into (replayer *)
 		      m_rvalue->playback_rvalue ());
 }
 
+recording::string *
+recording::assignment::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "%s = %s;",
+			      m_lvalue->get_debug_string (),
+			      m_rvalue->get_debug_string ());
+}
+
 void
 recording::assignment_op::replay_into (replayer *r)
 {
@@ -962,6 +1415,16 @@ recording::assignment_op::replay_into (replayer *r)
 		      binary_op);
 }
 
+recording::string *
+recording::assignment_op::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "%s %s= %s;",
+			      m_lvalue->get_debug_string (),
+			      binary_op_strings[m_op],
+			      m_rvalue->get_debug_string ());
+}
+
 void
 recording::comment::replay_into (replayer *)
 {
@@ -970,6 +1433,14 @@ recording::comment::replay_into (replayer *)
 		   m_text->c_str ());
 }
 
+recording::string *
+recording::comment::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "/* %s */",
+			      m_text->c_str ());
+}
+
 void
 recording::conditional::replay_into (replayer *)
 {
@@ -980,6 +1451,22 @@ recording::conditional::replay_into (replayer *)
 		       playback_label (m_on_false));
 }
 
+recording::string *
+recording::conditional::make_debug_string ()
+{
+  if (m_on_false)
+    return string::from_printf (m_ctxt,
+				"if (%s) goto %s else goto %s;",
+				m_boolval->get_debug_string (),
+				m_on_true->get_debug_string (),
+				m_on_false->get_debug_string ());
+  else
+    return string::from_printf (m_ctxt,
+				"if (%s) goto %s;",
+				m_boolval->get_debug_string (),
+				m_on_true->get_debug_string ());
+}
+
 void
 recording::place_label::replay_into (replayer *)
 {
@@ -988,6 +1475,14 @@ recording::place_label::replay_into (replayer *)
 			   m_label->playback_label ());
 }
 
+recording::string *
+recording::place_label::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "%s:",
+			      m_label->get_debug_string ());
+}
+
 void
 recording::jump::replay_into (replayer *)
 {
@@ -996,6 +1491,14 @@ recording::jump::replay_into (replayer *)
 		m_target->playback_label ());
 }
 
+recording::string *
+recording::jump::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "goto %s;",
+			      m_target->get_debug_string ());
+}
+
 void
 recording::return_::replay_into (replayer *)
 {
@@ -1004,6 +1507,18 @@ recording::return_::replay_into (replayer *)
 		  m_rvalue ? m_rvalue->playback_rvalue () : NULL);
 }
 
+recording::string *
+recording::return_::make_debug_string ()
+{
+  if (m_rvalue)
+    return string::from_printf (m_ctxt,
+				"return %s;",
+				m_rvalue->get_debug_string ());
+  else
+    return string::from_printf (m_ctxt,
+				"return;");
+}
+
 void
 recording::loop::replay_into (replayer *)
 {
@@ -1013,6 +1528,14 @@ recording::loop::replay_into (replayer *)
 		  m_boolval->playback_rvalue ()));
 }
 
+recording::string *
+recording::loop::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "loop_while (%s)",
+			      m_boolval->get_debug_string ());
+}
+
 void
 recording::loop::end (location *loc)
 {
@@ -1026,6 +1549,13 @@ recording::loop_end::replay_into (replayer *)
   m_loop->playback_loop ()->end (playback_location (m_loc));
 }
 
+recording::string *
+recording::loop_end::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "end_loop (%p)", (void *)m_loop);
+}
+
 /**********************************************************************
  Playback.
  **********************************************************************/
diff --git a/gcc/jit/internal-api.h b/gcc/jit/internal-api.h
index 66d8cdb..a2848a8 100644
--- a/gcc/jit/internal-api.h
+++ b/gcc/jit/internal-api.h
@@ -13,6 +13,8 @@
 #endif
 #endif
 
+const int NUM_GCC_JIT_TYPES = GCC_JIT_TYPE_FILE_PTR + 1;
+
 /* In order to allow jit objects to be usable outside of a compile
    whilst working with the existing structure of GCC's code the
    C API is implemented in terms of a gcc::jit::recording::context,
@@ -77,6 +79,7 @@ namespace recording {
   class location;
   class type;
   class field;
+  class struct_;
   class function;
   class label;
   class rvalue;
@@ -124,7 +127,7 @@ public:
   context (context *parent_ctxt);
   ~context ();
 
-  void record (memento *m) { m_mementos.safe_push (m); }
+  void record (memento *m);
   void replay_into (replayer *r);
   void disassociate_from_playback ();
 
@@ -261,6 +264,8 @@ public:
     return m_error_count;
   }
 
+  type *get_opaque_FILE_type ();
+
 private:
   context *m_parent_ctxt;
 
@@ -274,6 +279,8 @@ private:
   /* Recorded API usage.  */
   vec<memento *> m_mementos;
 
+  type *m_basic_types[NUM_GCC_JIT_TYPES];
+  type *m_FILE_type;
 };
 
 
@@ -291,19 +298,32 @@ public:
 
   void set_playback_obj (void *obj) { m_playback_obj = obj; }
 
+  /* Debugging hook, for use in generating error messages etc.  */
+  const char *
+  get_debug_string ();
+
 protected:
   memento (context *ctxt)
   : m_ctxt (ctxt),
-    m_playback_obj (NULL)
-  {}
+    m_playback_obj (NULL),
+    m_debug_string (NULL)
+  {
+    gcc_assert (ctxt);
+  }
 
   string *new_string (const char *text) { return m_ctxt->new_string (text); }
 
+private:
+  virtual string * make_debug_string () = 0;
+
 public:
   context *m_ctxt;
 
 protected:
   void *m_playback_obj;
+
+private:
+  string *m_debug_string;
 };
 
 /* or just use std::string? */
@@ -313,13 +333,19 @@ public:
   string (context *ctxt, const char *text);
   ~string ();
 
-  const char *c_str () { return m_copy; }
+  const char *c_str () { return m_buffer; }
+
+  static string * from_printf (context *ctxt, const char *fmt, ...)
+    GNU_PRINTF(2, 3);
 
   void replay_into (replayer *) {}
 
 private:
+  string * make_debug_string ();
+
+private:
   size_t m_len;
-  char *m_copy;
+  char *m_buffer;
 };
 
 class location : public memento
@@ -341,6 +367,9 @@ public:
   }
 
 private:
+  string * make_debug_string ();
+
+private:
   string *m_filename;
   int m_line;
   int m_column;
@@ -352,6 +381,25 @@ public:
   type *get_pointer ();
   type *get_const ();
 
+  /* Get the type obtained when dereferencing this type.
+
+     This will return NULL if it's not valid to dereference this type.
+     The caller is responsible for setting an error.  */
+  virtual type *dereference () = 0;
+
+  /* Is it typesafe to copy to this type from rtype?  */
+  virtual bool accepts_writes_from (type *rtype)
+  {
+    return this == rtype;
+  }
+
+  /* Strip off "const" etc */
+  virtual type *unqualified ()
+  {
+    return this;
+  }
+
+
   playback::type *
   playback_type ()
   {
@@ -373,10 +421,28 @@ public:
   : type (ctxt),
     m_kind (kind) {}
 
+  type *dereference ();
+
+  bool accepts_writes_from (type *rtype)
+  {
+    if (m_kind == GCC_JIT_TYPE_VOID_PTR)
+      if (rtype->dereference ())
+	{
+	  /* LHS (this) is type (void *), and the RHS is a pointer:
+	     accept it:  */
+	  return true;
+	}
+
+    return type::accepts_writes_from (rtype);
+  }
+
 public:
   void replay_into (replayer *r);
 
 private:
+  string * make_debug_string ();
+
+private:
   enum gcc_jit_types m_kind;
 };
 
@@ -388,9 +454,14 @@ public:
   : type (other_type->m_ctxt),
     m_other_type (other_type) {}
 
+  type *dereference () { return m_other_type; }
+
   void replay_into (replayer *r);
 
 private:
+  string * make_debug_string ();
+
+private:
   type *m_other_type;
 };
 
@@ -402,9 +473,23 @@ public:
   : type (other_type->m_ctxt),
     m_other_type (other_type) {}
 
+  type *dereference () { return m_other_type->dereference (); }
+
+  bool accepts_writes_from (type */*rtype*/)
+  {
+    /* Can't write to a "const".  */
+    return false;
+  }
+
+  /* Strip off the "const", giving the underlying type.  */
+  type *unqualified () { return m_other_type; }
+
   void replay_into (replayer *);
 
 private:
+  string * make_debug_string ();
+
+private:
   type *m_other_type;
 };
 
@@ -418,9 +503,15 @@ public:
   : memento (ctxt),
     m_loc (loc),
     m_type (type),
-    m_name (name)
+    m_name (name),
+    m_container (NULL)
   {}
 
+  type * get_type () const { return m_type; }
+
+  struct_ * get_container () const { return m_container; }
+  void set_container (struct_ *c) { m_container = c; }
+
   void replay_into (replayer *);
 
   playback::field *
@@ -430,9 +521,13 @@ public:
   }
 
 private:
+  string * make_debug_string ();
+
+private:
   location *m_loc;
   type *m_type;
   string *m_name;
+  struct_ *m_container;
 };
 
 class struct_ : public type
@@ -441,16 +536,16 @@ public:
   struct_ (context *ctxt,
 	   location *loc,
 	   string *name,
-	   vec<field *> fields)
-  : type (ctxt),
-    m_loc (loc),
-    m_name (name),
-    m_fields (fields)
-  {}
+	   vec<field *> fields);
+
+  type *dereference ();
 
   void replay_into (replayer *r);
 
 private:
+  string * make_debug_string ();
+
+private:
   location *m_loc;
   string *m_name;
   vec<field *> m_fields;
@@ -460,10 +555,16 @@ class rvalue : public memento
 {
 public:
   rvalue (context *ctxt,
-	  location *loc)
+	  location *loc,
+	  type *type_)
   : memento (ctxt),
-    m_loc (loc)
-  {}
+    m_loc (loc),
+    m_type (type_)
+  {
+    gcc_assert (type_);
+  }
+
+  type * get_type () const { return m_type; }
 
   playback::rvalue *
   playback_rvalue () const
@@ -483,14 +584,16 @@ public:
 
 protected:
   location *m_loc;
+  type *m_type;
 };
 
 class lvalue : public rvalue
 {
 public:
   lvalue (context *ctxt,
-	  location *loc)
-    : rvalue (ctxt, loc)
+	  location *loc,
+	  type *type_)
+    : rvalue (ctxt, loc, type_)
     {}
 
   playback::lvalue *
@@ -517,8 +620,7 @@ public:
 	 location *loc,
 	 type *type,
 	 string *name)
-  : lvalue (ctxt, loc),
-    m_type (type),
+    : lvalue (ctxt, loc, type),
     m_name (name) {}
 
   lvalue *
@@ -533,7 +635,9 @@ public:
   }
 
 private:
-  type *m_type;
+  string * make_debug_string () { return m_name; }
+
+private:
   string *m_name;
 };
 
@@ -611,11 +715,15 @@ public:
   new_loop (location *loc,
 	    rvalue *boolval);
 
+  type *get_return_type () const { return m_return_type; }
   string * get_name () const { return m_name; }
   vec<param *> get_params () const { return m_params; }
   bool is_variadic () const { return m_is_variadic; }
 
 private:
+  string * make_debug_string ();
+
+private:
   location *m_loc;
   enum gcc_jit_function_kind m_kind;
   type *m_return_type;
@@ -643,6 +751,9 @@ public:
   }
 
 private:
+  string * make_debug_string ();
+
+private:
   function *m_func;
   string *m_name;
 };
@@ -654,15 +765,16 @@ public:
 	  location *loc,
 	  type *type,
 	  string *name)
-  : lvalue (ctxt, loc),
-    m_type (type),
+  : lvalue (ctxt, loc, type),
     m_name (name)
   {}
 
   void replay_into (replayer *);
 
 private:
-  type *m_type;
+  string * make_debug_string () { return m_name; }
+
+private:
   string *m_name;
 };
 
@@ -671,16 +783,17 @@ class memento_of_new_rvalue_from_int : public rvalue
 public:
   memento_of_new_rvalue_from_int (context *ctxt,
 				  location *loc,
-				  type *type,
+				  type *type_,
 				  int value)
-  : rvalue (ctxt, loc),
-    m_type (type),
+  : rvalue (ctxt, loc, type_),
     m_value (value) {}
 
   void replay_into (replayer *r);
 
 private:
-  type *m_type;
+  string * make_debug_string ();
+
+private:
   int m_value;
 };
 
@@ -689,17 +802,18 @@ class memento_of_new_rvalue_from_double : public rvalue
 public:
   memento_of_new_rvalue_from_double (context *ctxt,
 				     location *loc,
-				     type *type,
+				     type *type_,
 				     double value)
-  : rvalue (ctxt, loc),
-    m_type (type),
+  : rvalue (ctxt, loc, type_),
     m_value (value)
   {}
 
   void replay_into (replayer *);
 
 private:
-  type *m_type;
+  string * make_debug_string ();
+
+private:
   double m_value;
 };
 
@@ -708,17 +822,18 @@ class memento_of_new_rvalue_from_ptr : public rvalue
 public:
   memento_of_new_rvalue_from_ptr (context *ctxt,
 				  location *loc,
-				  type *type,
+				  type *type_,
 				  void *value)
-  : rvalue (ctxt, loc),
-    m_type (type),
+  : rvalue (ctxt, loc, type_),
     m_value (value)
   {}
 
   void replay_into (replayer *);
 
 private:
-  type *m_type;
+  string * make_debug_string ();
+
+private:
   void *m_value;
 };
 
@@ -728,12 +843,15 @@ public:
   memento_of_new_string_literal (context *ctxt,
 				 location *loc,
 				 string *value)
-  : rvalue (ctxt, loc),
+  : rvalue (ctxt, loc, ctxt->get_type (GCC_JIT_TYPE_CONST_CHAR_PTR)),
     m_value (value) {}
 
   void replay_into (replayer *r);
 
 private:
+  string * make_debug_string ();
+
+private:
   string *m_value;
 };
 
@@ -745,17 +863,18 @@ public:
 	    enum gcc_jit_unary_op op,
 	    type *result_type,
 	    rvalue *a)
-  : rvalue (ctxt, loc),
+  : rvalue (ctxt, loc, result_type),
     m_op (op),
-    m_result_type (result_type),
     m_a (a)
   {}
 
   void replay_into (replayer *r);
 
 private:
+  string * make_debug_string ();
+
+private:
   enum gcc_jit_unary_op m_op;
-  type *m_result_type;
   rvalue *m_a;
 };
 
@@ -767,17 +886,18 @@ public:
 	     enum gcc_jit_binary_op op,
 	     type *result_type,
 	     rvalue *a, rvalue *b)
-  : rvalue (ctxt, loc),
+  : rvalue (ctxt, loc, result_type),
     m_op (op),
-    m_result_type (result_type),
     m_a (a),
     m_b (b) {}
 
   void replay_into (replayer *r);
 
 private:
+  string * make_debug_string ();
+
+private:
   enum gcc_jit_binary_op m_op;
-  type *m_result_type;
   rvalue *m_a;
   rvalue *m_b;
 };
@@ -789,7 +909,7 @@ public:
 	      location *loc,
 	      enum gcc_jit_comparison op,
 	      rvalue *a, rvalue *b)
-  : rvalue (ctxt, loc),
+  : rvalue (ctxt, loc, ctxt->get_type (GCC_JIT_TYPE_INT)), /* FIXME: should be bool? */
     m_op (op),
     m_a (a),
     m_b (b)
@@ -798,6 +918,9 @@ public:
   void replay_into (replayer *r);
 
 private:
+  string * make_debug_string ();
+
+private:
   enum gcc_jit_comparison m_op;
   rvalue *m_a;
   rvalue *m_b;
@@ -815,6 +938,9 @@ public:
   void replay_into (replayer *r);
 
 private:
+  string * make_debug_string ();
+
+private:
   function *m_func;
   vec<rvalue *> m_args;
 };
@@ -826,7 +952,7 @@ public:
 		location *loc,
 		rvalue *ptr,
 		rvalue *index)
-  : rvalue (ctxt, loc),
+  : rvalue (ctxt, loc, ptr->get_type ()->dereference ()),
     m_ptr (ptr),
     m_index (index)
   {}
@@ -834,6 +960,9 @@ public:
   void replay_into (replayer *r);
 
 private:
+  string * make_debug_string ();
+
+private:
   rvalue *m_ptr;
   rvalue *m_index;
 };
@@ -845,7 +974,7 @@ public:
 			  location *loc,
 			  lvalue *val,
 			  field *field)
-  : lvalue (ctxt, loc),
+  : lvalue (ctxt, loc, field->get_type ()),
     m_lvalue (val),
     m_field (field)
   {}
@@ -853,6 +982,9 @@ public:
   void replay_into (replayer *r);
 
 private:
+  string * make_debug_string ();
+
+private:
   lvalue *m_lvalue;
   field *m_field;
 };
@@ -864,7 +996,7 @@ public:
 		       location *loc,
 		       rvalue *val,
 		       field *field)
-  : rvalue (ctxt, loc),
+  : rvalue (ctxt, loc, field->get_type ()),
     m_rvalue (val),
     m_field (field)
   {}
@@ -872,6 +1004,9 @@ public:
   void replay_into (replayer *r);
 
 private:
+  string * make_debug_string ();
+
+private:
   rvalue *m_rvalue;
   field *m_field;
 };
@@ -883,7 +1018,7 @@ public:
 			    location *loc,
 			    rvalue *val,
 			    field *field)
-  : lvalue (ctxt, loc),
+  : lvalue (ctxt, loc, field->get_type ()),
     m_rvalue (val),
     m_field (field)
   {}
@@ -891,6 +1026,9 @@ public:
   void replay_into (replayer *r);
 
 private:
+  string * make_debug_string ();
+
+private:
   rvalue *m_rvalue;
   field *m_field;
 };
@@ -901,12 +1039,15 @@ public:
   dereference_rvalue (context *ctxt,
 		      location *loc,
 		      rvalue *val)
-  : lvalue (ctxt, loc),
+  : lvalue (ctxt, loc, val->get_type ()->dereference ()),
     m_rvalue (val) {}
 
   void replay_into (replayer *r);
 
 private:
+  string * make_debug_string ();
+
+private:
   rvalue *m_rvalue;
 };
 
@@ -916,13 +1057,16 @@ public:
   get_address_of_lvalue (context *ctxt,
 			 location *loc,
 			 lvalue *val)
-  : rvalue (ctxt, loc),
+  : rvalue (ctxt, loc, val->get_type ()->get_pointer ()),
     m_lvalue (val)
   {}
 
   void replay_into (replayer *r);
 
 private:
+  string * make_debug_string ();
+
+private:
   lvalue *m_lvalue;
 };
 
@@ -930,16 +1074,17 @@ class local : public lvalue
 {
 public:
   local (function *func, location *loc, type *type_, string *name)
-  : lvalue (func->m_ctxt, loc),
+    : lvalue (func->m_ctxt, loc, type_),
     m_func (func),
-    m_type (type_),
     m_name (name) {}
 
   void replay_into (replayer *r);
 
 private:
+  string * make_debug_string () { return m_name; }
+
+private:
   function *m_func;
-  type *m_type;
   string *m_name;
 };
 
@@ -980,6 +1125,9 @@ public:
   void replay_into (replayer *r);
 
 private:
+  string * make_debug_string ();
+
+private:
   rvalue *m_rvalue;
 };
 
@@ -997,6 +1145,9 @@ public:
   void replay_into (replayer *r);
 
 private:
+  string * make_debug_string ();
+
+private:
   lvalue *m_lvalue;
   rvalue *m_rvalue;
 };
@@ -1017,6 +1168,9 @@ public:
   void replay_into (replayer *r);
 
 private:
+  string * make_debug_string ();
+
+private:
   lvalue *m_lvalue;
   enum gcc_jit_binary_op m_op;
   rvalue *m_rvalue;
@@ -1034,6 +1188,9 @@ public:
   void replay_into (replayer *r);
 
 private:
+  string * make_debug_string ();
+
+private:
   string *m_text;
 };
 
@@ -1053,6 +1210,9 @@ public:
   void replay_into (replayer *r);
 
 private:
+  string * make_debug_string ();
+
+private:
   rvalue *m_boolval;
   label *m_on_true;
   label *m_on_false;
@@ -1070,6 +1230,9 @@ public:
   void replay_into (replayer *r);
 
 private:
+  string * make_debug_string ();
+
+private:
   label *m_label;
 };
 
@@ -1085,6 +1248,9 @@ public:
   void replay_into (replayer *r);
 
 private:
+  string * make_debug_string ();
+
+private:
   label *m_target;
 };
 
@@ -1100,6 +1266,9 @@ public:
   void replay_into (replayer *r);
 
 private:
+  string * make_debug_string ();
+
+private:
   rvalue *m_rvalue;
 };
 
@@ -1125,6 +1294,9 @@ public:
   }
 
 private:
+  string * make_debug_string ();
+
+private:
   function *m_func;
   location *m_loc;
   rvalue *m_boolval;
@@ -1143,6 +1315,9 @@ public:
   void replay_into (replayer *r);
 
 private:
+  string * make_debug_string ();
+
+private:
   loop *m_loop;
   location *m_loc;
 };
diff --git a/gcc/jit/libgccjit.c b/gcc/jit/libgccjit.c
index ded581e..58037e1 100644
--- a/gcc/jit/libgccjit.c
+++ b/gcc/jit/libgccjit.c
@@ -76,9 +76,35 @@ struct gcc_jit_loop : public gcc::jit::recording::loop
       }								\
   JIT_END_STMT
 
+#define RETURN_VAL_IF_FAIL_PRINTF2(TEST_EXPR, RETURN_EXPR, CTXT, ERR_FMT, A0, A1) \
+  JIT_BEGIN_STMT							\
+    if (!(TEST_EXPR))							\
+      {								\
+	jit_error ((CTXT), "%s: " ERR_FMT,				\
+		   __func__, (A0), (A1));				\
+	return (RETURN_EXPR);						\
+      }								\
+  JIT_END_STMT
+
+#define RETURN_VAL_IF_FAIL_PRINTF3(TEST_EXPR, RETURN_EXPR, CTXT, ERR_FMT, A0, A1, A2) \
+  JIT_BEGIN_STMT							\
+    if (!(TEST_EXPR))							\
+      {								\
+	jit_error ((CTXT), "%s: " ERR_FMT,				\
+		   __func__, (A0), (A1), (A2));			\
+	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))
 
+#define RETURN_NULL_IF_FAIL_PRINTF2(TEST_EXPR, CTXT, ERR_FMT, A0, A1) \
+  RETURN_VAL_IF_FAIL_PRINTF2 (TEST_EXPR, NULL, CTXT, ERR_FMT, A0, A1)
+
+#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_IF_FAIL(TEST_EXPR, CTXT, ERR_MSG)			\
   JIT_BEGIN_STMT							\
     if (!(TEST_EXPR))							\
@@ -88,6 +114,16 @@ struct gcc_jit_loop : public gcc::jit::recording::loop
       }								\
   JIT_END_STMT
 
+#define RETURN_IF_FAIL_PRINTF4(TEST_EXPR, CTXT, ERR_FMT, A0, A1, A2, A3) \
+  JIT_BEGIN_STMT							\
+    if (!(TEST_EXPR))							\
+      {								\
+	jit_error ((CTXT), "%s: " ERR_FMT,				\
+		   __func__, (A0), (A1), (A2), (A3));			\
+	return;							\
+      }								\
+  JIT_END_STMT
+
 /* Check that FUNC is non-NULL, and that it's OK to add statements to
    it.  */
 #define RETURN_IF_NOT_FUNC_DEFINITION(FUNC) \
@@ -107,11 +143,11 @@ struct gcc_jit_loop : public gcc::jit::recording::loop
   JIT_END_STMT
 
 static void
-jit_error (gcc_jit_context *ctxt, const char *fmt, ...)
+jit_error (gcc::jit::recording::context *ctxt, const char *fmt, ...)
   GNU_PRINTF(2, 3);
 
 static void
-jit_error (gcc_jit_context *ctxt, const char *fmt, ...)
+jit_error (gcc::jit::recording::context *ctxt, const char *fmt, ...)
 {
   va_list ap;
   va_start (ap, fmt);
@@ -127,6 +163,13 @@ jit_error (gcc_jit_context *ctxt, const char *fmt, ...)
   va_end (ap);
 }
 
+static bool
+compatible_types (gcc::jit::recording::type *ltype,
+		  gcc::jit::recording::type *rtype)
+{
+  return ltype->accepts_writes_from (rtype);
+}
+
 gcc_jit_context *
 gcc_jit_context_acquire (void)
 {
@@ -210,7 +253,15 @@ gcc_jit_context_new_struct_type (gcc_jit_context *ctxt,
   if (num_fields)
     RETURN_NULL_IF_FAIL (fields, ctxt, "NULL fields ptr");
   for (int i = 0; i < num_fields; i++)
-    RETURN_NULL_IF_FAIL (fields[i], ctxt, "NULL field ptr");
+    {
+      RETURN_NULL_IF_FAIL (fields[i], ctxt, "NULL field ptr");
+      RETURN_NULL_IF_FAIL_PRINTF2 (
+	NULL == fields[i]->get_container (),
+	ctxt,
+	"%s is already a field of %s",
+	fields[i]->get_debug_string (),
+	fields[i]->get_container ()->get_debug_string ());
+    }
 
   return (gcc_jit_type *)ctxt->new_struct_type (loc, name, num_fields,
 						(gcc::jit::recording::field **)fields);
@@ -473,6 +524,21 @@ gcc_jit_rvalue_dereference_field (gcc_jit_rvalue *ptr,
 {
   RETURN_NULL_IF_FAIL (ptr, NULL, "NULL ptr");
   RETURN_NULL_IF_FAIL (field, NULL, "NULL field");
+  gcc::jit::recording::type *underlying_type =
+    ptr->get_type ()->dereference ();
+  RETURN_NULL_IF_FAIL_PRINTF3 (
+    underlying_type, ptr->m_ctxt,
+    "dereference of non-pointer %s (type: %s) when accessing ->%s",
+    ptr->get_debug_string (),
+    ptr->get_type ()->get_debug_string (),
+    field->get_debug_string ());
+  RETURN_NULL_IF_FAIL_PRINTF2 (
+    (field->get_container ()->unqualified ()
+     == underlying_type->unqualified ()),
+    ptr->m_ctxt,
+    "%s is not a field of %s",
+    field->get_debug_string (),
+    underlying_type->get_debug_string ());
 
   return (gcc_jit_lvalue *)ptr->dereference_field (loc, field);
 }
@@ -483,6 +549,15 @@ gcc_jit_rvalue_dereference (gcc_jit_rvalue *rvalue,
 {
   RETURN_NULL_IF_FAIL (rvalue, NULL, "NULL rvalue");
 
+  gcc::jit::recording::type *underlying_type =
+    rvalue->get_type ()->dereference ();
+
+  RETURN_NULL_IF_FAIL_PRINTF2 (
+    underlying_type, rvalue->m_ctxt,
+    "dereference of non-pointer %s (type: %s)",
+    rvalue->get_debug_string (),
+    rvalue->get_type ()->get_debug_string ());
+
   return (gcc_jit_lvalue *)rvalue->dereference (loc);
 }
 
@@ -551,8 +626,19 @@ gcc_jit_function_add_assignment (gcc_jit_function *func,
 				 gcc_jit_rvalue *rvalue)
 {
   RETURN_IF_NOT_FUNC_DEFINITION (func);
-  RETURN_IF_FAIL (lvalue, NULL, "NULL lvalue");
-  RETURN_IF_FAIL (rvalue, NULL, "NULL rvalue");
+  gcc::jit::recording::context *ctxt = func->m_ctxt;
+  RETURN_IF_FAIL (lvalue, ctxt, "NULL lvalue");
+  RETURN_IF_FAIL (rvalue, ctxt, "NULL rvalue");
+  RETURN_IF_FAIL_PRINTF4 (
+    compatible_types (lvalue->get_type (),
+		      rvalue->get_type ()),
+    ctxt,
+    "mismatching types:"
+    " assignment to %s (type: %s) from %s (type: %s)",
+    lvalue->get_debug_string (),
+    lvalue->get_type ()->get_debug_string (),
+    rvalue->get_debug_string (),
+    rvalue->get_type ()->get_debug_string ());
 
   return func->add_assignment (loc, lvalue, rvalue);
 }
@@ -615,7 +701,19 @@ gcc_jit_function_add_return (gcc_jit_function *func,
 			     gcc_jit_rvalue *rvalue)
 {
   RETURN_IF_NOT_FUNC_DEFINITION (func);
-  RETURN_IF_FAIL (rvalue, NULL, "NULL rvalue");
+  gcc::jit::recording::context *ctxt = func->m_ctxt;
+  RETURN_IF_FAIL (rvalue, ctxt, "NULL rvalue");
+  RETURN_IF_FAIL_PRINTF4 (
+    compatible_types (
+      func->get_return_type (),
+      rvalue->get_type ()),
+    ctxt,
+    "mismatching types:"
+    " return of %s (type: %s) in function %s (return type: %s)",
+    rvalue->get_debug_string (),
+    rvalue->get_type ()->get_debug_string (),
+    func->get_debug_string (),
+    func->get_return_type ()->get_debug_string ());
 
   return func->add_return (loc, rvalue);
 }
diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h
index 6a19b29..298b5dd 100644
--- a/gcc/jit/libgccjit.h
+++ b/gcc/jit/libgccjit.h
@@ -45,7 +45,8 @@ typedef struct gcc_jit_location gcc_jit_location;
 typedef struct gcc_jit_type gcc_jit_type;
 
 /* A gcc_jit_field encapsulates a field within a struct; it is used
-   when creating a struct type (using gcc_jit_context_new_struct_type).  */
+   when creating a struct type (using gcc_jit_context_new_struct_type).
+   Fields cannot be shared between structs.  */
 typedef struct gcc_jit_field gcc_jit_field;
 
 /* A gcc_jit_function encapsulates a function: either one that you're
@@ -481,7 +482,7 @@ enum gcc_jit_binary_op
   GCC_JIT_BINARY_OP_DIVIDE,
 
   /* Remainder of division of arithmetic values; analogous to:
-       (EXPR_A) / (EXPR_B)
+       (EXPR_A) % (EXPR_B)
      in C.  */
   GCC_JIT_BINARY_OP_MODULO,
 
diff --git a/gcc/testsuite/ChangeLog.jit b/gcc/testsuite/ChangeLog.jit
index a225efd..bd20f8c 100644
--- a/gcc/testsuite/ChangeLog.jit
+++ b/gcc/testsuite/ChangeLog.jit
@@ -1,3 +1,12 @@
+2014-01-30  David Malcolm  <dmalcolm@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.
+	* jit.dg/test-error-dereference-read-of-non-pointer.c: Likewise.
+	* jit.dg/test-error-mismatching-types-in-assignment.c: Likewise.
+	* jit.dg/test-error-return-within-void-function.c: Likewise.
+
 2014-01-29  David Malcolm  <dmalcolm@redhat.com>
 
 	* jit.dg/test-accessing-struct.c (create_code): Update for API change
diff --git a/gcc/testsuite/jit.dg/test-error-accessing-field-in-other-struct.c b/gcc/testsuite/jit.dg/test-error-accessing-field-in-other-struct.c
new file mode 100644
index 0000000..6789195
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-error-accessing-field-in-other-struct.c
@@ -0,0 +1,113 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+struct foo
+{
+  int x;
+  int y;
+};
+
+struct bar
+{
+  int p;
+  int q;
+};
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to inject the equivalent of:
+     void
+     test_bogus_access (struct foo *f)
+     {
+        f->p = f->q;
+     }
+     i.e. using the wrong struct.
+  */
+  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);
+
+  /* Map "struct foo".  */
+  gcc_jit_field *x =
+    gcc_jit_context_new_field (ctxt,
+                               NULL,
+                               int_type,
+                               "x");
+  gcc_jit_field *y =
+    gcc_jit_context_new_field (ctxt,
+                               NULL,
+                               int_type,
+                               "y");
+  gcc_jit_field *foo_fields[] = {x, y};
+  gcc_jit_type *struct_foo =
+    gcc_jit_context_new_struct_type (ctxt, NULL, "foo", 2, foo_fields);
+
+  /* Map "struct bar".  */
+  gcc_jit_field *p =
+    gcc_jit_context_new_field (ctxt,
+                               NULL,
+                               int_type,
+                               "p");
+  gcc_jit_field *q =
+    gcc_jit_context_new_field (ctxt,
+                               NULL,
+                               int_type,
+                               "q");
+  /* We don't actually need a gcc_jit_type for "struct bar" for the test.  */
+#if 0
+  gcc_jit_field *bar_fields[] = {p, q};
+  gcc_jit_type *struct_bar =
+    gcc_jit_context_new_struct_type (ctxt, NULL, "foo", 2, bar_fields);
+#endif
+
+  gcc_jit_type *foo_ptr = gcc_jit_type_get_pointer (struct_foo);
+
+  /* Build the test function.  */
+  gcc_jit_param *param_f =
+    gcc_jit_context_new_param (ctxt, NULL, foo_ptr, "f");
+  gcc_jit_function *test_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                  GCC_JIT_FUNCTION_EXPORTED,
+                                  void_type,
+                                  "test_bogus_access",
+                                  1, &param_f,
+                                  0);
+
+  /* Erroneous: f->p = ... */
+  gcc_jit_lvalue *lvalue =
+    gcc_jit_rvalue_dereference_field (
+      gcc_jit_param_as_rvalue (param_f),
+      NULL,
+      p);
+
+  /* Erroneous: ... = f->q; */
+  gcc_jit_rvalue *rvalue =
+    gcc_jit_lvalue_as_rvalue (
+      gcc_jit_rvalue_dereference_field (
+	gcc_jit_param_as_rvalue (param_f),
+	NULL,
+	q));
+
+  gcc_jit_function_add_assignment (
+    test_fn,
+    NULL,
+    lvalue, rvalue);
+}
+
+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_rvalue_dereference_field:"
+		      " p is not a field of struct foo");
+}
+
diff --git a/gcc/testsuite/jit.dg/test-error-dereference-field-of-non-pointer.c b/gcc/testsuite/jit.dg/test-error-dereference-field-of-non-pointer.c
new file mode 100644
index 0000000..e69ca8d
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-error-dereference-field-of-non-pointer.c
@@ -0,0 +1,89 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+struct foo
+{
+  int x;
+  int y;
+};
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to inject the equivalent of:
+     void
+     test_bogus_dereference ()
+     {
+        struct foo tmp;
+        tmp->x = tmp->y;
+     }
+     i.e. where tmp is *not* a pointer.
+  */
+  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);
+
+  /* Map "struct foo".  */
+  gcc_jit_field *x =
+    gcc_jit_context_new_field (ctxt,
+                               NULL,
+                               int_type,
+                               "x");
+  gcc_jit_field *y =
+    gcc_jit_context_new_field (ctxt,
+                               NULL,
+                               int_type,
+                               "y");
+  gcc_jit_field *foo_fields[] = {x, y};
+  gcc_jit_type *struct_foo =
+    gcc_jit_context_new_struct_type (ctxt, NULL, "foo", 2, foo_fields);
+
+  /* Build the test function.  */
+  gcc_jit_function *test_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                  GCC_JIT_FUNCTION_EXPORTED,
+                                  void_type,
+                                  "test_bogus_dereference",
+                                  0, NULL,
+                                  0);
+  gcc_jit_lvalue *tmp =
+    gcc_jit_function_new_local (test_fn, NULL, struct_foo, "tmp");
+
+  /* Erroneous: tmp->x = ... */
+  gcc_jit_lvalue *lvalue =
+    gcc_jit_rvalue_dereference_field (
+      gcc_jit_lvalue_as_rvalue (tmp),
+      NULL,
+      x);
+
+  /* Erroneous: ... = tmp->y; */
+  gcc_jit_rvalue *rvalue =
+    gcc_jit_lvalue_as_rvalue (
+      gcc_jit_rvalue_dereference_field (
+	gcc_jit_lvalue_as_rvalue (tmp),
+	NULL,
+	y));
+
+  gcc_jit_function_add_assignment (
+    test_fn,
+    NULL,
+    lvalue, rvalue);
+}
+
+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_rvalue_dereference_field:"
+		       " dereference of non-pointer tmp (type: struct foo)"
+		       " when accessing ->x"));
+}
+
diff --git a/gcc/testsuite/jit.dg/test-error-dereference-read-of-non-pointer.c b/gcc/testsuite/jit.dg/test-error-dereference-read-of-non-pointer.c
new file mode 100644
index 0000000..c9ae40d
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-error-dereference-read-of-non-pointer.c
@@ -0,0 +1,54 @@
+#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:
+       void
+       int test_bogus_dereference_read (int i)
+       {
+	 return *i;
+       }
+     i.e. where i is *not* a pointer.
+  */
+  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);
+
+  /* Build the test function.  */
+  gcc_jit_param *param_i =
+      gcc_jit_context_new_param (ctxt, NULL, int_type, "i");
+  gcc_jit_function *test_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                  GCC_JIT_FUNCTION_EXPORTED,
+                                  void_type,
+                                  "test_bogus_dereference_read",
+                                  1, &param_i,
+                                  0);
+  /* Erroneous: "return *i;" */
+  gcc_jit_function_add_return (
+    test_fn,
+    NULL,
+    gcc_jit_lvalue_as_rvalue (
+      gcc_jit_rvalue_dereference (
+        gcc_jit_param_as_rvalue (param_i),
+	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_rvalue_dereference:"
+		       " dereference of non-pointer i (type: int)"));
+}
+
diff --git a/gcc/testsuite/jit.dg/test-error-mismatching-types-in-assignment.c b/gcc/testsuite/jit.dg/test-error-mismatching-types-in-assignment.c
new file mode 100644
index 0000000..58b1650
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-error-mismatching-types-in-assignment.c
@@ -0,0 +1,58 @@
+#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:
+
+     void
+     test_fn ()
+     {
+        int i;
+        i = "this is not an int";
+     }
+
+     and verify that the API complains about the mismatching types
+     in the assignment.
+  */
+  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_function *test_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                  GCC_JIT_FUNCTION_EXPORTED,
+                                  void_type,
+                                  "test_fn",
+                                  0, NULL,
+                                  0);
+  gcc_jit_lvalue *i =
+    gcc_jit_function_new_local (
+      test_fn, NULL, int_type, "i");
+
+  gcc_jit_function_add_assignment (
+    test_fn, NULL,
+    i, /* of type int */
+    gcc_jit_context_new_string_literal (
+      ctxt, "this is not an int"));
+}
+
+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_function_add_assignment:"
+		      " mismatching types:"
+		      " assignment to i (type: int)"
+		      " from \"this is not an int\" (type: const char *)");
+}
+
diff --git a/gcc/testsuite/jit.dg/test-error-return-within-void-function.c b/gcc/testsuite/jit.dg/test-error-return-within-void-function.c
new file mode 100644
index 0000000..3abc188
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-error-return-within-void-function.c
@@ -0,0 +1,52 @@
+#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:
+     void
+     test_fn ()
+     {
+        return 42;
+     }
+
+     and verify that the API complains about the return
+     of a value within a function with "void" return.
+  */
+  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_function *test_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                  GCC_JIT_FUNCTION_EXPORTED,
+                                  void_type, /* "void" return */
+                                  "test_fn",
+                                  0, NULL,
+                                  0);
+  /* "return 42;"  (i.e. non-void) */
+  gcc_jit_function_add_return (
+    test_fn, NULL,
+    gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 42));
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  /* Ensure that the "return 42" leads to the API giving a NULL
+     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_function_add_return:"
+		      " mismatching types: return of (int)42 (type: int)"
+		      " in function test_fn (return type: void)");
+}
+
-- 
1.7.11.7



More information about the Gcc-patches mailing list