Pushed to branch dmalcolm/jit:

This adds a new API entrypoint:

  gcc_jit_context_new_union_type

gcc/jit/
        * libgccjit.h (gcc_jit_context_new_union_type): New entrypoint.
        (gcc_jit_lvalue_access_field): Rename first param from "struct_"
        to "struct_or_union".
        (gcc_jit_rvalue_access_field): Likewise.

        * libgccjit.c (gcc_jit_context_new_union_type): New entrypoint.

        * libgccjit.map (gcc_jit_context_new_union_type): New entrypoint.

        * internal-api.h (gcc::jit::recording::compound_type): New class
        (gcc::jit::recording::union): New class.
        (gcc::jit::playback::struct_): Rename this class to...
        (gcc::jit::playback::compound_type): ...this.
        (gcc::jit::recording::context::new_union_type): New method.
        (gcc::jit::recording::context): Rename field "m_structs" to
        "m_compound_types", generalizing from a vec <struct_ *> to a
        vec<compound_type *>.
        (gcc::jit::recording::field): Update field m_container from
        struct * to container_type *.
        (gcc::jit::recording::field::get_container): Generalize from
        struct_ * to container_type *.
        (gcc::jit::recording::field::set_container): Likewise.
        (gcc::jit::recording::compound_type): New subclass of type, to
        be a superclass of existing class struct_ and new class union_.
        (gcc::jit::recording::struct_::get_name): Move to...
        (gcc::jit::recording::compound_type::get_name): ...here.
        (gcc::jit::recording::struct_::get_loc): Move to...
        (gcc::jit::recording::compound_type::get_loc): ...here.
        (gcc::jit::recording::struct_::set_fields): Move to...
        (gcc::jit::recording::compound_type::set_fields): ...here.
        (gcc::jit::recording::struct_::dereference): Move to...
        (gcc::jit::recording::compound_type::dereference): ...here.
        (gcc::jit::recording::struct_::is_int): Move to...
        (gcc::jit::recording::compound_type::is_int): ...here.
        (gcc::jit::recording::struct_::is_float): Move to...
        (gcc::jit::recording::compound_type::is_float): ...here.
        (gcc::jit::recording::struct_::is_bool): Move to...
        (gcc::jit::recording::compound_type::is_bool): ...here.
        (gcc::jit::recording::struct_::is_pointer): Move to...
        (gcc::jit::recording::compound_type::is_pointer): ...here.
        (gcc::jit::recording::struct_::is_array): Move to...
        (gcc::jit::recording::compound_type::is_array): ...here.
        (gcc::jit::recording::struct_::playback_struct): Move to...
        (gcc::jit::recording::compound_type::playback_compound_type):
        ...here, renaming and updating return type.
        (gcc::jit::recording::struct_): Inherit from compound_type,
        rather than just type.
        (gcc::jit::recording::fields): Update to work on compound_type *
        rather than struct_ *, renaming "m_struct" to "m_struct_or_union".
        (gcc::jit::recording::union): New subclass of compound_type.
        (gcc::jit::playback::context::new_struct_type): Generalize by
        renaming to...
        (gcc::jit::playback::context::new_compound_type): ...this, and
        and an "is_struct" bool param.
        (gcc::jit::playback::struct_): Generalize by renaming class to...
        (gcc::jit::playback::compound_type): ...this.

        * internal-api.c (gcc::jit::recording::context::context): Rename
        field "m_structs" to "m_compound_types".
        (gcc::jit::recording::context::new_struct_type): Likewise.
        (gcc::jit::recording::context::new_union_type): New method.
        (gcc::jit::recording::context::dump_to_file): Field "m_structs"
        is renamed "m_compound_types" and changes type from struct_ *
        to compound_type *.
        (gcc::jit::recording::compound_type::compound_type): New ctor,
        built from old body of gcc::jit::recording::struct_::struct_.
        (gcc::jit::recording::struct_::set_fields): Move class to...
        (gcc::jit::recording::compound_type::set_fields): ... here.
        (gcc::jit::recording::struct_::dereference): Move class to...
        (gcc::jit::recording::compound_type::dereference): ...here.
        (gcc::jit::recording::struct_::struct_): Reimplement by calling
        base class ctor.
        (gcc::jit::recording::struct_::replay_into): The playback hook
        is now "new_compound_type" and adds a bool, with true for
        "is_struct" (vs a union).
        (gcc::jit::recording::struct_::make_debug_string): "m_name" is
        now moved to base class and private, so use an accessor.
        (gcc::jit::recording::union_::union_): New function.
        (gcc::jit::recording::union_::replay_into): New function.
        (gcc::jit::recording::union_::make_debug_string): New function.
        (gcc::jit::recording::fields::fields): Update first param from
        struct_ * to compound_type *, and rename field "m_struct" to
        "m_struct_or_union".
        (gcc::jit::recording::fields::replay_into): "m_struct" is now
        "m_struct_or_union" and has a playback_compound_type rather
        than a playback_struct.
        (gcc::jit::recording::fields::write_to_dump): Update for
        renaming of m_struct to m_struct_or_union.
        (gcc::jit::playback::context::new_struct_type): Rename method
        to...
        (gcc::jit::playback::context::new_compound_type): this,
        generalizing so that it can make unions as well as structs; the
        underlying playback type is now called "compound_type".
        (gcc::jit::playback::struct_::set_fields): This method's class has
        changed name, so this is now...
        (gcc::jit::playback::compound_type::set_fields): ...this method.

        * TODO.rst: Unions are done.

