Make type_stack pushing a bit safer

This changes type_stack to make pushing elements a bit safer: if an
element requires an argument, these are now always pushed at the same
time, rather than separately.

This patch also adds a few comments to help document a bit better.

Approved-By: Simon Marchi <simon.marchi@efficios.com>


diff --git a/gdb/c-exp.y b/gdb/c-exp.y
index 98be2da..3abfafe 100644
--- a/gdb/c-exp.y
+++ b/gdb/c-exp.y
@@ -1303,15 +1303,13 @@
 	|	direct_abs_decl array_mod
 			{
 			  cpstate->type_stack.push ($1);
-			  cpstate->type_stack.push ($2);
-			  cpstate->type_stack.push (tp_array);
+			  cpstate->type_stack.push (tp_array, $2);
 			  $$ = cpstate->type_stack.create ();
 			  cpstate->type_stacks.emplace_back ($$);
 			}
 	|	array_mod
 			{
-			  cpstate->type_stack.push ($1);
-			  cpstate->type_stack.push (tp_array);
+			  cpstate->type_stack.push (tp_array, $1);
 			  $$ = cpstate->type_stack.create ();
 			  cpstate->type_stacks.emplace_back ($$);
 			}
diff --git a/gdb/d-exp.y b/gdb/d-exp.y
index 6b4fd04..e774dee 100644
--- a/gdb/d-exp.y
+++ b/gdb/d-exp.y
@@ -613,11 +613,9 @@
 |	'*' BasicType2
 		{ type_stack->push (tp_pointer); }
 |	'[' INTEGER_LITERAL ']'
-		{ type_stack->push ($2.val);
-		  type_stack->push (tp_array); }
+		{ type_stack->push (tp_array, $2.val); }
 |	'[' INTEGER_LITERAL ']' BasicType2
-		{ type_stack->push ($2.val);
-		  type_stack->push (tp_array); }
+		{ type_stack->push (tp_array, $2.val); }
 ;
 
 BasicType:
diff --git a/gdb/f-exp.y b/gdb/f-exp.y
index 07fc54c..a8ee9a3 100644
--- a/gdb/f-exp.y
+++ b/gdb/f-exp.y
@@ -1159,8 +1159,7 @@
       ival = static_cast <int> (val);
     }
 
-  type_stack->push (ival);
-  type_stack->push (tp_kind);
+  type_stack->push (tp_kind, ival);
 }
 
 /* Helper function for convert_to_kind_type.  */
diff --git a/gdb/type-stack.h b/gdb/type-stack.h
index af5a89d..64940dd 100644
--- a/gdb/type-stack.h
+++ b/gdb/type-stack.h
@@ -26,34 +26,49 @@
 struct type;
 struct expr_builder;
 
-/* For parsing of complicated types.
-   An array should be preceded in the list by the size of the array.  */
+/* The kind of element on the stack of types and qualifiers, used for
+   parsing complicated types.  */
 enum type_pieces
-  {
-    tp_end = -1, 
-    tp_pointer, 
-    tp_reference, 
-    tp_rvalue_reference,
-    tp_array, 
-    tp_function,
-    tp_function_with_arguments,
-    tp_const, 
-    tp_volatile, 
-    tp_space_identifier,
-    tp_atomic,
-    tp_restrict,
-    tp_type_stack,
-    tp_kind
-  };
+{
+  /* This is returned by pop() to indicate that the stack is empty.
+     Note that it may not be pushed by the user.  */
+  tp_end = -1,
+  tp_pointer,
+  tp_reference,
+  tp_rvalue_reference,
+  /* An array type, where the dimension is pushed on the stack as
+     well.  */
+  tp_array,
+  tp_function,
+  /* A function with argument types; the types are also pushed on the
+     stack.  */
+  tp_function_with_arguments,
+  tp_const,
+  tp_volatile,
+  /* An address space identifier.  The address space is also pushed on
+     the stack.  */
+  tp_space_identifier,
+  tp_atomic,
+  tp_restrict,
+  /* A separate type stack, which is also pushed onto this type
+     stack.  */
+  tp_type_stack,
+  /* Fortran-specific, specifies the kind.  */
+  tp_kind,
+};
 
