diff --git a/ChangeLog b/ChangeLog
--- a/ChangeLog
+++ b/ChangeLog
@@ -556,6 +556,17 @@
 
 	* tests/scanner/annotation.c: fixed a few copy-paste errors
 
+2008-10-15  Andreas Rottmann  <a.rottmann@gmx.at>
+
+	* gir/Makefile.am (girepository): New target. This target creates
+	a symbolic link that is needed so that the tests using the
+	repository work when the typelibs are not installed.
+	* tests/repository/Makefile.am (TESTS_ENVIRONMENT): Set
+	XDG_DATA_DIRS, so tests work when the typelibs are not installed.
+
+	* tests/scanner/Makefile.am (%.typelib): Set PYTHONPATH
+	appropriatly when invoking the scanner.
+
 2008-10-14  Johan Bilien  <jobi@via.ecp.fr>
 
 	Bug 556323 – transfer-ownership is wrong for functions returning const
@@ -801,6 +812,56 @@
 	* test/scanner/foo-expected.gir: test that.
 
 2008-10-11  Andreas Rottmann  <a.rottmann@gmx.at>
+
+	* tests/scanner/utility.h (UtilityTaggedValue): Make the union
+	member anonymous.
+	(UtilityByte): New union typedef with an unnamed struct in it.
+
+	* giscanner/transformer.py (Transformer._create_struct): Create
+	unnamed structs for symbols with a None ident.
+	(Transformer._create_union): Likewise.
+
+	* giscanner/girwriter.py (GIRWriter._write_record): Allow name
+	being None.
+	(GIRWriter._write_union): Likewise.
+
+	* girepository/girparser.c (start_struct): Allow a NULL name for
+	non-toplevel structs.
+	(start_union): Likewise.
+
+	* tests/scanner/utility.h (UtilityTaggedValue): New struct
+	typedef, which has a nested union member.
+	* tests/scanner/utility-expected.gir: Adapted.
+
+	* giscanner/transformer.py (Transformer._create_member): Create
+	struct/union members if appropriate.
+	(Transformer._create_struct, Transformer._create_union): Allow for
+	structs/unions without a C type.
+
+	* giscanner/glibtransformer.py (GLibTransformer._resolve_field):
+	We don't need to resolve non-typef'd
+	(GLibTransformer._resolve_field): Add cases for non-typedef'd
+	struct/union "fields".
+
+	* giscanner/girwriter.py (GIRWriter._write_record): Allow for
+	records without a C type.
+	(GIRWriter._write_field): structs and unions may appear in places
+	where fields do.
+
+	* girepository/girparser.c (ParseContext): Removed member
+	current_node, added node_stack instead.
+	(CURRENT_NODE): New macro, returns the current node (top of
+	node_stack).
+	(VALID_UNION_STATE, VALID_STRUCT_STATE): New predicate macros,
+	return true if the state passed is a valid point for a union and
+	struct node, respectively.
+	(pop_node, push_node): New functions; pop or push a node from
+	node_stack.
+	(state_switch_end_struct_or_union): New function, switches the
+	state at the end of a struct/union.
+	Rest of the file adapted to tehse changes.
+
+2008-10-09  Andreas Rottmann  <a.rottmann@gmx.at>
 
 	Bug 555712: Struct and union issues
 
diff --git a/gir/Makefile.am b/gir/Makefile.am
--- a/gir/Makefile.am
+++ b/gir/Makefile.am
@@ -121,6 +121,11 @@
 %.typelib: %.gir $(top_builddir)/tools/g-ir-compiler$(EXEEXT) Makefile
 	$(DEBUG) $(top_builddir)/tools/g-ir-compiler$(EXEEXT) --includedir=. $(G_IR_COMPILER_OPTS) $< -o $@
 
+girepository: Makefile
+	rm -f girepository && ln -s . girepository
+CLEANFILES += girepository
+nodist_noinst_DATA = girepository
+
 typelibsdir = $(datadir)/girepository
 typelibs_DATA = GLib-2.0.typelib GModule-2.0.typelib GObject-2.0.typelib Gio-2.0.typelib
 CLEANFILES += $(typelibs_DATA)
diff --git a/girepository/girparser.c b/girepository/girparser.c
--- a/girepository/girparser.c
+++ b/girepository/girparser.c
@@ -78,13 +78,14 @@
 
   const char *namespace;
   GIrModule *current_module;
-  GIrNode *current_node;
+  GSList *node_stack;
   GIrNode *current_typed;
   gboolean is_varargs;
   GList *type_stack;
   GList *type_parameters;
   int type_depth;
 };
