diff --git a/ChangeLog b/ChangeLog
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2008-11-11  Andreas Rottmann  <a.rottmann@gmx.at>
+	
+	* girepository/girparser.c (ParseContext): Removed member
+	current_node, added node_stack instead.
+	(CURRENT_NODE): New macro, returns the current node (top of
+	node_stack).
+	(pop_node, push_node): New functions; pop or push a node from
+	node_stack.
+	Rest of the file adapted to these changes, which are necessary 
+	for supporting nested structs/and unions.
+
 2008-11-09  Jürg Billeter  <j@bitron.ch>
 
 	* giscanner/ast.py:
@@ -1121,7 +1132,7 @@
 	* test/scanner/foo.h: add function which uses unsigned as a type.
 	* test/scanner/foo-expected.gir: test that.
 
-2008-10-11  Andreas Rottmann  <a.rottmann@gmx.at>
+2008-10-09  Andreas Rottmann  <a.rottmann@gmx.at>
 
 	Bug 555712: Struct and union issues
 
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);
 	}
       
@@ -1972,9 +1994,9 @@
       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_);
+      push_node (ctx, (GIrNode *)struct_);
       
       state_switch (ctx, STATE_STRUCT);
       return TRUE;
@@ -2020,9 +2042,9 @@
 	  else
 	    union_->deprecated = FALSE;
 
-	  ctx->current_node = (GIrNode *)union_;
 	  ctx->current_module->entries = 
 	    g_list_append (ctx->current_module->entries, union_);
+	  push_node (ctx, (GIrNode *)union_);
 	  
 	  state_switch (ctx, STATE_UNION);
 	}
@@ -2052,9 +2074,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 +2220,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 +2487,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 +2601,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 +2654,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 +2662,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 +2688,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 +2700,7 @@
 					    element_name, error, "enumeration", 
 					    "bitfield", NULL))
 	{
-	  ctx->current_node = NULL;
+	  pop_node (ctx);
 	  state_switch (ctx, STATE_NAMESPACE);
 	}
       break;
@@ -2657,7 +2708,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,7 +2734,7 @@
     case STATE_STRUCT:
       if (require_end_element (context, ctx, "record", element_name, error))
 	{
-	  ctx->current_node = NULL;
+	  pop_node (ctx);
 	  state_switch (ctx, STATE_NAMESPACE);
 	}
       break;
@@ -2700,7 +2751,7 @@
     case STATE_UNION:
       if (require_end_element (context, ctx, "union", element_name, error))
 	{
-	  ctx->current_node = NULL;
+	  pop_node (ctx);
 	  state_switch (ctx, STATE_NAMESPACE);
 	}
       break;
@@ -2721,7 +2772,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:
