diff mbox

[jit] Support self-referential data structures (API changes).

Message ID 1392758602-21252-1-git-send-email-dmalcolm@redhat.com
State New
Headers show

Commit Message

David Malcolm Feb. 18, 2014, 9:23 p.m. UTC
Committed to branch dmalcolm/jit:

New API type:
  - gcc_jit_struct

New API entrypoints:
  - gcc_jit_context_new_opaque_struct
  - gcc_jit_struct_as_type
  - gcc_jit_struct_set_fields
  - gcc_jit_context_null: get the NULL value for a pointer type.

Changed API entrypoint:
  - gcc_jit_context_new_struct_type: changed return type from
    (gcc_jit_type *) to (gcc_jit_struct *).

Internally, split out populating the fields of a struct from the creation
of said struct.

Also, require conditionals to be of boolean type (so that conversions must,
for now, be explicit), since the implicit behavior of passing in a pointer
didn't match that of C.

gcc/jit/
	* libgccjit.h (gcc_jit_struct): New.
	(gcc_jit_context_new_struct_type): Change return type from gcc_jit_type
	to gcc_jit_struct.
	(gcc_jit_context_new_opaque_struct): New.
	(gcc_jit_struct_as_type): New.
	(gcc_jit_struct_set_fields): New.
	(gcc_jit_context_null): New.

	* libgccjit.map (gcc_jit_context_new_opaque_struct): New.
	(gcc_jit_context_null): New.
	(gcc_jit_struct_as_type): New.
	(gcc_jit_struct_set_fields): New.

	* libgccjit++.h (gccjit::context::new_struct_type): Return a
	struct_ rather than a type.
	(gccjit::context::new_opaque_struct_type): New.
	(gccjit::struct_): New subclass of type.

	* libgccjit.c (gcc_jit_struct): New.
	(RETURN_VAL_IF_FAIL_PRINTF1): New.
	(RETURN_VAL_IF_FAIL_PRINTF2): New.
	(RETURN_NULL_IF_FAIL_PRINTF1): New.
	(RETURN_IF_FAIL_PRINTF1): New.
	(RETURN_IF_FAIL_PRINTF2): New.
	(gcc_jit_context_new_struct_type): Return a gcc_jit_struct rather
	than a gcc_jit_type; implement by creating the struct, then
	setting the fields in it.
	(gcc_jit_context_new_opaque_struct): New.
	(gcc_jit_struct_as_type): New.
	(gcc_jit_struct_set_fields): New.
	(gcc_jit_context_null): New.
	(gcc_jit_lvalue_access_field): Use the struct's context when
	reporting on a NULL field; verify that the field has been placed
	in a struct.
	(gcc_jit_rvalue_access_field): Likewise.
	(is_bool): New.
	(gcc_jit_function_add_conditional): Use the function's context
	when reporting errors; verify that boolval's type is indeed
	boolean.
	(gcc_jit_function_new_loop): Likewise.

	* internal-api.h (gcc::jit::recording::context::new_struct_type):
	Don't accept fields, and return a struct_ rather than a type_, so
	that fields can be set later.
	(gcc::jit::recording::struct_::struct_): Store a (fields *) rather
	than a vec of fields.
	(gcc::jit::recording::struct_::as_type): New.
	(gcc::jit::recording::struct_::get_fields): New.
	(gcc::jit::recording::struct_::set_fields): New.
	(gcc::jit::recording::struct_::playback_struct): New.
	(gcc::jit::recording::fields): New class.
	(gcc::jit::playback::context::new_struct_type): Don't accept
	fields, and return a struct_ rather than a type_, so that fields
	can be set later.
	(gcc::jit::playback::struct_): New subclass of type.

	* internal-api.c (gcc::jit::recording::context::get_type): With
	nested contexts, create basic types within the ultimate parent
	context, allowing for a fast check for the boolean type using
	pointer equality.
	(gcc::jit::recording::context::new_struct_type): Don't accept
	fields, and return a struct_ rather than a type_, so that fields
	can be set later.
	(gcc::jit::recording::context::get_opaque_FILE_type): Update for
	struct-creation changes.
	(gcc::jit::recording::struct_::struct_): Store a (fields *) rather
	than a vec of fields.
	(gcc::jit::recording::struct_::set_fields): New.
	(gcc::jit::recording::struct_::replay_into): Don't playback the
	fields, as this is now done by a fields instance.
	(gcc::jit::recording::fields::fields): New.
	(gcc::jit::recording::fields::replay_into): New.
	(gcc::jit::recording::fields::make_debug_string): New.
	(gcc::jit:: playback::context::new_struct_type): Don't accept
	fields, and return a struct_ rather than a type_, so that fields
	can be set later.
	(gcc::jit::playback::struct_::set_fields): New.

	* TODO.rst: Update.

gcc/testsuite/
	* jit.dg/test-accessing-struct.c (create_code): Update for change to
	return type of gcc_jit_context_new_struct_type.
	* jit.dg/test-arrays.c (create_code): Likewise.
	* jit.dg/test-error-accessing-field-in-other-struct.c (create_code):
	Likewise.
	* jit.dg/test-error-dereference-field-of-non-pointer.c (create_code):
	Likewise.
	* jit.dg/test-fuzzer.c (make_random_type): Likewise.
	* jit.dg/test-nested-contexts.c (make_types): Likewise.
	* jit.dg/test-quadratic.c (make_types): Likewise.
	* jit.dg/test-reading-struct.c (create_code): Likewise.
	* jit.dg/test-types.c (create_code): Likewise.

	* jit.dg/test-linked-list.c: New selftest, exercising
	gcc_jit_context_new_opaque_struct, gcc_jit_type_get_pointer, and
	gcc_jit_context_null.
	* jit.dg/test-combination.c: Add test-linked-list.c
---
 gcc/jit/ChangeLog.jit                              |  82 ++++++++++++
 gcc/jit/TODO.rst                                   |  24 +---
 gcc/jit/internal-api.c                             | 120 +++++++++++------
 gcc/jit/internal-api.h                             |  61 +++++++--
 gcc/jit/libgccjit++.h                              |  55 ++++++--
 gcc/jit/libgccjit.c                                | 143 +++++++++++++++++++--
 gcc/jit/libgccjit.h                                |  27 +++-
 gcc/jit/libgccjit.map                              |   4 +
 gcc/testsuite/ChangeLog.jit                        |  20 +++
 gcc/testsuite/jit.dg/test-accessing-struct.c       |   5 +-
 gcc/testsuite/jit.dg/test-arrays.c                 |   4 +-
 gcc/testsuite/jit.dg/test-combination.c            |   9 ++
 .../test-error-accessing-field-in-other-struct.c   |   7 +-
 .../test-error-dereference-field-of-non-pointer.c  |   6 +-
 gcc/testsuite/jit.dg/test-fuzzer.c                 |   4 +-
 gcc/testsuite/jit.dg/test-linked-list.c            | 133 +++++++++++++++++++
 gcc/testsuite/jit.dg/test-nested-contexts.c        |   5 +-
 gcc/testsuite/jit.dg/test-quadratic.c              |   5 +-
 gcc/testsuite/jit.dg/test-reading-struct.c         |   3 +-
 gcc/testsuite/jit.dg/test-types.c                  |  13 +-
 20 files changed, 617 insertions(+), 113 deletions(-)
 create mode 100644 gcc/testsuite/jit.dg/test-linked-list.c