+#define CURRENT_NODE(ctx) ((GIrNode *)((ctx)->node_stack->data))
 
 static gboolean
 start_alias (GMarkupParseContext *context,
@@ -218,6 +219,27 @@
   g_debug ("State: %d", newstate);
   ctx->prev_state = ctx->state;
   ctx->state = newstate;
+}
+
+static GIrNode *
+pop_node (ParseContext *ctx)
+{
+  g_assert (ctx->node_stack != 0);
+  
+  GSList *top = ctx->node_stack;
+  GIrNode *node = top->data;
+  
+  g_debug ("popping node %d %s", node->type, node->name);
+  ctx->node_stack = top->next;
+  g_slist_free_1 (top);
+  return node;
+}
+
+static void
+push_node (ParseContext *ctx, GIrNode *node)
+{
+  g_debug ("pushing node %d %s", node->type, node->name);
+  ctx->node_stack = g_slist_prepend (ctx->node_stack, node);
 }
 
 static GIrNodeType * parse_type_internal (const gchar *str, gchar **next, gboolean in_glib,
@@ -508,7 +530,7 @@
   else
     boxed->deprecated = FALSE;
 	  
-  ctx->current_node = (GIrNode *)boxed;
+  push_node (ctx, (GIrNode *)boxed);
   ctx->current_module->entries = 
     g_list_append (ctx->current_module->entries, boxed);
   
@@ -607,20 +629,20 @@
   else
     function->throws = FALSE;
 
-  if (ctx->current_node == NULL)
+  if (ctx->node_stack == NULL)
     {
       ctx->current_module->entries = 
 	g_list_append (ctx->current_module->entries, function);	      
     }
   else
-    switch (ctx->current_node->type)
+    switch (CURRENT_NODE (ctx)->type)
       {
       case G_IR_NODE_INTERFACE:
       case G_IR_NODE_OBJECT:
 	{
 	  GIrNodeInterface *iface;
 	  
-	  iface = (GIrNodeInterface *)ctx->current_node;
+	  iface = (GIrNodeInterface *)CURRENT_NODE (ctx);
 	  iface->members = g_list_append (iface->members, function);
 	}
 	break;
@@ -628,7 +650,7 @@
 	{
 	  GIrNodeBoxed *boxed;
 	  
-	  boxed = (GIrNodeBoxed *)ctx->current_node;
+	  boxed = (GIrNodeBoxed *)CURRENT_NODE (ctx);
 	  boxed->members = g_list_append (boxed->members, function);
 	}
 	break;
@@ -636,14 +658,14 @@
 	{
 	  GIrNodeStruct *struct_;
 	  
-	  struct_ = (GIrNodeStruct *)ctx->current_node;
+	  struct_ = (GIrNodeStruct *)CURRENT_NODE (ctx);
 	  struct_->members = g_list_append (struct_->members, function);		}
 	break;
       case G_IR_NODE_UNION:
 	{
 	  GIrNodeUnion *union_;
 	  
-	  union_ = (GIrNodeUnion *)ctx->current_node;
+	  union_ = (GIrNodeUnion *)CURRENT_NODE (ctx);
 	  union_->members = g_list_append (union_->members, function);
 	}
 	break;
@@ -651,7 +673,7 @@
 	g_assert_not_reached ();
       }
   
-  ctx->current_node = (GIrNode *)function;
+  push_node(ctx, (GIrNode *)function);
   state_switch (ctx, STATE_FUNCTION);
   
   return TRUE;
@@ -764,14 +786,14 @@
 
   ((GIrNode *)param)->name = g_strdup (name);
 	  
-  switch (ctx->current_node->type)
+  switch (CURRENT_NODE (ctx)->type)
     {
     case G_IR_NODE_FUNCTION:
     case G_IR_NODE_CALLBACK:
       {
 	GIrNodeFunction *func;
 
-	func = (GIrNodeFunction *)ctx->current_node;
+	func = (GIrNodeFunction *)CURRENT_NODE (ctx);
 	func->parameters = g_list_append (func->parameters, param);
       }
       break;
@@ -779,7 +801,7 @@
       {
 	GIrNodeSignal *signal;
 
-	signal = (GIrNodeSignal *)ctx->current_node;
+	signal = (GIrNodeSignal *)CURRENT_NODE (ctx);
 	signal->parameters = g_list_append (signal->parameters, param);
       }
       break;
@@ -787,7 +809,7 @@
       {
 	GIrNodeVFunc *vfunc;
 		
-	vfunc = (GIrNodeVFunc *)ctx->current_node;
+	vfunc = (GIrNodeVFunc *)CURRENT_NODE (ctx);
 	vfunc->parameters = g_list_append (vfunc->parameters, param);
       }
       break;
@@ -861,13 +883,13 @@
   else
     field->offset = 0;
   
-  switch (ctx->current_node->type)
+  switch (CURRENT_NODE (ctx)->type)
     {
     case G_IR_NODE_OBJECT:
       {
 	GIrNodeInterface *iface;
 	
-	iface = (GIrNodeInterface *)ctx->current_node;
+	iface = (GIrNodeInterface *)CURRENT_NODE (ctx);
 	iface->members = g_list_append (iface->members, field);
 	state_switch (ctx, STATE_CLASS_FIELD);
       }
@@ -876,7 +898,7 @@
       {
 	GIrNodeInterface *iface;
 	
-	iface = (GIrNodeInterface *)ctx->current_node;
+	iface = (GIrNodeInterface *)CURRENT_NODE (ctx);
 	iface->members = g_list_append (iface->members, field);
 	state_switch (ctx, STATE_INTERFACE_FIELD);
       }
@@ -885,7 +907,7 @@
       {
 	GIrNodeBoxed *boxed;
 	
-	boxed = (GIrNodeBoxed *)ctx->current_node;
+	boxed = (GIrNodeBoxed *)CURRENT_NODE (ctx);
 		boxed->members = g_list_append (boxed->members, field);
 		state_switch (ctx, STATE_BOXED_FIELD);
       }
@@ -894,7 +916,7 @@
       {
 	GIrNodeStruct *struct_;
 	
-	struct_ = (GIrNodeStruct *)ctx->current_node;
+	struct_ = (GIrNodeStruct *)CURRENT_NODE (ctx);
 	struct_->members = g_list_append (struct_->members, field);
 	state_switch (ctx, STATE_STRUCT_FIELD);
       }
@@ -903,7 +925,7 @@
       {
 	GIrNodeUnion *union_;
 	
-	union_ = (GIrNodeUnion *)ctx->current_node;
+	union_ = (GIrNodeUnion *)CURRENT_NODE (ctx);
 	union_->members = g_list_append (union_->members, field);
 	if (branch)
 	  {
@@ -1017,7 +1039,7 @@
 	  else
 	    enum_->deprecated = FALSE;
 
-	  ctx->current_node = (GIrNode *) enum_;
+	  push_node (ctx, (GIrNode *) enum_);
 	  ctx->current_module->entries = 
 	    g_list_append (ctx->current_module->entries, enum_);	      
 	  
@@ -1083,7 +1105,7 @@
 	  else
 	    property->construct_only = FALSE;
 
-	  iface = (GIrNodeInterface *)ctx->current_node;
+	  iface = (GIrNodeInterface *)CURRENT_NODE (ctx);
 	  iface->members = g_list_append (iface->members, property);
 
 	  if (ctx->state == STATE_CLASS)
@@ -1159,7 +1181,7 @@
 	  else
 	    value_->deprecated = FALSE;
 
-	  enum_ = (GIrNodeEnum *)ctx->current_node;
+	  enum_ = (GIrNodeEnum *)CURRENT_NODE (ctx);
 	  enum_->values = g_list_append (enum_->values, value_);
 	}
       
@@ -1211,7 +1233,7 @@
 
 	  if (ctx->state == STATE_NAMESPACE)
 	    {
-	      ctx->current_node = (GIrNode *) constant;
+	      push_node (ctx, (GIrNode *) constant);
 	      ctx->current_module->entries = 
 		g_list_append (ctx->current_module->entries, constant);
 	    }
@@ -1219,7 +1241,7 @@
 	    {
 	      GIrNodeInterface *iface;
 
-	      iface = (GIrNodeInterface *)ctx->current_node;
+	      iface = (GIrNodeInterface *)CURRENT_NODE (ctx);
 	      iface->members = g_list_append (iface->members, constant);
 	    }
 
@@ -1287,7 +1309,7 @@
 	  else
 	    domain->deprecated = FALSE;
 
-	  ctx->current_node = (GIrNode *) domain;
+	  push_node (ctx, (GIrNode *) domain);
 	  ctx->current_module->entries = 
 	    g_list_append (ctx->current_module->entries, domain);
 
@@ -1339,7 +1361,7 @@
 	  else
 	    iface->deprecated = FALSE;
 	  
-	  ctx->current_node = (GIrNode *) iface;
+	  push_node (ctx, (GIrNode *) iface);
 	  ctx->current_module->entries = 
 	    g_list_append (ctx->current_module->entries, iface);	      
 	  
@@ -1399,7 +1421,7 @@
 
 	  iface->abstract = abstract && strcmp (abstract, "1") == 0;
 
-	  ctx->current_node = (GIrNode *) iface;
+	  push_node (ctx, (GIrNode *) iface);
 	  ctx->current_module->entries = 
 	    g_list_append (ctx->current_module->entries, iface);	      
 	  
@@ -1455,18 +1477,18 @@
       ctx->type_depth = 1;
       if (is_varargs)
 	{
-	  switch (ctx->current_node->type)
+	  switch (CURRENT_NODE (ctx)->type)
 	    {
 	    case G_IR_NODE_FUNCTION:
 	    case G_IR_NODE_CALLBACK:
 	      {
-		GIrNodeFunction *func = (GIrNodeFunction *)ctx->current_node;
+		GIrNodeFunction *func = (GIrNodeFunction *)CURRENT_NODE (ctx);
 		func->is_varargs = TRUE;
 	      }
 	      break;
 	    case G_IR_NODE_VFUNC:
 	      {
-		GIrNodeVFunc *vfunc = (GIrNodeVFunc *)ctx->current_node;
+		GIrNodeVFunc *vfunc = (GIrNodeVFunc *)CURRENT_NODE (ctx);
 		vfunc->is_varargs = TRUE;
 	      }
 	      break;
@@ -1612,7 +1634,7 @@
       }
       break;
     default:
-      g_printerr("current node is %d\n", ctx->current_node->type);
+      g_printerr("current node is %d\n", CURRENT_NODE (ctx)->type);
       g_assert_not_reached ();
     }
   g_list_free (ctx->type_parameters);
@@ -1701,24 +1723,24 @@
       transfer = find_attribute ("transfer-ownership", attribute_names, attribute_values);
       parse_param_transfer (param, transfer);
 
-      switch (ctx->current_node->type)
+      switch (CURRENT_NODE (ctx)->type)
 	{
 	case G_IR_NODE_FUNCTION:
 	case G_IR_NODE_CALLBACK:
 	  {
-	    GIrNodeFunction *func = (GIrNodeFunction *)ctx->current_node;
+	    GIrNodeFunction *func = (GIrNodeFunction *)CURRENT_NODE (ctx);
 	    func->result = param;
 	  }
 	  break;
 	case G_IR_NODE_SIGNAL:
 	  {
-	    GIrNodeSignal *signal = (GIrNodeSignal *)ctx->current_node;
+	    GIrNodeSignal *signal = (GIrNodeSignal *)CURRENT_NODE (ctx);
 	    signal->result = param;
 	  }
 	  break;
 	case G_IR_NODE_VFUNC:
 	  {
-	    GIrNodeVFunc *vfunc = (GIrNodeVFunc *)ctx->current_node;
+	    GIrNodeVFunc *vfunc = (GIrNodeVFunc *)CURRENT_NODE (ctx);
 	    vfunc->result = param;
 	  }
 	  break;
@@ -1756,7 +1778,7 @@
       return FALSE;
     }
       
-  iface = (GIrNodeInterface *)ctx->current_node;
+  iface = (GIrNodeInterface *)CURRENT_NODE (ctx);
   iface->interfaces = g_list_append (iface->interfaces, g_strdup (name));
 
   return TRUE;
@@ -1832,10 +1854,10 @@
 	  else
 	    signal->has_class_closure = FALSE;
 
-	  iface = (GIrNodeInterface *)ctx->current_node;
+	  iface = (GIrNodeInterface *)CURRENT_NODE (ctx);
 	  iface->members = g_list_append (iface->members, signal);
 
-	  ctx->current_node = (GIrNode *)signal;
+	  push_node (ctx, (GIrNode *)signal);
 	  state_switch (ctx, STATE_FUNCTION);
 	}
       
@@ -1910,10 +1932,10 @@
 	  else
 	    vfunc->offset = 0;
 
-	  iface = (GIrNodeInterface *)ctx->current_node;
+	  iface = (GIrNodeInterface *)CURRENT_NODE (ctx);
 	  iface->members = g_list_append (iface->members, vfunc);
 
-	  ctx->current_node = (GIrNode *)vfunc;
+	  push_node (ctx, (GIrNode *)vfunc);
 	  state_switch (ctx, STATE_FUNCTION);
 	}
       
@@ -1932,7 +1954,10 @@
 	      GError             **error)
 {
   if (strcmp (element_name, "record") == 0 && 
-      ctx->state == STATE_NAMESPACE)
+      (ctx->state == STATE_NAMESPACE ||
+       ctx->state == STATE_UNION ||
+       ctx->state == STATE_STRUCT ||
+       ctx->state == STATE_CLASS))
     {
       const gchar *name;
       const gchar *deprecated;
@@ -1945,7 +1970,7 @@
       gtype_name = find_attribute ("glib:type-name", attribute_names, attribute_values);
       gtype_init = find_attribute ("glib:get-type", attribute_names, attribute_values);
 
-      if (name == NULL)
+      if (name == NULL && ctx->node_stack == NULL)
 	{
 	  MISSING_ATTRIBUTE (context, error, element_name, "name");
 	  return FALSE;
@@ -1963,7 +1988,7 @@
 
       struct_ = (GIrNodeStruct *) g_ir_node_new (G_IR_NODE_STRUCT);
       
-      ((GIrNode *)struct_)->name = g_strdup (name);
+      ((GIrNode *)struct_)->name = g_strdup (name ? name : "");
       if (deprecated)
 	struct_->deprecated = TRUE;
       else
@@ -1971,10 +1996,10 @@
 
       struct_->gtype_name = g_strdup (gtype_name);
       struct_->gtype_init = g_strdup (gtype_init);
-      
-      ctx->current_node = (GIrNode *)struct_;
-      ctx->current_module->entries = 
-	g_list_append (ctx->current_module->entries, struct_);
+      if (ctx->node_stack == NULL)
+          ctx->current_module->entries = 
+            g_list_append (ctx->current_module->entries, struct_);
+      push_node (ctx, (GIrNode *)struct_);
       
       state_switch (ctx, STATE_STRUCT);
       return TRUE;
@@ -1991,8 +2016,11 @@
 	     ParseContext       *ctx,
 	     GError             **error)
 {
-  if (strcmp (element_name, "union") == 0 && 
-      ctx->state == STATE_NAMESPACE)
+  if (strcmp (element_name, "union") == 0 &&
+      (ctx->state == STATE_NAMESPACE ||
+       ctx->state == STATE_UNION ||
+       ctx->state == STATE_STRUCT ||
+       ctx->state == STATE_CLASS))
     {
       const gchar *name;
       const gchar *deprecated;
@@ -2004,7 +2032,7 @@
       typename = find_attribute ("glib:type-name", attribute_names, attribute_values);
       typeinit = find_attribute ("glib:get-type", attribute_names, attribute_values);
       
-      if (name == NULL)
+      if (name == NULL && ctx->node_stack == NULL)
 	MISSING_ATTRIBUTE (context, error, element_name, "name");
       else
 	{
@@ -2012,7 +2040,7 @@
 
 	  union_ = (GIrNodeUnion *) g_ir_node_new (G_IR_NODE_UNION);
 	  
-	  ((GIrNode *)union_)->name = g_strdup (name);
+	  ((GIrNode *)union_)->name = g_strdup (name ? name : "");
 	  union_->gtype_name = g_strdup (typename);
 	  union_->gtype_init = g_strdup (typeinit);
 	  if (deprecated)
@@ -2020,9 +2048,10 @@
 	  else
 	    union_->deprecated = FALSE;
 
-	  ctx->current_node = (GIrNode *)union_;
-	  ctx->current_module->entries = 
-	    g_list_append (ctx->current_module->entries, union_);
+          if (ctx->node_stack == NULL)
+            ctx->current_module->entries = 
+              g_list_append (ctx->current_module->entries, union_);
+          push_node (ctx, (GIrNode *)union_);
 	  
 	  state_switch (ctx, STATE_UNION);
 	}
@@ -2052,9 +2081,9 @@
       else if (offset == NULL)
 	MISSING_ATTRIBUTE (context, error, element_name, "offset");
 	{
-	  ((GIrNodeUnion *)ctx->current_node)->discriminator_type 
+	  ((GIrNodeUnion *)CURRENT_NODE (ctx))->discriminator_type 
 	    = parse_type (ctx, type);
-	  ((GIrNodeUnion *)ctx->current_node)->discriminator_offset 
+	  ((GIrNodeUnion *)CURRENT_NODE (ctx))->discriminator_offset 
 	    = atoi (offset);
 	}
       
@@ -2198,7 +2227,7 @@
 	    {  
 	      GIrNodeInterface *iface;
 
-	      iface = (GIrNodeInterface *)ctx->current_node;
+	      iface = (GIrNodeInterface *)CURRENT_NODE (ctx);
 	      iface ->prerequisites = g_list_append (iface->prerequisites, g_strdup (name));
 	    }
 
@@ -2465,6 +2494,41 @@
 }
 
 static gboolean
+state_switch_end_struct_or_union (GMarkupParseContext *context,
+                                  ParseContext *ctx,
+                                  const gchar *element_name,
+                                  GError **error)
+{
+  pop_node (ctx);
+  if (ctx->node_stack == NULL)
+    {
+      state_switch (ctx, STATE_NAMESPACE);
+    }
+  else 
+    {
+      if (CURRENT_NODE (ctx)->type == G_IR_NODE_STRUCT)
+        state_switch (ctx, STATE_STRUCT);
+      else if (CURRENT_NODE (ctx)->type == G_IR_NODE_UNION)
+        state_switch (ctx, STATE_UNION);
+      else if (CURRENT_NODE (ctx)->type == G_IR_NODE_OBJECT)
+        state_switch (ctx, STATE_CLASS);
+      else
+        {
+          int line_number, char_number;
+          g_markup_parse_context_get_position (context, &line_number, &char_number);
+          g_set_error (error,
+                       G_MARKUP_ERROR,
+                       G_MARKUP_ERROR_INVALID_CONTENT,
+                       "Unexpected end tag '%s' on line %d char %d",
+                       element_name,
+                       line_number, char_number);
+          return FALSE;
+        }
+    }
+  return TRUE;
+}
+
+static gboolean
 require_end_element (GMarkupParseContext *context,
 		     ParseContext        *ctx,
 		     const char          *expected_name,
@@ -2544,28 +2608,22 @@
 
     case STATE_FUNCTION:
       {
- 	gboolean current_is_toplevel;
-	GList *last = g_list_last (ctx->current_module->entries);
-	
-	current_is_toplevel = ctx->current_node == last->data;	
-
-	if (current_is_toplevel)
+        pop_node (ctx);
+	if (ctx->node_stack == NULL)
 	  {
-	    ctx->current_node = NULL;
 	    state_switch (ctx, STATE_NAMESPACE);
 	  }
 	else 
-	  { 
-	    ctx->current_node = g_list_last (ctx->current_module->entries)->data;
-	    if (ctx->current_node->type == G_IR_NODE_INTERFACE)
+	  {
+	    if (CURRENT_NODE (ctx)->type == G_IR_NODE_INTERFACE)
 	      state_switch (ctx, STATE_INTERFACE);
-	    else if (ctx->current_node->type == G_IR_NODE_OBJECT) 
+	    else if (CURRENT_NODE (ctx)->type == G_IR_NODE_OBJECT) 
 	      state_switch (ctx, STATE_CLASS);
-	    else if (ctx->current_node->type == G_IR_NODE_BOXED)
+	    else if (CURRENT_NODE (ctx)->type == G_IR_NODE_BOXED)
 	      state_switch (ctx, STATE_BOXED);
-	    else if (ctx->current_node->type == G_IR_NODE_STRUCT)
+	    else if (CURRENT_NODE (ctx)->type == G_IR_NODE_STRUCT)
 	      state_switch (ctx, STATE_STRUCT);
-	    else if (ctx->current_node->type == G_IR_NODE_UNION)
+	    else if (CURRENT_NODE (ctx)->type == G_IR_NODE_UNION)
 	      state_switch (ctx, STATE_UNION);
 	    else
 	      {
@@ -2603,7 +2661,7 @@
     case STATE_CLASS:
       if (require_end_element (context, ctx, "class", element_name, error))
 	{
-	  ctx->current_node = NULL;
+	  pop_node (ctx);
 	  state_switch (ctx, STATE_NAMESPACE);
 	}
       break;
@@ -2611,7 +2669,7 @@
     case STATE_ERRORDOMAIN:
       if (require_end_element (context, ctx, "errordomain", element_name, error))
 	{
-	  ctx->current_node = NULL;
+	  pop_node (ctx);
 	  state_switch (ctx, STATE_NAMESPACE);
 	}
       break;
@@ -2637,7 +2695,7 @@
     case STATE_INTERFACE:
       if (require_end_element (context, ctx, "interface", element_name, error))
 	{
-	  ctx->current_node = NULL;
+	  pop_node (ctx);
 	  state_switch (ctx, STATE_NAMESPACE);
 	}
       break;
@@ -2649,7 +2707,7 @@
 					    element_name, error, "enumeration", 
 					    "bitfield", NULL))
 	{
-	  ctx->current_node = NULL;
+	  pop_node (ctx);
 	  state_switch (ctx, STATE_NAMESPACE);
 	}
       break;
@@ -2657,7 +2715,7 @@
     case STATE_BOXED:
       if (require_end_element (context, ctx, "glib:boxed", element_name, error))
 	{
-	  ctx->current_node = NULL;
+	  pop_node (ctx);
 	  state_switch (ctx, STATE_NAMESPACE);
 	}
       break;
@@ -2683,8 +2741,7 @@
     case STATE_STRUCT:
       if (require_end_element (context, ctx, "record", element_name, error))
 	{
-	  ctx->current_node = NULL;
-	  state_switch (ctx, STATE_NAMESPACE);
+	  state_switch_end_struct_or_union (context, ctx, element_name, error);
 	}
       break;
 
@@ -2700,8 +2757,7 @@
     case STATE_UNION:
       if (require_end_element (context, ctx, "union", element_name, error))
 	{
-	  ctx->current_node = NULL;
-	  state_switch (ctx, STATE_NAMESPACE);
+	  state_switch_end_struct_or_union (context, ctx, element_name, error);
 	}
       break;
     case STATE_IMPLEMENTS:
@@ -2721,7 +2777,7 @@
 	break;
       if (require_end_element (context, ctx, "constant", element_name, error))
 	{
-	  ctx->current_node = NULL;
+	  pop_node (ctx);
 	  switch (ctx->state)
 	    {
 	    case STATE_NAMESPACE_CONSTANT:
diff --git a/giscanner/girwriter.py b/giscanner/girwriter.py
--- a/giscanner/girwriter.py
+++ b/giscanner/girwriter.py
@@ -302,8 +302,11 @@
             self._write_method(method)
 
     def _write_record(self, record):
-        attrs = [('name', record.name),
-                 ('c:type', record.symbol)]
+        attrs = []
+        if record.name is not None:
+            attrs.append(('name', record.name))
+        if record.symbol is not None: # the record might be anonymous
+            attrs.append(('c:type', record.symbol))
         self._append_deprecated(record, attrs)
         if isinstance(record, GLibBoxed):
             attrs.extend(self._boxed_attrs(record))
@@ -315,8 +318,11 @@
                 self._write_boxed_ctors_methods(record)
 
     def _write_union(self, union):
-        attrs = [('name', union.name),
-                 ('c:type', union.symbol)]
+        attrs = []
+        if union.name is not None:
+            attrs.append(('name', union.name))
+        if union.symbol is not None: # the union might be anonymous
+            attrs.append(('c:type', union.symbol))
         self._append_deprecated(union, attrs)
         if isinstance(union, GLibBoxed):
             attrs.extend(self._boxed_attrs(union))
@@ -334,19 +340,22 @@
 
         if isinstance(field, Callback):
             self._write_callback(field)
-            return
-
-        attrs = [('name', field.name)]
-        # Fields are assumed to be read-only
-        # (see also girparser.c and generate.c)
-        if not field.readable:
-            attrs.append(('readable', '0'))
-        if field.writable:
-            attrs.append(('writable', '1'))
-        if field.bits:
-            attrs.append(('bits', str(field.bits)))
-        with self.tagcontext('field', attrs):
-            self._write_type(field.type)
+        elif isinstance(field, Struct):
+            self._write_record(field)
+        elif isinstance(field, Union):
+            self._write_union(field)
+        else:
+            attrs = [('name', field.name)]
+            # Fields are assumed to be read-only
+            # (see also girparser.c and generate.c)
+            if not field.readable:
+                attrs.append(('readable', '0'))
+            if field.writable:
+                attrs.append(('writable', '1'))
+            if field.bits:
+                attrs.append(('bits', str(field.bits)))
+            with self.tagcontext('field', attrs):
+                self._write_type(field.type)
 
     def _write_signal(self, signal):
         attrs = [('name', signal.name)]
diff --git a/giscanner/glibtransformer.py b/giscanner/glibtransformer.py
--- a/giscanner/glibtransformer.py
+++ b/giscanner/glibtransformer.py
@@ -844,8 +844,12 @@
     def _resolve_field(self, field):
         if isinstance(field, Callback):
             self._resolve_function(field)
-            return
-        field.type = self._resolve_param_type(field.type)
+        elif isinstance(field, Struct): # non-typedef'd struct
+            self._resolve_struct(field)
+        elif isinstance(field, Union): # non-typedef'd union
+            self._resolve_union(field)
+        else:
+            field.type = self._resolve_param_type(field.type)
 
     def _resolve_alias(self, alias):
         alias.target = self._resolve_type_name(alias.target, alias.target)
diff --git a/giscanner/transformer.py b/giscanner/transformer.py
--- a/giscanner/transformer.py
+++ b/giscanner/transformer.py
@@ -304,10 +304,15 @@
                 child, dirs.get(child.ident, {}))
 
     def _create_member(self, symbol):
-        ctype = symbol.base_type.type
+        base_type = symbol.base_type
+        ctype = base_type.type
         if (ctype == CTYPE_POINTER and
-            symbol.base_type.base_type.type == CTYPE_FUNCTION):
+            base_type.base_type.type == CTYPE_FUNCTION):
             node = self._create_callback(symbol)
+        elif ctype == CTYPE_STRUCT and base_type.name is None:
+            node = self._create_struct(symbol, anonymous=True)
+        elif ctype == CTYPE_UNION and base_type.name is None:
+            node = self._create_union(symbol, anonymous=True)
         else:
             opts = {}
             if ctype == CTYPE_ARRAY:
@@ -566,18 +571,23 @@
         self._create_union(symbol)
         return union
 
-    def _create_struct(self, symbol):
-        struct = self._typedefs_ns.get(symbol.ident, None)
-        if struct is None:
-            # This is a bit of a hack; really we should try
-            # to resolve through the typedefs to find the real
-            # name
-            if symbol.ident.startswith('_'):
-                name = symbol.ident[1:]
-            else:
-                name = symbol.ident
-            name = self.remove_prefix(name)
-            struct = Struct(name, symbol.ident)
+    def _create_struct(self, symbol, anonymous=False):
+        if symbol.ident is None:
+            # the struct is an anonymous member of another union or a struct
+            assert anonymous
+            struct = Struct(None, None)
+        else:
+            struct = self._typedefs_ns.get(symbol.ident, None)
+            if struct is None:
+                # This is a bit of a hack; really we should try
+                # to resolve through the typedefs to find the real
+                # name
+                if symbol.ident.startswith('_'):
+                    name = symbol.ident[1:]
+                else:
+                    name = symbol.ident
+                name = self.remove_prefix(name)
+                struct = Struct(name, symbol.ident)
 
         for child in symbol.base_type.child_list:
             field = self._traverse_one(child)
@@ -586,18 +596,23 @@
 
         return struct
 
-    def _create_union(self, symbol):
-        union = self._typedefs_ns.get(symbol.ident, None)
-        if union is None:
-            # This is a bit of a hack; really we should try
-            # to resolve through the typedefs to find the real
-            # name
-            if symbol.ident.startswith('_'):
-                name = symbol.ident[1:]
-            else:
-                name = symbol.ident
-            name = self.remove_prefix(name)
-            union = Union(name, symbol.ident)
+    def _create_union(self, symbol, anonymous=False):
+        if symbol.ident is None:
+            # the union is an anonymous member of another union or a struct
+            assert anonymous
+            union = Union(None, None)
+        else:
+            union = self._typedefs_ns.get(symbol.ident, None)
+            if union is None:
+                # This is a bit of a hack; really we should try
+                # to resolve through the typedefs to find the real
+                # name
+                if symbol.ident.startswith('_'):
+                    name = symbol.ident[1:]
+                else:
+                    name = symbol.ident
+                name = self.remove_prefix(name)
+                union = Union(name, symbol.ident)
 
         for child in symbol.base_type.child_list:
             field = self._traverse_one(child)
diff --git a/tests/repository/Makefile.am b/tests/repository/Makefile.am
--- a/tests/repository/Makefile.am
+++ b/tests/repository/Makefile.am
@@ -13,4 +13,5 @@
 gitestthrows_LDADD = $(GIREPO_LIBS) $(top_builddir)/girepository/libgirepository.la
 
 TESTS = gitestrepo gitestthrows
-TESTS_ENVIRONMENT=env top_builddir="$(top_builddir)" $(DEBUG)
+TESTS_ENVIRONMENT=env top_builddir="$(top_builddir)" $(DEBUG) \
+   XDG_DATA_DIRS="$(top_srcdir)/gir:$(XDG_DATA_DIRS)"
diff --git a/tests/scanner/utility-1.0-expected.gir b/tests/scanner/utility-1.0-expected.gir
--- a/tests/scanner/utility-1.0-expected.gir
+++ b/tests/scanner/utility-1.0-expected.gir
@@ -58,5 +58,34 @@
         <type name="double" c:type="double"/>
       </field>
     </union>
+    <record name="TaggedValue" c:type="UtilityTaggedValue">
+      <field name="tag" writable="1">
+        <type name="int" c:type="int"/>
+      </field>
+      <union>
+        <field name="v_pointer" writable="1">
+          <type name="any" c:type="gpointer"/>
+        </field>
+        <field name="v_real" writable="1">
+          <type name="double" c:type="double"/>
+        </field>
+        <field name="v_integer" writable="1">
+          <type name="long" c:type="long"/>
+        </field>
+      </union>
+    </record>
+    <union name="Byte" c:type="UtilityByte">
+      <field name="value" writable="1">
+        <type name="uint8" c:type="guint8"/>
+      </field>
+      <record>
+        <field name="first_nibble" writable="1" bits="4">
+          <type name="uint8" c:type="guint8"/>
+        </field>
+        <field name="second_nibble" writable="1" bits="4">
+          <type name="uint8" c:type="guint8"/>
+        </field>
+      </record>
+    </union>
   </namespace>
 </repository>
diff --git a/tests/scanner/utility.h b/tests/scanner/utility.h
--- a/tests/scanner/utility.h
+++ b/tests/scanner/utility.h
@@ -53,5 +53,27 @@
   glong integer;
   double real;
 } UtilityUnion;
+
+typedef struct
+{
+  int tag;
+  union
+  {
+    gpointer v_pointer;
+    double v_real;
+    long v_integer;
+  };
+} UtilityTaggedValue;
+
+typedef union
+{
+  guint8 value;
+  struct
+  {
+    guint8 first_nibble : 4;
+    guint8 second_nibble : 4;
+  };
+} UtilityByte;
+    
   
 #endif /* __UTILITY_H__ */