gcc/testsuite/
        * jit.dg/test-accessing-union.c: New test case.
        * jit.dg/test-combination.c: Add test-accessing-union.c.
---
 gcc/jit/ChangeLog.jit                       | 101 +++++++++++++++++++++++++++
 gcc/jit/TODO.rst                            |   5 --
 gcc/jit/internal-api.c                      | 102 ++++++++++++++++++++--------
 gcc/jit/internal-api.h                      |  94 +++++++++++++++++--------
 gcc/jit/libgccjit.c                         |  30 ++++++++
 gcc/jit/libgccjit.h                         |  12 +++-
 gcc/jit/libgccjit.map                       |   1 +
 gcc/testsuite/ChangeLog.jit                 |   5 ++
 gcc/testsuite/jit.dg/test-accessing-union.c |  97 ++++++++++++++++++++++++++
 gcc/testsuite/jit.dg/test-combination.c     |   9 +++
 10 files changed, 391 insertions(+), 65 deletions(-)
 create mode 100644 gcc/testsuite/jit.dg/test-accessing-union.c

diff --git a/gcc/jit/ChangeLog.jit b/gcc/jit/ChangeLog.jit
index f7fd642..cb4ee60 100644
--- a/gcc/jit/ChangeLog.jit
+++ b/gcc/jit/ChangeLog.jit
@@ -1,5 +1,106 @@
 2014-08-08  David Malcolm  <dmalc...@redhat.com>
 