diff mbox

Patch

diff --git a/gcc/jit/ChangeLog.jit b/gcc/jit/ChangeLog.jit
index b0e12b1..860bee6 100644
--- a/gcc/jit/ChangeLog.jit
+++ b/gcc/jit/ChangeLog.jit
@@ -1,5 +1,87 @@ 
 2014-02-18  David Malcolm  <dmalcolm@redhat.com>
 
+	* libgccjit.h (gcc_jit_struct): New.
+	(gcc_jit_context_new_struct_type): Change return type from gcc_jit_type
+	to gcc_jit_struct.
+	(gcc_jit_context_new_opaque_struct): New.
+	(gcc_jit_struct_as_type): New.
+	(gcc_jit_struct_set_fields): New.
+	(gcc_jit_context_null): New.
+
+	* libgccjit.map (gcc_jit_context_new_opaque_struct): New.
+	(gcc_jit_context_null): New.
+	(gcc_jit_struct_as_type): New.
+	(gcc_jit_struct_set_fields): New.
+
+	* libgccjit++.h (gccjit::context::new_struct_type): Return a
+	struct_ rather than a type.
+	(gccjit::context::new_opaque_struct_type): New.
+	(gccjit::struct_): New subclass of type.
+
+	* libgccjit.c (gcc_jit_struct): New.
+	(RETURN_VAL_IF_FAIL_PRINTF1): New.
+	(RETURN_VAL_IF_FAIL_PRINTF2): New.
+	(RETURN_NULL_IF_FAIL_PRINTF1): New.
+	(RETURN_IF_FAIL_PRINTF1): New.
+	(RETURN_IF_FAIL_PRINTF2): New.
+	(gcc_jit_context_new_struct_type): Return a gcc_jit_struct rather
+	than a gcc_jit_type; implement by creating the struct, then
+	setting the fields in it.
+	(gcc_jit_context_new_opaque_struct): New.
+	(gcc_jit_struct_as_type): New.
+	(gcc_jit_struct_set_fields): New.
+	(gcc_jit_context_null): New.
+	(gcc_jit_lvalue_access_field): Use the struct's context when
+	reporting on a NULL field; verify that the field has been placed
+	in a struct.
+	(gcc_jit_rvalue_access_field): Likewise.
+	(is_bool): New.
+	(gcc_jit_function_add_conditional): Use the function's context
+	when reporting errors; verify that boolval's type is indeed
+	boolean.
+	(gcc_jit_function_new_loop): Likewise.
+
+	* internal-api.h (gcc::jit::recording::context::new_struct_type):
+	Don't accept fields, and return a struct_ rather than a type_, so
+	that fields can be set later.
+	(gcc::jit::recording::struct_::struct_): Store a (fields *) rather
+	than a vec of fields.
+	(gcc::jit::recording::struct_::as_type): New.
+	(gcc::jit::recording::struct_::get_fields): New.
+	(gcc::jit::recording::struct_::set_fields): New.
+	(gcc::jit::recording::struct_::playback_struct): New.
+	(gcc::jit::recording::fields): New class.
+	(gcc::jit::playback::context::new_struct_type): Don't accept
+	fields, and return a struct_ rather than a type_, so that fields
+	can be set later.
+	(gcc::jit::playback::struct_): New subclass of type.
+
+	* internal-api.c (gcc::jit::recording::context::get_type): With
+	nested contexts, create basic types within the ultimate parent
+	context, allowing for a fast check for the boolean type using
+	pointer equality.
+	(gcc::jit::recording::context::new_struct_type): Don't accept
+	fields, and return a struct_ rather than a type_, so that fields
+	can be set later.
+	(gcc::jit::recording::context::get_opaque_FILE_type): Update for
+	struct-creation changes.
+	(gcc::jit::recording::struct_::struct_): Store a (fields *) rather
+	than a vec of fields.
+	(gcc::jit::recording::struct_::set_fields): New.
+	(gcc::jit::recording::struct_::replay_into): Don't playback the
+	fields, as this is now done by a fields instance.
+	(gcc::jit::recording::fields::fields): New.
+	(gcc::jit::recording::fields::replay_into): New.
+	(gcc::jit::recording::fields::make_debug_string): New.
+	(gcc::jit:: playback::context::new_struct_type): Don't accept
+	fields, and return a struct_ rather than a type_, so that fields
+	can be set later.
+	(gcc::jit::playback::struct_::set_fields): New.
+
+	* TODO.rst: Update.
+
+2014-02-18  David Malcolm  <dmalcolm@redhat.com>
+
 	* libgccjit.c (gcc_jit_function_new_local): Use the context of the
 	function when reporting errors.
 	(gcc_jit_function_place_forward_label): Likewise.
diff --git a/gcc/jit/TODO.rst b/gcc/jit/TODO.rst
index c149dde..7288aef 100644
--- a/gcc/jit/TODO.rst
+++ b/gcc/jit/TODO.rst
@@ -18,23 +18,6 @@  Initial Release
   * more types:
     * unions
     * function ptrs
-    * explicitly opaque structs, perhaps:
-
-        extern gcc_jit_type *
-        gcc_jit_context_new_opaque_struct (gcc_jit_context *ctxt,
-                                           const char *name);
-
-    * ability to create self-referential structs, or cycles in the graph:
-
-         struct foo { struct bar *m_bar; }
-         struct bar { struct foo *m_foo; }
-
-    * get int type with given number of either bits or bytes:
-
-        extern gcc_jit_type *
-        gcc_jit_context_get_int_type (gcc_jit_context *ctxt,
-                                      int num_bytes,
-                                      int is_signed);
 
   * ability to bind a pre-existing global variable
 
@@ -109,13 +92,12 @@  Initial Release
 
     * gcc_jit_context_new_rvalue_from_int: must be a numeric type
 
-    * gcc_jit_context_zero: must be a numeric type.  If we do this should
-      we introduce a gcc_jit_context_null for pointer types?  (you can do
-      this via gcc_jit_context_new_rvalue_from_ptr, but having an explicit
-      hook is friendlier).
+    * gcc_jit_context_zero: must be a numeric type
 
     * gcc_jit_context_one: must be a numeric type
 
+    * gcc_jit_context_null: must be a pointer 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
diff --git a/gcc/jit/internal-api.c b/gcc/jit/internal-api.c
index dacb55d..37fe70b 100644
--- a/gcc/jit/internal-api.c
+++ b/gcc/jit/internal-api.c
@@ -211,9 +211,15 @@  recording::context::get_type (enum gcc_jit_types kind)
      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;