-/* The stack can contain either an enum type_pieces or an int.  */
+/* Items on the type stack.  */
 union type_stack_elt
-  {
-    enum type_pieces piece;
-    int int_val;
-    struct type_stack *stack_val;
-    std::vector<struct type *> *typelist_val;
-  };
+{
+  /* An ordinary type qualifier.  */
+  enum type_pieces piece;
+  /* An integer value.  Currently only used for address spaces.  */
+  int int_val;
+  /* Another type stack.  */
+  struct type_stack *stack_val;
+  /* A list of types.  */
+  std::vector<struct type *> *typelist_val;
+};
 
 /* The type stack is an instance of this structure.  */
 
@@ -80,18 +95,31 @@ struct type_stack
 
   void insert (enum type_pieces tp);
 
+  /* Push an ordinary element on the type stack.  This can be used for
+     any element that doesn't require any extra data.  */
   void push (enum type_pieces tp)
   {
+    /* tp_end can only be returned by this class, not pushed.  The
+       others require a payload on the stack and so can only be pushed
+       by the appropriate method.  */
+    gdb_assert (tp != tp_end);
+    gdb_assert (!requires_payload (tp));
     type_stack_elt elt;
     elt.piece = tp;
     m_elements.push_back (elt);
   }
 
-  void push (int n)
+  /* Push an element and an integer value onto the stack.  The integer
+     value is pushed first, followed by TP.  Only piece kinds that
+     accept an integer argument are allowed.  */
+  void push (enum type_pieces tp, int n)
   {
+    gdb_assert (tp == tp_array || tp == tp_space_identifier || tp == tp_kind);
     type_stack_elt elt;
     elt.int_val = n;
     m_elements.push_back (elt);
+    elt.piece = tp;
+    m_elements.push_back (elt);
   }
 
   /* Push the type stack STACK as an element on this type stack.  */
@@ -101,11 +129,12 @@ struct type_stack
     type_stack_elt elt;
     elt.stack_val = stack;
     m_elements.push_back (elt);
-    push (tp_type_stack);
+    elt.piece = tp_type_stack;
+    m_elements.push_back (elt);
   }
 
-  /* Push a function type with arguments onto the global type stack.
-     LIST holds the argument types.  If the final item in LIST is NULL,
+  /* Push a function type with arguments onto this type stack.  LIST
+     holds the argument types.  If the final item in LIST is NULL,
      then the function will be varargs.  */
 
   void push (std::vector<struct type *> *list)
@@ -113,7 +142,8 @@ struct type_stack
     type_stack_elt elt;
     elt.typelist_val = list;
     m_elements.push_back (elt);
-    push (tp_function_with_arguments);
+    elt.piece = tp_function_with_arguments;
+    m_elements.push_back (elt);
   }
 
   enum type_pieces pop ()
@@ -127,11 +157,7 @@ struct type_stack
 
   int pop_int ()
   {
-    if (m_elements.empty ())
-      {
-	/* "Can't happen".  */
-	return 0;
-      }
+    gdb_assert (!m_elements.empty ());
     type_stack_elt elt = m_elements.back ();
     m_elements.pop_back ();
     return elt.int_val;
@@ -198,6 +224,14 @@ struct type_stack
     m_elements.insert (m_elements.begin () + slot, element);
   }
 
+  /* Return true if TP requires some payload element.  */
+  bool requires_payload (type_pieces tp) const
+  {
+    return (tp == tp_array || tp == tp_kind || tp == tp_type_stack
+	    || tp == tp_function_with_arguments
+	    || tp == tp_space_identifier);
+  }
+
 
   /* Elements on the stack.  */
   std::vector<union type_stack_elt> m_elements;