+       * libgccjit.h (gcc_jit_context_new_union_type): New entrypoint.
+       (gcc_jit_lvalue_access_field): Rename first param from "struct_"
+       to "struct_or_union".
+       (gcc_jit_rvalue_access_field): Likewise.
+
+       * libgccjit.c (gcc_jit_context_new_union_type): New entrypoint.
+
+       * libgccjit.map (gcc_jit_context_new_union_type): New entrypoint.
+
+       * internal-api.h (gcc::jit::recording::compound_type): New class
+       (gcc::jit::recording::union): New class.
+       (gcc::jit::playback::struct_): Rename this class to...
+       (gcc::jit::playback::compound_type): ...this.
+       (gcc::jit::recording::context::new_union_type): New method.
+       (gcc::jit::recording::context): Rename field "m_structs" to
+       "m_compound_types", generalizing from a vec <struct_ *> to a
+       vec<compound_type *>.
+       (gcc::jit::recording::field): Update field m_container from
+       struct * to container_type *.
+       (gcc::jit::recording::field::get_container): Generalize from
+       struct_ * to container_type *.
+       (gcc::jit::recording::field::set_container): Likewise.
+       (gcc::jit::recording::compound_type): New subclass of type, to
+       be a superclass of existing class struct_ and new class union_.
+       (gcc::jit::recording::struct_::get_name): Move to...
+       (gcc::jit::recording::compound_type::get_name): ...here.
+       (gcc::jit::recording::struct_::get_loc): Move to...
+       (gcc::jit::recording::compound_type::get_loc): ...here.
+       (gcc::jit::recording::struct_::set_fields): Move to...
+       (gcc::jit::recording::compound_type::set_fields): ...here.
+       (gcc::jit::recording::struct_::dereference): Move to...
+       (gcc::jit::recording::compound_type::dereference): ...here.
+       (gcc::jit::recording::struct_::is_int): Move to...
+       (gcc::jit::recording::compound_type::is_int): ...here.
+       (gcc::jit::recording::struct_::is_float): Move to...
+       (gcc::jit::recording::compound_type::is_float): ...here.
+       (gcc::jit::recording::struct_::is_bool): Move to...
+       (gcc::jit::recording::compound_type::is_bool): ...here.
+       (gcc::jit::recording::struct_::is_pointer): Move to...
+       (gcc::jit::recording::compound_type::is_pointer): ...here.
+       (gcc::jit::recording::struct_::is_array): Move to...
+       (gcc::jit::recording::compound_type::is_array): ...here.
+       (gcc::jit::recording::struct_::playback_struct): Move to...
+       (gcc::jit::recording::compound_type::playback_compound_type):
+       ...here, renaming and updating return type.
+       (gcc::jit::recording::struct_): Inherit from compound_type,
+       rather than just type.
+       (gcc::jit::recording::fields): Update to work on compound_type *
+       rather than struct_ *, renaming "m_struct" to "m_struct_or_union".
+       (gcc::jit::recording::union): New subclass of compound_type.
+       (gcc::jit::playback::context::new_struct_type): Generalize by
+       renaming to...
+       (gcc::jit::playback::context::new_compound_type): ...this, and
+       and an "is_struct" bool param.
+       (gcc::jit::playback::struct_): Generalize by renaming class to...
+       (gcc::jit::playback::compound_type): ...this.
+
+       * internal-api.c (gcc::jit::recording::context::context): Rename
+       field "m_structs" to "m_compound_types".
+       (gcc::jit::recording::context::new_struct_type): Likewise.
+       (gcc::jit::recording::context::new_union_type): New method.
+       (gcc::jit::recording::context::dump_to_file): Field "m_structs"
+       is renamed "m_compound_types" and changes type from struct_ *
+       to compound_type *.
+       (gcc::jit::recording::compound_type::compound_type): New ctor,
+       built from old body of gcc::jit::recording::struct_::struct_.
+       (gcc::jit::recording::struct_::set_fields): Move class to...
+       (gcc::jit::recording::compound_type::set_fields): ... here.
+       (gcc::jit::recording::struct_::dereference): Move class to...
+       (gcc::jit::recording::compound_type::dereference): ...here.
+       (gcc::jit::recording::struct_::struct_): Reimplement by calling
+       base class ctor.
+       (gcc::jit::recording::struct_::replay_into): The playback hook
+       is now "new_compound_type" and adds a bool, with true for
+       "is_struct" (vs a union).
+       (gcc::jit::recording::struct_::make_debug_string): "m_name" is
+       now moved to base class and private, so use an accessor.
+       (gcc::jit::recording::union_::union_): New function.
+       (gcc::jit::recording::union_::replay_into): New function.
+       (gcc::jit::recording::union_::make_debug_string): New function.
+       (gcc::jit::recording::fields::fields): Update first param from
+       struct_ * to compound_type *, and rename field "m_struct" to
+       "m_struct_or_union".
+       (gcc::jit::recording::fields::replay_into): "m_struct" is now
+       "m_struct_or_union" and has a playback_compound_type rather
+       than a playback_struct.
+       (gcc::jit::recording::fields::write_to_dump): Update for
+       renaming of m_struct to m_struct_or_union.
+       (gcc::jit::playback::context::new_struct_type): Rename method
+       to...
+       (gcc::jit::playback::context::new_compound_type): this,
+       generalizing so that it can make unions as well as structs; the
+       underlying playback type is now called "compound_type".
+       (gcc::jit::playback::struct_::set_fields): This method's class has
+       changed name, so this is now...
+       (gcc::jit::playback::compound_type::set_fields): ...this method.
+
+       * TODO.rst: Unions are done.
+
+2014-08-08  David Malcolm  <dmalc...@redhat.com>
+
        * TODO.rst: Function ptrs are done.
        * internal-api.c
        (gcc::jit::recording::context::new_function_ptr_type): New method.