+      /* For basic types, use them from the parent ctxt.  */
+      if (m_parent_ctxt)
+	m_basic_types[kind] = m_parent_ctxt->get_type (kind);
+      else
+	{
+	  recording::type *result = new memento_of_get_type (this, kind);
+	  record (result);
+	  m_basic_types[kind] = result;
+	}
     }
 
   return m_basic_types[kind];
@@ -278,18 +284,11 @@  recording::context::new_field (recording::location *loc,
   return result;
 }
 
-recording::type *
+recording::struct_ *
 recording::context::new_struct_type (recording::location *loc,
-				     const char *name,
-				     int num_fields,
-				     field **fields)
+				     const char *name)
 {
-  vec<field *> vec_fields;
-  vec_fields.create (num_fields);
-  for (int i = 0; i < num_fields; i++)
-    vec_fields.safe_push (fields[i]);
-  recording::type *result = new struct_ (this, loc, new_string (name),
-			      vec_fields);
+  recording::struct_ *result = new struct_ (this, loc, new_string (name));
   record (result);
   return result;
 }
@@ -545,7 +544,7 @@  recording::type *
 recording::context::get_opaque_FILE_type ()
 {
   if (!m_FILE_type)
-    m_FILE_type = new_struct_type (NULL, "FILE", 0, NULL);
+    m_FILE_type = new_struct_type (NULL, "FILE");
   return m_FILE_type;
 }
 
@@ -918,19 +917,24 @@  recording::field::make_debug_string ()
 /* gcc::jit::recording::struct_:: */
 recording::struct_::struct_ (context *ctxt,
 			     location *loc,
-			     string *name,
-			     vec<field *> fields)
+			     string *name)
 : type (ctxt),
   m_loc (loc),
   m_name (name),
-  m_fields (fields)
+  m_fields (NULL)
 {
-  /* 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);
-    }
+}
+
+void
+recording::struct_::set_fields (location *loc,
+				int num_fields,
+				field **field_array)
+{
+  m_loc = loc;
+  gcc_assert (NULL == m_fields);
+
+  m_fields = new fields (this, num_fields, field_array);
+  m_ctxt->record (m_fields);
 }
 
 recording::type *
@@ -942,15 +946,9 @@  recording::struct_::dereference ()
 void
 recording::struct_::replay_into (replayer *r)
 {
-  vec<playback::field *> playback_fields;
-  playback_fields.create (m_fields.length ());
-  for (unsigned i = 0; i < m_fields.length (); i++)
-    playback_fields.safe_push (m_fields[i]->playback_field ());
-
   set_playback_obj (
     r->new_struct_type (playback_location (m_loc),
-			m_name->c_str (),
-			&playback_fields));
+			m_name->c_str ()));
 }
 
 recording::string *
@@ -960,6 +958,39 @@  recording::struct_::make_debug_string ()
 			      "struct %s", m_name->c_str ());
 }
 
+/* gcc::jit::recording::fields:: */
+recording::fields::fields (struct_ *struct_,
+			   int num_fields,
+			   field **fields)
+: memento (struct_->m_ctxt),
+  m_struct (struct_),
+  m_fields ()
+{
+  for (int i = 0; i < num_fields; i++)
+    {
+      gcc_assert (fields[i]->get_container () == NULL);
+      fields[i]->set_container (m_struct);
+      m_fields.safe_push (fields[i]);
+    }
+}
+
+void
+recording::fields::replay_into (replayer *)
+{
+  vec<playback::field *> playback_fields;
+  playback_fields.create (m_fields.length ());
+  for (unsigned i = 0; i < m_fields.length (); i++)
+    playback_fields.safe_push (m_fields[i]->playback_field ());
+  m_struct->playback_struct ()->set_fields (playback_fields);
+}
+
+recording::string *
+recording::fields::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "fields");
+}
+
 /* gcc::jit::recording::rvalue:: */
 
 recording::rvalue *
@@ -1937,25 +1968,35 @@  new_field (location *loc,
   return new field (decl);
 }
 
-playback::type *
+playback::struct_ *
 playback::context::
 new_struct_type (location *loc,
-		 const char *name,
-		 vec<field *> *fields)
+		 const char *name)
 {
   gcc_assert (name);
-  gcc_assert (fields);
 
-  /* Compare with c/c-decl.c: start_struct and finish_struct. */
+  /* Compare with c/c-decl.c: start_struct. */
 
   tree t = make_node (RECORD_TYPE);
   TYPE_NAME (t) = get_identifier (name);
   TYPE_SIZE (t) = 0;
 
+  if (loc)
+    set_tree_location (t, loc);
+
+  return new struct_ (t);
+}
+
+void
+playback::struct_::set_fields (const vec<playback::field *> &fields)
+{
+  /* Compare with c/c-decl.c: finish_struct. */
+  tree t = as_tree ();
+
   tree fieldlist = NULL;
-  for (unsigned i = 0; i < fields->length (); i++)
+  for (unsigned i = 0; i < fields.length (); i++)
     {
-      field *f = (*fields)[i];
+      field *f = fields[i];
       DECL_CONTEXT (f->as_tree ()) = t;
       fieldlist = chainon (f->as_tree (), fieldlist);
     }
@@ -1963,11 +2004,6 @@  new_struct_type (location *loc,
   TYPE_FIELDS (t) = fieldlist;
 
   layout_type (t);
-
-  if (loc)
-    set_tree_location (t, loc);
-
-  return new type (t);
 }
 
 playback::type *
diff --git a/gcc/jit/internal-api.h b/gcc/jit/internal-api.h
index 45ab9ea..1be192e 100644
--- a/gcc/jit/internal-api.h
+++ b/gcc/jit/internal-api.h
@@ -85,6 +85,7 @@  namespace recording {
   class function_type;
   class field;
   class struct_;
+  class fields;
   class function;
   class label;
   class rvalue;
@@ -98,6 +99,7 @@  namespace playback {
   class location;
   class type;
   class field;
+  class struct_;
   class function;
   class label;
   class rvalue;
@@ -160,12 +162,9 @@  public:
 	     type *type,
 	     const char *name);
 
-  type *
+  struct_ *
   new_struct_type (location *loc,
-		   const char *name,
-		   int num_fields,
-		   field **fields);
-
+		   const char *name);
 
   param *
   new_param (location *loc,
@@ -619,19 +618,52 @@  class struct_ : public type
 public:
   struct_ (context *ctxt,
 	   location *loc,
-	   string *name,
-	   vec<field *> fields);
+	   string *name);
+
+  type *
+  as_type () { return this; }
+
+  fields * get_fields () { return m_fields; }
+
+  void
+  set_fields (location *loc,
+	      int num_fields,
+	      field **fields);
 
   type *dereference ();
 
   void replay_into (replayer *r);
 
+  playback::struct_ *
+  playback_struct ()
+  {
+    return static_cast <playback::struct_ *> (m_playback_obj);
+  }
+
 private:
   string * make_debug_string ();
 
 private:
   location *m_loc;
   string *m_name;
+  fields *m_fields;
+};
+
+// memento of struct_::set_fields
+class fields : public memento
+{
+public:
+  fields (struct_ *struct_,
+	  int num_fields,
+	  field **fields);
+
+  void replay_into (replayer *r);
+
+private:
+  string * make_debug_string ();
+
+private:
+  struct_ *m_struct;
   vec<field *> m_fields;
 };
 
@@ -1481,10 +1513,9 @@  public:
 	     type *type,
 	     const char *name);
 
-  type *
+  struct_ *
   new_struct_type (location *loc,
-		   const char *name,
-		   vec<field *> *fields);
+		   const char *name);
 
   type *
   new_function_type (type *return_type,
@@ -1682,6 +1713,16 @@  private:
   tree m_inner;
 };
 
+class struct_ : public type
+{
+public:
+  struct_ (tree inner)
+    : type (inner)
+  {}
+
+  void set_fields (const vec<field *> &fields);
+};
+
 class field : public wrapper
 {
 public:
diff --git a/gcc/jit/libgccjit++.h b/gcc/jit/libgccjit++.h
index a718d0c..63f8610 100644
--- a/gcc/jit/libgccjit++.h
+++ b/gcc/jit/libgccjit++.h
@@ -19,6 +19,7 @@  namespace gccjit
   class location;
   class field;
   class type;
+  class struct_;
   class param;
   class function;
   class label;
@@ -97,9 +98,12 @@  namespace gccjit
     field new_field (type type_, const std::string &name,
 		     location loc = location ());
 
-    type new_struct_type (const std::string &name,
-			  std::vector<field> &fields,
-			  location loc = location ());
+    struct_ new_struct_type (const std::string &name,
+			     std::vector<field> &fields,
+			     location loc = location ());
+
+    struct_ new_opaque_struct_type (const std::string &name,
+				    location loc = location ());
 
     param new_param (type type_,
 		     const std::string &name,
@@ -264,6 +268,15 @@  namespace gccjit
     rvalue one ();
  };
 
+  class struct_ : public type
+  {
+  public:
+    struct_ ();
+    struct_ (gcc_jit_struct *inner);
+
+    gcc_jit_struct *get_inner_struct () const;
+  };
+
   class function : public object
   {
   public:
@@ -525,7 +538,7 @@  context::new_field (type type_, const std::string &name, location loc)
 					   name.c_str ()));
 }
 
-inline type
+inline struct_
 context::new_struct_type (const std::string &name,
 			  std::vector<field> &fields,
 			  location loc)
@@ -538,11 +551,21 @@  context::new_struct_type (const std::string &name,
   gcc_jit_field **as_array_of_ptrs =
     reinterpret_cast<gcc_jit_field **> (as_array_of_wrappers);
 
-  return type (gcc_jit_context_new_struct_type (m_inner_ctxt,
-						loc.get_inner_location (),
-						name.c_str (),
-						fields.size (),
-						as_array_of_ptrs));
+  return struct_ (gcc_jit_context_new_struct_type (m_inner_ctxt,
+						   loc.get_inner_location (),
+						   name.c_str (),
+						   fields.size (),
+						   as_array_of_ptrs));
+}
+
+inline struct_
+context::new_opaque_struct_type (const std::string &name,
+				 location loc)
+{
+  return struct_ (gcc_jit_context_new_opaque_struct (
+		    m_inner_ctxt,
+		    loc.get_inner_location (),
+		    name.c_str ()));
 }
 
 inline param
@@ -1020,6 +1043,20 @@  type::one ()
   return get_context ().new_rvalue (*this, 1);
 }
 
+// class struct_
+inline struct_::struct_ () : type (NULL) {}
+inline struct_::struct_ (gcc_jit_struct *inner) :
+  type (gcc_jit_struct_as_type (inner))
+{
+}
+
+inline gcc_jit_struct *
+struct_::get_inner_struct () const
+{
+  /* Manual downcast: */
+  return reinterpret_cast<gcc_jit_struct *> (get_inner_object ());
+}
+
 // class function
 inline function::function () : object (NULL) {}
 inline function::function (gcc_jit_function *inner)
diff --git a/gcc/jit/libgccjit.c b/gcc/jit/libgccjit.c
index b5b3968..d089ad5 100644
--- a/gcc/jit/libgccjit.c
+++ b/gcc/jit/libgccjit.c
@@ -44,6 +44,10 @@  struct gcc_jit_type : public gcc::jit::recording::type
 {
 };
 
+struct gcc_jit_struct : public gcc::jit::recording::struct_
+{
+};
+
 struct gcc_jit_field : public gcc::jit::recording::field
 {
 };
@@ -93,6 +97,16 @@  struct gcc_jit_loop : public gcc::jit::recording::loop
       }								\
   JIT_END_STMT
 
+#define RETURN_VAL_IF_FAIL_PRINTF1(TEST_EXPR, RETURN_EXPR, CTXT, ERR_FMT, A0) \
+  JIT_BEGIN_STMT							\
+    if (!(TEST_EXPR))							\
+      {								\
+	jit_error ((CTXT), "%s: " ERR_FMT,				\
+		   __func__, (A0));				\
+	return (RETURN_EXPR);						\
+      }								\
+  JIT_END_STMT
+
 #define RETURN_VAL_IF_FAIL_PRINTF2(TEST_EXPR, RETURN_EXPR, CTXT, ERR_FMT, A0, A1) \
   JIT_BEGIN_STMT							\
     if (!(TEST_EXPR))							\
@@ -136,6 +150,9 @@  struct gcc_jit_loop : public gcc::jit::recording::loop
 #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_PRINTF1(TEST_EXPR, CTXT, ERR_FMT, A0) \
+  RETURN_VAL_IF_FAIL_PRINTF1 (TEST_EXPR, NULL, CTXT, ERR_FMT, A0)
+
 #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)
 
@@ -157,6 +174,26 @@  struct gcc_jit_loop : public gcc::jit::recording::loop
       }								\
   JIT_END_STMT
 
+#define RETURN_IF_FAIL_PRINTF1(TEST_EXPR, CTXT, ERR_FMT, A0) \
+  JIT_BEGIN_STMT							\
+    if (!(TEST_EXPR))							\
+      {								\
+	jit_error ((CTXT), "%s: " ERR_FMT,				\
+		   __func__, (A0));					\
+	return;							\
+      }								\
+  JIT_END_STMT
+
+#define RETURN_IF_FAIL_PRINTF2(TEST_EXPR, CTXT, ERR_FMT, A0, A1) \
+  JIT_BEGIN_STMT							\
+    if (!(TEST_EXPR))							\
+      {								\
+	jit_error ((CTXT), "%s: " ERR_FMT,				\
+		   __func__, (A0), (A1));				\
+	return;							\
+      }								\
+  JIT_END_STMT
+
 #define RETURN_IF_FAIL_PRINTF4(TEST_EXPR, CTXT, ERR_FMT, A0, A1, A2, A3) \
   JIT_BEGIN_STMT							\
     if (!(TEST_EXPR))							\