diff --git a/gcc/jit/TODO.rst b/gcc/jit/TODO.rst
index d832337..fd7b07c 100644
--- a/gcc/jit/TODO.rst
+++ b/gcc/jit/TODO.rst
@@ -13,11 +13,6 @@ Initial Release
 * enums and ABI: give enums specific numbers, in ranges, to make it
   possible to maintain a logical ordering whilst preserving ABI.
 
-* more language features:
-
-  * more types:
-    * unions
-
 * expose the statements in the API? (mostly so they can be stringified?)
 
 * support more arithmetic ops and comparison modes
diff --git a/gcc/jit/internal-api.c b/gcc/jit/internal-api.c
index cacb526..bc353be 100644
--- a/gcc/jit/internal-api.c
+++ b/gcc/jit/internal-api.c
@@ -134,7 +134,7 @@ recording::context::context (context *parent_ctxt)
   : m_parent_ctxt (parent_ctxt),
     m_error_count (0),
     m_mementos (),
-    m_structs (),
+    m_compound_types (),
     m_functions (),
     m_FILE_type (NULL),
     m_builtins_manager(NULL)
@@ -377,7 +377,17 @@ recording::context::new_struct_type (recording::location 
*loc,
 {
   recording::struct_ *result = new struct_ (this, loc, new_string (name));
   record (result);
-  m_structs.safe_push (result);
+  m_compound_types.safe_push (result);
+  return result;
+}
+
+recording::union_ *
+recording::context::new_union_type (recording::location *loc,
+                                   const char *name)
+{
+  recording::union_ *result = new union_ (this, loc, new_string (name));
+  record (result);
+  m_compound_types.safe_push (result);
   return result;
 }
 
@@ -695,15 +705,15 @@ recording::context::dump_to_file (const char *path, bool 
update_locations)
   int i;
   dump d (*this, path, update_locations);
 
-  /* Forward declaration of structs.  */
-  struct_ *st;
-  FOR_EACH_VEC_ELT (m_structs, i, st)
+  /* Forward declaration of structs and unions.  */
+  compound_type *st;
+  FOR_EACH_VEC_ELT (m_compound_types, i, st)
     {
       d.write ("%s;\n\n", st->get_debug_string ());
     }
 
   /* Content of structs, where set.  */
-  FOR_EACH_VEC_ELT (m_structs, i, st)
+  FOR_EACH_VEC_ELT (m_compound_types, i, st)
     if (st->get_fields ())
       {
        st->get_fields ()->write_to_dump (d);
@@ -1294,10 +1304,10 @@ recording::field::make_debug_string ()
   return m_name;
 }
 
-/* gcc::jit::recording::struct_:: */
-recording::struct_::struct_ (context *ctxt,
-                            location *loc,
-                            string *name)
+/* gcc::jit::recording::compound_type */
+recording::compound_type::compound_type (context *ctxt,
+                                        location *loc,
+                                        string *name)
 : type (ctxt),
   m_loc (loc),
   m_name (name),
@@ -1306,9 +1316,9 @@ recording::struct_::struct_ (context *ctxt,
 }
 
 void
-recording::struct_::set_fields (location *loc,
-                               int num_fields,
-                               field **field_array)
+recording::compound_type::set_fields (location *loc,
+                                     int num_fields,
+                                     field **field_array)
 {
   m_loc = loc;
   gcc_assert (NULL == m_fields);
@@ -1318,38 +1328,71 @@ recording::struct_::set_fields (location *loc,
 }
 
 recording::type *
-recording::struct_::dereference ()
+recording::compound_type::dereference ()
 {
   return NULL; /* not a pointer */
 }
 
+/* gcc::jit::recording::struct_:: */
+recording::struct_::struct_ (context *ctxt,
+                            location *loc,
+                            string *name)
+: compound_type (ctxt, loc, name)
+{
+}
+
 void
 recording::struct_::replay_into (replayer *r)
 {
   set_playback_obj (
-    r->new_struct_type (playback_location (r, m_loc),
-                       m_name->c_str ()));
+    r->new_compound_type (playback_location (r, get_loc ()),
+                         get_name ()->c_str (),
+                         true /* is_struct */));
 }
 
 recording::string *
 recording::struct_::make_debug_string ()
 {
   return string::from_printf (m_ctxt,
-                             "struct %s", m_name->c_str ());
+                             "struct %s", get_name ()->c_str ());
+}
+
+/* gcc::jit::recording::union_:: */
+recording::union_::union_ (context *ctxt,
+                          location *loc,
+                          string *name)
+: compound_type (ctxt, loc, name)
+{
+}
+
+void
+recording::union_::replay_into (replayer *r)
+{
+  set_playback_obj (
+    r->new_compound_type (playback_location (r, get_loc ()),
+                         get_name ()->c_str (),
+                         false /* is_struct */));
+}
+
+recording::string *
+recording::union_::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+                             "union %s", get_name ()->c_str ());
 }
 
 /* gcc::jit::recording::fields:: */