@@ -330,7 +367,7 @@  gcc_jit_field_as_object (gcc_jit_field *field)
   return static_cast <gcc_jit_object *> (field->as_object ());
 }
 
-gcc_jit_type *
+gcc_jit_struct *
 gcc_jit_context_new_struct_type (gcc_jit_context *ctxt,
 				 gcc_jit_location *loc,
 				 const char *name,
@@ -352,10 +389,61 @@  gcc_jit_context_new_struct_type (gcc_jit_context *ctxt,
 	fields[i]->get_container ()->get_debug_string ());
     }
 
-  return (gcc_jit_type *)ctxt->new_struct_type (loc, name, num_fields,
-						(gcc::jit::recording::field **)fields);
+  gcc::jit::recording::struct_ *result =
+    ctxt->new_struct_type (loc, name);
+  result->set_fields (loc,
+		      num_fields,
+		      (gcc::jit::recording::field **)fields);
+  return static_cast<gcc_jit_struct *> (result);
+}
+
+gcc_jit_struct *
+gcc_jit_context_new_opaque_struct (gcc_jit_context *ctxt,
+				   gcc_jit_location *loc,
+				   const char *name)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, "NULL context");
+  RETURN_NULL_IF_FAIL (name, ctxt, "NULL name");
+
+  return (gcc_jit_struct *)ctxt->new_struct_type (loc, name);
 }
 
+gcc_jit_type *
+gcc_jit_struct_as_type (gcc_jit_struct *struct_type)
+{
+  RETURN_NULL_IF_FAIL (struct_type, NULL, "NULL struct_type");
+
+  return static_cast <gcc_jit_type *> (struct_type->as_type ());
+}
+
+void
+gcc_jit_struct_set_fields (gcc_jit_struct *struct_type,
+			   gcc_jit_location *loc,
+			   int num_fields,
+			   gcc_jit_field **fields)
+{
+  RETURN_IF_FAIL (struct_type, NULL, "NULL struct_type");
+  gcc::jit::recording::context *ctxt = struct_type->m_ctxt;
+  RETURN_IF_FAIL_PRINTF1 (
+    NULL == struct_type->get_fields (), ctxt,
+    "%s already has had fields set",
+    struct_type->get_debug_string ());
+  if (num_fields)
+    RETURN_IF_FAIL (fields, ctxt, "NULL fields ptr");
+  for (int i = 0; i < num_fields; i++)
+    {
+      RETURN_IF_FAIL (fields[i], ctxt, "NULL field ptr");
+      RETURN_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 ());
+    }
+
+  struct_type->set_fields (loc, num_fields,
+			   (gcc::jit::recording::field **)fields);
+}
 
 /* Constructing functions.  */
 gcc_jit_param *
@@ -597,6 +685,16 @@  gcc_jit_context_new_rvalue_from_ptr (gcc_jit_context *ctxt,
 }
 
 gcc_jit_rvalue *
+gcc_jit_context_null (gcc_jit_context *ctxt,
+		      gcc_jit_type *pointer_type)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, "NULL context");
+  RETURN_NULL_IF_FAIL (pointer_type, ctxt, "NULL type");
+
+  return gcc_jit_context_new_rvalue_from_ptr (ctxt, pointer_type, NULL);
+}
+
+gcc_jit_rvalue *
 gcc_jit_context_new_string_literal (gcc_jit_context *ctxt,
 				    const char *value)
 {
@@ -751,7 +849,11 @@  gcc_jit_lvalue_access_field (gcc_jit_lvalue *struct_,
 			     gcc_jit_field *field)
 {
   RETURN_NULL_IF_FAIL (struct_, NULL, "NULL struct");
-  RETURN_NULL_IF_FAIL (field, NULL, "NULL field");
+  gcc::jit::recording::context *ctxt = struct_->m_ctxt;
+  RETURN_NULL_IF_FAIL (field, ctxt, "NULL field");
+  RETURN_NULL_IF_FAIL_PRINTF1 (field->get_container (), field->m_ctxt,
+			       "field %s has not been placed in a struct",
+			       field->get_debug_string ());
 
   return (gcc_jit_lvalue *)struct_->access_field (loc, field);
 }
@@ -762,7 +864,11 @@  gcc_jit_rvalue_access_field (gcc_jit_rvalue *struct_,
 			     gcc_jit_field *field)
 {
   RETURN_NULL_IF_FAIL (struct_, NULL, "NULL struct");
-  RETURN_NULL_IF_FAIL (field, NULL, "NULL field");
+  gcc::jit::recording::context *ctxt = struct_->m_ctxt;
+  RETURN_NULL_IF_FAIL (field, ctxt, "NULL field");
+  RETURN_NULL_IF_FAIL_PRINTF1 (field->get_container (), field->m_ctxt,
+			       "field %s has not been placed in a struct",
+			       field->get_debug_string ());
 
   return (gcc_jit_rvalue *)struct_->access_field (loc, field);
 }
@@ -912,6 +1018,15 @@  gcc_jit_function_add_assignment_op (gcc_jit_function *func,
   return func->add_assignment_op (loc, lvalue, op, rvalue);
 }
 
+static bool
+is_bool (gcc_jit_rvalue *boolval)
+{
+  gcc::jit::recording::type *actual_type = boolval->get_type ();
+  gcc::jit::recording::type *bool_type =
+    boolval->m_ctxt->get_type (GCC_JIT_TYPE_BOOL);
+  return actual_type == bool_type;
+}
+
 void
 gcc_jit_function_add_conditional (gcc_jit_function *func,
 				  gcc_jit_location *loc,
@@ -920,8 +1035,14 @@  gcc_jit_function_add_conditional (gcc_jit_function *func,
 				  gcc_jit_label *on_false)
 {
   RETURN_IF_NOT_FUNC_DEFINITION (func);
-  RETURN_IF_FAIL (boolval, NULL, "NULL boolval");
-  RETURN_IF_FAIL (on_true, NULL, "NULL on_true");
+  gcc::jit::recording::context *ctxt = func->m_ctxt;
+  RETURN_IF_FAIL (boolval, ctxt, "NULL boolval");
+  RETURN_IF_FAIL_PRINTF2 (
+   is_bool (boolval), ctxt,
+   "%s (type: %s) is not of boolean type ",
+   boolval->get_debug_string (),
+   boolval->get_type ()->get_debug_string ());
+  RETURN_IF_FAIL (on_true, ctxt, "NULL on_true");
   /* on_false can be NULL */
 
   return func->add_conditional (loc, boolval, on_true, on_false);
@@ -980,7 +1101,13 @@  gcc_jit_function_new_loop (gcc_jit_function *func,
 			   gcc_jit_rvalue *boolval)
 {
   RETURN_NULL_IF_NOT_FUNC_DEFINITION (func);
-  RETURN_NULL_IF_FAIL (boolval, NULL, "NULL boolval");
+  gcc::jit::recording::context *ctxt = func->m_ctxt;
+  RETURN_NULL_IF_FAIL (boolval, ctxt, "NULL boolval");
+  RETURN_NULL_IF_FAIL_PRINTF2 (
+   is_bool (boolval), ctxt,
+   "%s (type: %s) is not of boolean type ",
+   boolval->get_debug_string (),
+   boolval->get_type ()->get_debug_string ());
 
   return (gcc_jit_loop *)func->new_loop (loc, boolval, NULL, NULL);
 }
diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h
index 3751bdd..3ea6653 100644
--- a/gcc/jit/libgccjit.h
+++ b/gcc/jit/libgccjit.h
@@ -36,6 +36,7 @@  typedef struct gcc_jit_result gcc_jit_result;
      +- gcc_jit_object
          +- gcc_jit_location
          +- gcc_jit_type
+	    +- gcc_jit_struct
          +- gcc_jit_field
          +- gcc_jit_function
          +- gcc_jit_label
@@ -67,6 +68,10 @@  typedef struct gcc_jit_type gcc_jit_type;
    Fields cannot be shared between structs.  */
 typedef struct gcc_jit_field gcc_jit_field;
 
+/* A gcc_jit_struct encapsulates a struct type, either one that we have
+   the layout for, or an opaque type.  */
+typedef struct gcc_jit_struct gcc_jit_struct;
+
 /* A gcc_jit_function encapsulates a function: either one that you're
    creating yourself, or a reference to one that you're dynamically
    linking to within the rest of the process.  */
@@ -385,13 +390,29 @@  gcc_jit_context_new_field (gcc_jit_context *ctxt,
 extern gcc_jit_object *
 gcc_jit_field_as_object (gcc_jit_field *field);
 
-extern gcc_jit_type *
+extern gcc_jit_struct *
 gcc_jit_context_new_struct_type (gcc_jit_context *ctxt,
 				 gcc_jit_location *loc,
 				 const char *name,
 				 int num_fields,
 				 gcc_jit_field **fields);
 
+extern gcc_jit_struct *
+gcc_jit_context_new_opaque_struct (gcc_jit_context *ctxt,
+				   gcc_jit_location *loc,
+				   const char *name);
+
+extern gcc_jit_type *
+gcc_jit_struct_as_type (gcc_jit_struct *struct_type);
+
+/* Populating the fields of a formerly-opaque struct type.
+   This can only be called once on a given struct type.  */
+extern void
+gcc_jit_struct_set_fields (gcc_jit_struct *struct_type,
+			   gcc_jit_location *loc,
+			   int num_fields,
+			   gcc_jit_field **fields);
+
 /**********************************************************************
  Constructing functions.
  **********************************************************************/
@@ -511,6 +532,10 @@  gcc_jit_context_new_rvalue_from_ptr (gcc_jit_context *ctxt,
 				     gcc_jit_type *pointer_type,
 				     void *value);
 
+extern gcc_jit_rvalue *
+gcc_jit_context_null (gcc_jit_context *ctxt,
+		      gcc_jit_type *pointer_type);
+
 /* String literals. */
 extern gcc_jit_rvalue *
 gcc_jit_context_new_string_literal (gcc_jit_context *ctxt,
diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map
index 6dde3a1..fbdca38 100644
--- a/gcc/jit/libgccjit.map
+++ b/gcc/jit/libgccjit.map
@@ -18,6 +18,7 @@ 
     gcc_jit_context_new_function;
     gcc_jit_context_new_global;
     gcc_jit_context_new_location;
+    gcc_jit_context_new_opaque_struct;
     gcc_jit_context_new_param;
     gcc_jit_context_new_rvalue_from_double;
     gcc_jit_context_new_rvalue_from_int;
@@ -25,6 +26,7 @@ 
     gcc_jit_context_new_string_literal;
     gcc_jit_context_new_struct_type;
     gcc_jit_context_new_unary_op;
+    gcc_jit_context_null;
     gcc_jit_context_one;
     gcc_jit_context_release;
     gcc_jit_context_set_bool_option;
@@ -67,6 +69,8 @@ 
     gcc_jit_rvalue_dereference;
     gcc_jit_rvalue_dereference_field;
     gcc_jit_rvalue_get_type;
+    gcc_jit_struct_as_type;
+    gcc_jit_struct_set_fields;
     gcc_jit_type_as_object;
     gcc_jit_type_get_const;
     gcc_jit_type_get_pointer;
diff --git a/gcc/testsuite/ChangeLog.jit b/gcc/testsuite/ChangeLog.jit
index ec1d76a..0299115 100644
--- a/gcc/testsuite/ChangeLog.jit
+++ b/gcc/testsuite/ChangeLog.jit
@@ -1,3 +1,23 @@ 
+2014-02-18  David Malcolm  <dmalcolm@redhat.com>
+
+	* jit.dg/test-accessing-struct.c (create_code): Update for change to
+	return type of gcc_jit_context_new_struct_type.
+	* jit.dg/test-arrays.c (create_code): Likewise.
+	* jit.dg/test-error-accessing-field-in-other-struct.c (create_code):
+	Likewise.
+	* jit.dg/test-error-dereference-field-of-non-pointer.c (create_code):
+	Likewise.
+	* jit.dg/test-fuzzer.c (make_random_type): Likewise.
+	* jit.dg/test-nested-contexts.c (make_types): Likewise.
+	* jit.dg/test-quadratic.c (make_types): Likewise.
+	* jit.dg/test-reading-struct.c (create_code): Likewise.
+	* jit.dg/test-types.c (create_code): Likewise.
+
+	* jit.dg/test-linked-list.c: New selftest, exercising
+	gcc_jit_context_new_opaque_struct, gcc_jit_type_get_pointer, and
+	gcc_jit_context_null.
+	* jit.dg/test-combination.c: Add test-linked-list.c
+
 2014-02-14  David Malcolm  <dmalcolm@redhat.com>
 
 	* jit.dg/test-operator-overloading.cc (make_test_quadratic): Use
diff --git a/gcc/testsuite/jit.dg/test-accessing-struct.c b/gcc/testsuite/jit.dg/test-accessing-struct.c
index b28adeb..eb4ecca 100644
--- a/gcc/testsuite/jit.dg/test-accessing-struct.c
+++ b/gcc/testsuite/jit.dg/test-accessing-struct.c
@@ -42,9 +42,10 @@  create_code (gcc_jit_context *ctxt, void *user_data)
                                int_type,
                                "z");
   gcc_jit_field *fields[] = {x, y, z};
-  gcc_jit_type *struct_type =
+  gcc_jit_struct *struct_type =
     gcc_jit_context_new_struct_type (ctxt, NULL, "foo", 3, fields);
-  gcc_jit_type *ptr_type = gcc_jit_type_get_pointer (struct_type);
+  gcc_jit_type *ptr_type =
+    gcc_jit_type_get_pointer (gcc_jit_struct_as_type (struct_type));
 
   /* Build the test function.  */
   gcc_jit_param *param_f =
diff --git a/gcc/testsuite/jit.dg/test-arrays.c b/gcc/testsuite/jit.dg/test-arrays.c
index 2cff561..12ea77e 100644
--- a/gcc/testsuite/jit.dg/test-arrays.c
+++ b/gcc/testsuite/jit.dg/test-arrays.c
@@ -53,7 +53,7 @@  create_code (gcc_jit_context *ctxt, void *user_data)
     field_m_after,
   };
 
-  gcc_jit_type *struct_type =
+  gcc_jit_struct *struct_type =
     gcc_jit_context_new_struct_type (
       ctxt,
       NULL,
@@ -61,7 +61,7 @@  create_code (gcc_jit_context *ctxt, void *user_data)
       3, fields);
 
   gcc_jit_type *struct_ptr_type =
-    gcc_jit_type_get_pointer (struct_type);
+    gcc_jit_type_get_pointer (gcc_jit_struct_as_type (struct_type));
 
   /* Build the test_fn.  */
   gcc_jit_param *param_ah =
diff --git a/gcc/testsuite/jit.dg/test-combination.c b/gcc/testsuite/jit.dg/test-combination.c
index 7fc07ab..cd8a0f3 100644
--- a/gcc/testsuite/jit.dg/test-combination.c
+++ b/gcc/testsuite/jit.dg/test-combination.c
@@ -66,6 +66,13 @@ 
 #undef create_code
 #undef verify_code
 
+/* test-linked-list.c */
+#define create_code create_code_linked_list
+#define verify_code verify_code_linked_list
+#include "test-linked-list.c"
+#undef create_code
+#undef verify_code
+
 /* test-quadratic.c */
 #define create_code create_code_quadratic
 #define verify_code verify_code_quadratic
@@ -127,6 +134,7 @@  create_code (gcc_jit_context *ctxt, void * user_data)
   create_code_fibonacci (ctxt, user_data);
   create_code_functions (ctxt, user_data);
   create_code_hello_world (ctxt, user_data);
+  create_code_linked_list (ctxt, user_data);
   create_code_string_literal (ctxt, user_data);
   create_code_sum_of_squares (ctxt, user_data);
   create_code_types (ctxt, user_data);
@@ -144,6 +152,7 @@  verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
   verify_code_fibonacci (ctxt, result);
   verify_code_functions (ctxt, result);
   verify_code_hello_world (ctxt, result);
+  verify_code_linked_list (ctxt, result);
   verify_code_string_literal (ctxt, result);
   verify_code_sum_of_squares (ctxt, result);
   verify_code_types (ctxt, result);
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
index 6789195..1cc2cb6 100644
--- 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
@@ -45,7 +45,7 @@  create_code (gcc_jit_context *ctxt, void *user_data)
                                int_type,
                                "y");
   gcc_jit_field *foo_fields[] = {x, y};
-  gcc_jit_type *struct_foo =
+  gcc_jit_struct *struct_foo =
     gcc_jit_context_new_struct_type (ctxt, NULL, "foo", 2, foo_fields);
 
   /* Map "struct bar".  */
@@ -62,11 +62,12 @@  create_code (gcc_jit_context *ctxt, void *user_data)
   /* 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_struct *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);
+  gcc_jit_type *foo_ptr =
+    gcc_jit_type_get_pointer (gcc_jit_struct_as_type (struct_foo));
 
   /* Build the test function.  */
   gcc_jit_param *param_f =
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
index e69ca8d..287498d 100644
--- 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
@@ -40,7 +40,7 @@  create_code (gcc_jit_context *ctxt, void *user_data)
                                int_type,
                                "y");
   gcc_jit_field *foo_fields[] = {x, y};
-  gcc_jit_type *struct_foo =
+  gcc_jit_struct *struct_foo =
     gcc_jit_context_new_struct_type (ctxt, NULL, "foo", 2, foo_fields);
 
   /* Build the test function.  */
@@ -52,7 +52,9 @@  create_code (gcc_jit_context *ctxt, void *user_data)
                                   0, NULL,
                                   0);
   gcc_jit_lvalue *tmp =