-recording::fields::fields (struct_ *struct_,
+recording::fields::fields (compound_type *struct_or_union,
                           int num_fields,
                           field **fields)
-: memento (struct_->m_ctxt),
-  m_struct (struct_),
+: memento (struct_or_union->m_ctxt),
+  m_struct_or_union (struct_or_union),
   m_fields ()
 {
   for (int i = 0; i < num_fields; i++)
     {
       gcc_assert (fields[i]->get_container () == NULL);
-      fields[i]->set_container (m_struct);
+      fields[i]->set_container (m_struct_or_union);
       m_fields.safe_push (fields[i]);
     }
 }
@@ -1361,7 +1404,7 @@ recording::fields::replay_into (replayer *)
   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);
+  m_struct_or_union->playback_compound_type ()->set_fields (playback_fields);
 }
 
 void
@@ -1370,7 +1413,7 @@ recording::fields::write_to_dump (dump &d)
   int i;
   field *f;
 
-  d.write ("%s\n{\n", m_struct->get_debug_string ());
+  d.write ("%s\n{\n", m_struct_or_union->get_debug_string ());
   FOR_EACH_VEC_ELT (m_fields, i, f)
     f->write_to_dump (d);
   d.write ("};\n");
@@ -2685,27 +2728,28 @@ new_field (location *loc,
   return new field (decl);
 }
 
-playback::struct_ *
+playback::compound_type *
 playback::context::
-new_struct_type (location *loc,
-                const char *name)
+new_compound_type (location *loc,
+                  const char *name,
+                  bool is_struct) /* else is union */
 {
   gcc_assert (name);
 
   /* Compare with c/c-decl.c: start_struct. */
 
-  tree t = make_node (RECORD_TYPE);
+  tree t = make_node (is_struct ? RECORD_TYPE : UNION_TYPE);
   TYPE_NAME (t) = get_identifier (name);
   TYPE_SIZE (t) = 0;
 
   if (loc)
     set_tree_location (t, loc);
 
-  return new struct_ (t);
+  return new compound_type (t);
 }
 
 void