-    gcc_jit_function_new_local (test_fn, NULL, struct_foo, "tmp");
+    gcc_jit_function_new_local (test_fn, NULL,
+				gcc_jit_struct_as_type (struct_foo),
+				"tmp");
 
   /* Erroneous: tmp->x = ... */
   gcc_jit_lvalue *lvalue =
diff --git a/gcc/testsuite/jit.dg/test-fuzzer.c b/gcc/testsuite/jit.dg/test-fuzzer.c
index 7fbb5a2..11c1db5 100644
--- a/gcc/testsuite/jit.dg/test-fuzzer.c
+++ b/gcc/testsuite/jit.dg/test-fuzzer.c
@@ -212,14 +212,14 @@  make_random_type (fuzzer *f)
 	  }
 	char struct_name[256];
 	sprintf (struct_name, "s%i", f->num_types);
-	gcc_jit_type *struct_ = \
+	gcc_jit_struct *struct_ = \
 	  gcc_jit_context_new_struct_type (f->ctxt,
 					   get_random_location (f),
 					   struct_name,
 					   num_fields,
 					   fields);
 	free (fields);
-	return struct_;
+	return gcc_jit_struct_as_type (struct_);
       }
     }
 }
diff --git a/gcc/testsuite/jit.dg/test-linked-list.c b/gcc/testsuite/jit.dg/test-linked-list.c
new file mode 100644
index 0000000..b925b9e
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-linked-list.c
@@ -0,0 +1,133 @@ 
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+/* A doubly-linked list, to ensure that the JIT API can cope with
+   self-referential types.  */
+struct node
+{
+  struct node *prev;
+  struct node *next;
+  int value;
+};
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to inject the equivalent of:
+     int
+     test_linked_list (struct node *n)
+     {
+	int total = 0;
+	while (n)
+	  {
+	    total += n->value;
+	    n = n->next;
+	  }
+	return total;
+     }
+  */
+  gcc_jit_type *t_int =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+  gcc_jit_struct *t_node =
+    gcc_jit_context_new_opaque_struct (ctxt, NULL, "node");
+  gcc_jit_type *t_node_ptr =
+    gcc_jit_type_get_pointer (gcc_jit_struct_as_type (t_node));
+
+  gcc_jit_field *f_prev =
+    gcc_jit_context_new_field (ctxt, NULL, t_node_ptr, "prev");
+  gcc_jit_field *f_next =
+    gcc_jit_context_new_field (ctxt, NULL, t_node_ptr, "next");
+  gcc_jit_field *f_value =
+    gcc_jit_context_new_field (ctxt, NULL, t_int, "value");
+  gcc_jit_field *fields[] = {f_prev, f_next, f_value};
+  gcc_jit_struct_set_fields (t_node, NULL, 3, fields);
+
+  /* Build the test function.  */
+  gcc_jit_param *param_n =
+    gcc_jit_context_new_param (ctxt, NULL, t_node_ptr, "n");
+  gcc_jit_function *fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+				  GCC_JIT_FUNCTION_EXPORTED,
+				  t_int,
+				  "test_linked_list",
+				  1, &param_n,
+				  0);
+  /* int total; */
+  gcc_jit_lvalue *total =
+    gcc_jit_function_new_local (fn, NULL, t_int, "total");
+
+  /* total = 0; */
+  gcc_jit_function_add_assignment (
+    fn, NULL,
+    total,
+    gcc_jit_context_zero (ctxt, t_int));
+
+  /* while (n) */
+  gcc_jit_loop *loop =
+    gcc_jit_function_new_loop (
+      fn, NULL,
+      gcc_jit_context_new_comparison (ctxt, NULL,
+				      GCC_JIT_COMPARISON_NE,
+				      gcc_jit_param_as_rvalue (param_n),
+				      gcc_jit_context_null (ctxt, t_node_ptr)));
+
+  /* total += n->value; */
+  gcc_jit_function_add_assignment_op (
+    fn, NULL,
+    total,
+    GCC_JIT_BINARY_OP_PLUS,
+    gcc_jit_lvalue_as_rvalue (
+      gcc_jit_rvalue_dereference_field (
+	gcc_jit_param_as_rvalue (param_n),
+	NULL,
+	f_value)));
+
+  /* n = n->next; */
+  gcc_jit_function_add_assignment (
+    fn, NULL,
+    gcc_jit_param_as_lvalue (param_n),
+    gcc_jit_lvalue_as_rvalue (
+      gcc_jit_rvalue_dereference_field (
+	gcc_jit_param_as_rvalue (param_n),
+	NULL,
+	f_next)));
+
+  gcc_jit_loop_end (loop, NULL);
+
+  /* return total; */
+  gcc_jit_function_add_return (fn, NULL, gcc_jit_lvalue_as_rvalue (total));
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  struct node a, b, c;
+  typedef int (*fn_type) (struct node *n);
+  CHECK_NON_NULL (result);
+
+  fn_type test_linked_list =
+    (fn_type)gcc_jit_result_get_code (result, "test_linked_list");
+  CHECK_NON_NULL (test_linked_list);
+
+  /* Construct a simple linked-list on the stack: a->b->c: */
+  a.prev = NULL;
+  a.next = &b;
+  a.value = 5;
+
+  b.prev = &a;
+  b.next = &c;
+  b.value = 3;
+
+  c.prev = &b;
+  c.next = NULL;
+  c.value = 7;
+
+  CHECK_VALUE (test_linked_list (NULL), 0);
+  CHECK_VALUE (test_linked_list (&a), 15);
+  CHECK_VALUE (test_linked_list (&b), 10);
+  CHECK_VALUE (test_linked_list (&c), 7);
+}
diff --git a/gcc/testsuite/jit.dg/test-nested-contexts.c b/gcc/testsuite/jit.dg/test-nested-contexts.c
index eaedd75..d24a859 100644
--- a/gcc/testsuite/jit.dg/test-nested-contexts.c
+++ b/gcc/testsuite/jit.dg/test-nested-contexts.c
@@ -136,8 +136,9 @@  make_types (struct top_level *top_level)
 			     top_level->c,
 			     top_level->discriminant};
   top_level->struct_quadratic =