-playback::struct_::set_fields (const vec<playback::field *> &fields)
+playback::compound_type::set_fields (const vec<playback::field *> &fields)
 {
   /* Compare with c/c-decl.c: finish_struct. */
   tree t = as_tree ();
diff --git a/gcc/jit/internal-api.h b/gcc/jit/internal-api.h
index c4fe2f3..274b6ca 100644
--- a/gcc/jit/internal-api.h
+++ b/gcc/jit/internal-api.h
@@ -85,7 +85,9 @@ namespace recording {
   class type;
   class function_type;
   class field;
+  class compound_type;
   class struct_;
+  class union_;
   class fields;
   class function;
   class block;
@@ -101,7 +103,7 @@ namespace playback {
   class location;
   class type;
   class field;
-  class struct_;
+  class compound_type;
   class function;
   class block;
   class rvalue;
@@ -192,6 +194,10 @@ public:
   new_struct_type (location *loc,
                   const char *name);
 
+  union_ *
+  new_union_type (location *loc,
+                 const char *name);
+
   type *
   new_function_ptr_type (location *loc,
                         type *return_type,
@@ -347,7 +353,7 @@ private:
   vec<memento *> m_mementos;
 
   /* Specific recordings, for use by dump_to_file.  */
-  vec<struct_ *> m_structs;
+  vec<compound_type *> m_compound_types;
   vec<function *> m_functions;
 
   type *m_basic_types[NUM_GCC_JIT_TYPES];
@@ -748,8 +754,8 @@ public:
 
   type * get_type () const { return m_type; }
 
-  struct_ * get_container () const { return m_container; }
-  void set_container (struct_ *c) { m_container = c; }
+  compound_type * get_container () const { return m_container; }
+  void set_container (compound_type *c) { m_container = c; }
 
   void replay_into (replayer *);
 
@@ -768,22 +774,19 @@ private:
   location *m_loc;
   type *m_type;
   string *m_name;
-  struct_ *m_container;
+  compound_type *m_container;
 };
 
-class struct_ : public type
+/* Base class for struct_ and union_ */
+class compound_type : public type
 {
 public:
-  struct_ (context *ctxt,
-          location *loc,
-          string *name);
-
-  struct_ *dyn_cast_struct () { return this; }
-
-  type *
-  as_type () { return this; }
+  compound_type (context *ctxt,
+                location *loc,
+                string *name);
 
   string *get_name () const { return m_name; }
+  location *get_loc () const { return m_loc; }
   fields * get_fields () { return m_fields; }
 
   void
@@ -799,28 +802,42 @@ public:
   type *is_pointer () { return NULL; }
   type *is_array () { return NULL; }
 
-  void replay_into (replayer *r);
-
-  playback::struct_ *
-  playback_struct ()
+  playback::compound_type *
+  playback_compound_type ()
   {
-    return static_cast <playback::struct_ *> (m_playback_obj);
+    return static_cast <playback::compound_type *> (m_playback_obj);
   }
 
 private:
-  string * make_debug_string ();
-
-private:
   location *m_loc;
   string *m_name;
   fields *m_fields;
 };
 
+class struct_ : public compound_type
+{
+public:
+  struct_ (context *ctxt,
+          location *loc,
+          string *name);
+
+  struct_ *dyn_cast_struct () { return this; }
+
+  type *
+  as_type () { return this; }
+
+  void replay_into (replayer *r);
+
+private:
+  string * make_debug_string ();
+
+};
+
 // memento of struct_::set_fields
 class fields : public memento
 {
 public:
-  fields (struct_ *struct_,
+  fields (compound_type *struct_or_union,
          int num_fields,
          field **fields);
 
@@ -832,10 +849,28 @@ private:
   string * make_debug_string ();
 
 private:
-  struct_ *m_struct;
+  compound_type *m_struct_or_union;
   vec<field *> m_fields;
 };
 
+class union_ : public compound_type
+{
+public:
+  union_ (context *ctxt,
+         location *loc,
+         string *name);
+
+  void replay_into (replayer *r);
+
+private:
+  string * make_debug_string ();
+
+private:
+  location *m_loc;
+  string *m_name;
+  fields *m_fields;
+};
+
 class rvalue : public memento
 {
 public:
@@ -1674,9 +1709,10 @@ public:
             type *type,
             const char *name);
 
-  struct_ *
-  new_struct_type (location *loc,
-                  const char *name);
+  compound_type *
+  new_compound_type (location *loc,
+                    const char *name,
+                    bool is_struct); /* else is union */
 
   type *
   new_function_type (type *return_type,
@@ -1899,10 +1935,10 @@ private:
   tree m_inner;
 };
 
-class struct_ : public type
+class compound_type : public type
 {
 public:
-  struct_ (tree inner)
+  compound_type (tree inner)
     : type (inner)
   {}
 
diff --git a/gcc/jit/libgccjit.c b/gcc/jit/libgccjit.c
index 28deb7d..9550d8f 100644
--- a/gcc/jit/libgccjit.c
+++ b/gcc/jit/libgccjit.c
@@ -462,6 +462,36 @@ gcc_jit_struct_set_fields (gcc_jit_struct *struct_type,
 }
 
 gcc_jit_type *
+gcc_jit_context_new_union_type (gcc_jit_context *ctxt,
+                               gcc_jit_location *loc,
+                               const char *name,
+                               int num_fields,
+                               gcc_jit_field **fields)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  RETURN_NULL_IF_FAIL (name, ctxt, loc, "NULL name");
+  if (num_fields)
+    RETURN_NULL_IF_FAIL (fields, ctxt, loc, "NULL fields ptr");
+  for (int i = 0; i < num_fields; i++)
+    {
+      RETURN_NULL_IF_FAIL (fields[i], ctxt, loc, "NULL field ptr");
+      RETURN_NULL_IF_FAIL_PRINTF2 (
+       NULL == fields[i]->get_container (),
+       ctxt, loc,
+       "%s is already a field of %s",
+       fields[i]->get_debug_string (),
+       fields[i]->get_container ()->get_debug_string ());
+    }
+
+  gcc::jit::recording::union_ *result =
+    ctxt->new_union_type (loc, name);
+  result->set_fields (loc,
+                     num_fields,
+                     (gcc::jit::recording::field **)fields);
+  return (gcc_jit_type *) (result);
+}
+
+gcc_jit_type *
 gcc_jit_context_new_function_ptr_type (gcc_jit_context *ctxt,
                                       gcc_jit_location *loc,
                                       gcc_jit_type *return_type,
diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h
index a7e437ed..29d3389 100644
--- a/gcc/jit/libgccjit.h
+++ b/gcc/jit/libgccjit.h
@@ -436,6 +436,14 @@ gcc_jit_struct_set_fields (gcc_jit_struct *struct_type,
                           int num_fields,
                           gcc_jit_field **fields);
 
+/* Unions work similarly to structs.  */
+extern gcc_jit_type *
+gcc_jit_context_new_union_type (gcc_jit_context *ctxt,
+                               gcc_jit_location *loc,
+                               const char *name,
+                               int num_fields,
+                               gcc_jit_field **fields);
+
 /* Function pointers. */
 
 extern gcc_jit_type *
@@ -753,7 +761,7 @@ gcc_jit_context_new_array_access (gcc_jit_context *ctxt,
       (EXPR).field = ...;
    in C.  */
 extern gcc_jit_lvalue *
-gcc_jit_lvalue_access_field (gcc_jit_lvalue *struct_,
+gcc_jit_lvalue_access_field (gcc_jit_lvalue *struct_or_union,
                             gcc_jit_location *loc,
                             gcc_jit_field *field);
 
@@ -761,7 +769,7 @@ gcc_jit_lvalue_access_field (gcc_jit_lvalue *struct_,
       (EXPR).field
    in C.  */
 extern gcc_jit_rvalue *
-gcc_jit_rvalue_access_field (gcc_jit_rvalue *struct_,
+gcc_jit_rvalue_access_field (gcc_jit_rvalue *struct_or_union,
                             gcc_jit_location *loc,
                             gcc_jit_field *field);
 
diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map
index d7f5d7c..768e010 100644
--- a/gcc/jit/libgccjit.map
+++ b/gcc/jit/libgccjit.map
@@ -40,6 +40,7 @@
     gcc_jit_context_new_string_literal;
     gcc_jit_context_new_struct_type;
     gcc_jit_context_new_unary_op;
+    gcc_jit_context_new_union_type;
     gcc_jit_context_null;
     gcc_jit_context_one;
     gcc_jit_context_release;
diff --git a/gcc/testsuite/ChangeLog.jit b/gcc/testsuite/ChangeLog.jit
index 0842a1b..cdde662 100644
--- a/gcc/testsuite/ChangeLog.jit
+++ b/gcc/testsuite/ChangeLog.jit
@@ -1,5 +1,10 @@
 2014-08-08  David Malcolm  <dmalc...@redhat.com>
 
+       * jit.dg/test-accessing-union.c: New test case.
+       * jit.dg/test-combination.c: Add test-accessing-union.c.
+
+2014-08-08  David Malcolm  <dmalc...@redhat.com>
+
        * jit.dg/test-combination.c (create_code): Add missing calls to
        create_code_quadratic and create_code_reading_struct.
        (verify_code): Add missing calls to verify_code_quadratic and
diff --git a/gcc/testsuite/jit.dg/test-accessing-union.c 
b/gcc/testsuite/jit.dg/test-accessing-union.c
new file mode 100644
index 0000000..658d1bc
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-accessing-union.c
@@ -0,0 +1,97 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+union int_or_float
+{
+  int as_int;
+  float as_float;
+};
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to inject the equivalent of:
+     float
+     test_union (int i)
+     {
+        union int_or_float u;
+       u.as_int = i;
+       return u.as_float;
+     }
+  */
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+  gcc_jit_type *float_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_FLOAT);
+  gcc_jit_field *as_int =
+    gcc_jit_context_new_field (ctxt,
+                               NULL,
+                               int_type,
+                               "as_int");
+  gcc_jit_field *as_float =
+    gcc_jit_context_new_field (ctxt,
+                               NULL,
+                               float_type,
+                               "as_float");
+  gcc_jit_field *fields[] = {as_int, as_float};
+  gcc_jit_type *union_type =
+    gcc_jit_context_new_union_type (ctxt, NULL,
+                                   "int_or_float", 2, fields);
+
+  /* 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,
+                                  float_type,
+                                  "test_union",
+                                  1, &param_i,
+                                  0);
+
+  gcc_jit_lvalue *u =
+    gcc_jit_function_new_local (test_fn, NULL,
+                               union_type, "u");
+
+  gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
+
+  /* u.as_int = i; */
+  gcc_jit_block_add_assignment (
+    block,
+    NULL,
+    /* "u.as_int = ..." */
+    gcc_jit_lvalue_access_field (u,
+                                NULL,
+                                as_int),
+    gcc_jit_param_as_rvalue (param_i));
+
+  /* return u.as_float; */
+  gcc_jit_block_end_with_return (
+    block, NULL,
+    gcc_jit_rvalue_access_field (gcc_jit_lvalue_as_rvalue (u),
+                                NULL,
+                                as_float));
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  typedef float (*fn_type) (int i);
+  CHECK_NON_NULL (result);
+
+  fn_type test_union =
+    (fn_type)gcc_jit_result_get_code (result, "test_union");
+  CHECK_NON_NULL (test_union);
+
+  /* Call the JIT-generated function.  */
+  float f_result = test_union (42);
+
+  union int_or_float u;
+  u.as_float = f_result;
+
+  CHECK_VALUE (u.as_int, 42);
+}
diff --git a/gcc/testsuite/jit.dg/test-combination.c 
b/gcc/testsuite/jit.dg/test-combination.c
index a8bf3bc..a3e3102 100644
--- a/gcc/testsuite/jit.dg/test-combination.c
+++ b/gcc/testsuite/jit.dg/test-combination.c
@@ -14,6 +14,13 @@
 #undef create_code
 #undef verify_code
 
+/* test-accessing-union.c */
+#define create_code create_code_accessing_union
+#define verify_code verify_code_accessing_union
+#include "test-accessing-union.c"
+#undef create_code
+#undef verify_code
+
 /* test-array-as-pointer.c */
 #define create_code create_code_array_as_pointer
 #define verify_code verify_code_array_as_pointer
@@ -155,6 +162,7 @@ void
 create_code (gcc_jit_context *ctxt, void * user_data)
 {
   create_code_accessing_struct (ctxt, user_data);
+  create_code_accessing_union (ctxt, user_data);
   create_code_array_as_pointer (ctxt, user_data);
   create_code_arrays (ctxt, user_data);
   create_code_calling_external_function (ctxt, user_data);
@@ -179,6 +187,7 @@ void
 verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
 {
   verify_code_accessing_struct (ctxt, result);
+  verify_code_accessing_union (ctxt, result);
   verify_code_array_as_pointer (ctxt, result);
   verify_code_arrays (ctxt, result);
   verify_code_calling_external_function (ctxt, result);
-- 
1.8.5.3

Reply via email to