-    gcc_jit_context_new_struct_type (top_level->ctxt, NULL,
-				     "quadratic", 4, fields);
+    gcc_jit_struct_as_type (
+      gcc_jit_context_new_struct_type (top_level->ctxt, NULL,
+				       "quadratic", 4, fields));
   top_level->quadratic_ptr =
     gcc_jit_type_get_pointer (top_level->struct_quadratic);
 }
diff --git a/gcc/testsuite/jit.dg/test-quadratic.c b/gcc/testsuite/jit.dg/test-quadratic.c
index 9b02c06..337bea5 100644
--- a/gcc/testsuite/jit.dg/test-quadratic.c
+++ b/gcc/testsuite/jit.dg/test-quadratic.c
@@ -115,8 +115,9 @@  make_types (struct quadratic_test *testcase)
 			     testcase->c,
 			     testcase->discriminant};
   testcase->quadratic =
-    gcc_jit_context_new_struct_type (testcase->ctxt, NULL,
-				     "quadratic", 4, fields);
+    gcc_jit_struct_as_type (
+      gcc_jit_context_new_struct_type (testcase->ctxt, NULL,
+				       "quadratic", 4, fields));
   testcase->quadratic_ptr = gcc_jit_type_get_pointer (testcase->quadratic);
 }
 
diff --git a/gcc/testsuite/jit.dg/test-reading-struct.c b/gcc/testsuite/jit.dg/test-reading-struct.c
index fd53f84..4214320 100644
--- a/gcc/testsuite/jit.dg/test-reading-struct.c
+++ b/gcc/testsuite/jit.dg/test-reading-struct.c
@@ -45,7 +45,8 @@  create_code (gcc_jit_context *ctxt, void *user_data)
                                "y");
   gcc_jit_field *fields[] = {x, y};
   gcc_jit_type *struct_type =
-    gcc_jit_context_new_struct_type (ctxt, NULL, "bar", 2, fields);
+    gcc_jit_struct_as_type (
+      gcc_jit_context_new_struct_type (ctxt, NULL, "bar", 2, fields));
   gcc_jit_type *const_struct_type = gcc_jit_type_get_const (struct_type);
   gcc_jit_type *ptr_type = gcc_jit_type_get_pointer (const_struct_type);
 
diff --git a/gcc/testsuite/jit.dg/test-types.c b/gcc/testsuite/jit.dg/test-types.c
index f6fc1b2..575176f 100644
--- a/gcc/testsuite/jit.dg/test-types.c
+++ b/gcc/testsuite/jit.dg/test-types.c
@@ -161,12 +161,13 @@  create_code (gcc_jit_context *ctxt, void *user_data)
   };
 
   gcc_jit_type *zoo_type =
-    gcc_jit_context_new_struct_type (
-      ctxt,
-      NULL,
-      "zoo",
-      sizeof (zoo_fields) / sizeof (zoo_fields[0]),
-      zoo_fields);
+    gcc_jit_struct_as_type (
+      gcc_jit_context_new_struct_type (
+        ctxt,
+	NULL,
+	"zoo",
+	sizeof (zoo_fields) / sizeof (zoo_fields[0]),
+	zoo_fields));
 
   gcc_jit_type *zoo_ptr_type =
     gcc_jit_type_get_pointer (zoo_type);