[12/13] Move type stack handling to a new class

Message ID 20190403013805.11978-13-tom@tromey.com
State New
Headers show
Series
  • Remove parser-related globals
Related show

Commit Message

Tom Tromey April 3, 2019, 1:38 a.m.
This introduces a new "type_stack" class, and moves all the parser
type stack handling to this class.  Parsers that wish to use this
facility must now instantiate this class somehow.  I chose this
approach because a minority of the existing parsers require this.

2019-04-02  Tom Tromey  <tom@tromey.com>

	* type-stack.h: New file.
	* type-stack.c: New file.
	* parser-defs.h (enum type_pieces, union type_stack_elt): Move to
	type-stack.h.
	(insert_into_type_stack, insert_type, push_type, push_type_int)
	(insert_type_address_space, pop_type, pop_type_int)
	(pop_typelist, pop_type_stack, append_type_stack)
	(push_type_stack, get_type_stack, push_typelist)
	(follow_type_instance_flags, follow_types): Don't declare.
	* parse.c (type_stack): Remove global.
	(parse_exp_in_context): Update.
	(insert_into_type_stack, insert_type, push_type, push_type_int)
	(insert_type_address_space, pop_type, pop_type_int)
	(pop_typelist, pop_type_stack, append_type_stack)
	(push_type_stack, get_type_stack, push_typelist)
	(follow_type_instance_flags, follow_types): Remove (moved to
	type-stack.c).
	* f-exp.y (type_stack): New global.
	Update rules.
	(push_kind_type, f_parse): Update.
	* d-exp.y (type_stack): New global.
	Update rules.
	(d_parse): Update.
	* c-exp.y (struct c_parse_state) <type_stack>: New member.
	Update rules.
	* Makefile.in (COMMON_SFILES): Add type-stack.c.
	(HFILES_NO_SRCDIR): Add type-stack.h.
---
 gdb/ChangeLog     |  30 +++++
 gdb/Makefile.in   |   2 +
 gdb/c-exp.y       |  77 ++++++-----
 gdb/d-exp.y       |  22 ++-
 gdb/f-exp.y       |  30 +++--
 gdb/parse.c       | 333 ----------------------------------------------
 gdb/parser-defs.h |  59 --------
 gdb/type-stack.c  | 209 +++++++++++++++++++++++++++++
 gdb/type-stack.h  | 205 ++++++++++++++++++++++++++++
 9 files changed, 523 insertions(+), 444 deletions(-)
 create mode 100644 gdb/type-stack.c
 create mode 100644 gdb/type-stack.h

-- 
2.17.2

Patch

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 5614cc3386c..0f495783600 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1131,6 +1131,7 @@  COMMON_SFILES = \
 	trad-frame.c \
 	tramp-frame.c \
 	target-float.c \
+	type-stack.c \
 	typeprint.c \
 	ui-file.c \
 	ui-out.c \
@@ -1406,6 +1407,7 @@  HFILES_NO_SRCDIR = \
 	trad-frame.h \
 	target-float.h \
 	tramp-frame.h \
+	type-stack.h \
 	typeprint.h \
 	ui-file.h \
 	ui-out.h \
diff --git a/gdb/c-exp.y b/gdb/c-exp.y
index 842b492e58a..627ea1f3bae 100644
--- a/gdb/c-exp.y
+++ b/gdb/c-exp.y
@@ -53,6 +53,7 @@ 
 #include "objc-lang.h"
 #include "typeprint.h"
 #include "cp-abi.h"
+#include "type-stack.h"
 
 #define parse_type(ps) builtin_type (ps->gdbarch ())
 
@@ -104,6 +105,9 @@  struct c_parse_state
      token, we simply keep it all and delete it after parsing has
      completed.  */
   auto_obstack expansion_obstack;
+
+  /* The type stack.  */
+  struct type_stack type_stack;
 };
 
 /* This is set and cleared in c_parse.  */
@@ -604,8 +608,10 @@  function_method:       exp '(' parameter_typelist ')' const_or_volatile
 			  /* Save the const/volatile qualifiers as
 			     recorded by the const_or_volatile
 			     production's actions.  */
-			  write_exp_elt_longcst (pstate,
-						 follow_type_instance_flags ());
+			  write_exp_elt_longcst
+			    (pstate,
+			     (cpstate->type_stack
+			      .follow_type_instance_flags ()));
 			  write_exp_elt_longcst (pstate, len);
 			  for (type *type_elt : *type_list)
 			    write_exp_elt_type (pstate, type_elt);
@@ -617,8 +623,9 @@  function_method:       exp '(' parameter_typelist ')' const_or_volatile
 function_method_void:	    exp '(' ')' const_or_volatile
 		       { write_exp_elt_opcode (pstate, TYPE_INSTANCE);
 			 /* See above.  */
-			 write_exp_elt_longcst (pstate,
-						follow_type_instance_flags ());
+			 write_exp_elt_longcst
+			   (pstate,
+			    cpstate->type_stack.follow_type_instance_flags ());
 			 write_exp_elt_longcst (pstate, 0);
 			 write_exp_elt_longcst (pstate, 0);
 			 write_exp_elt_opcode (pstate, TYPE_INSTANCE);
@@ -1158,7 +1165,9 @@  variable:	name_not_typename
 	;
 
 space_identifier : '@' NAME
-		{ insert_type_address_space (pstate, copy_name ($2.stoken)); }
+		{
+		  cpstate->type_stack.insert (pstate, copy_name ($2.stoken));
+		}
 	;
 
 const_or_volatile: const_or_volatile_noopt
@@ -1179,30 +1188,30 @@  const_or_volatile_or_space_identifier:
 
 ptr_operator:
 		ptr_operator '*'
-			{ insert_type (tp_pointer); }
+			{ cpstate->type_stack.insert (tp_pointer); }
 		const_or_volatile_or_space_identifier
 	|	'*'
-			{ insert_type (tp_pointer); }
+			{ cpstate->type_stack.insert (tp_pointer); }
 		const_or_volatile_or_space_identifier
 	|	'&'
-			{ insert_type (tp_reference); }
+			{ cpstate->type_stack.insert (tp_reference); }
 	|	'&' ptr_operator
-			{ insert_type (tp_reference); }
+			{ cpstate->type_stack.insert (tp_reference); }
 	|       ANDAND
-			{ insert_type (tp_rvalue_reference); }
+			{ cpstate->type_stack.insert (tp_rvalue_reference); }
 	|       ANDAND ptr_operator
-			{ insert_type (tp_rvalue_reference); }
+			{ cpstate->type_stack.insert (tp_rvalue_reference); }
 	;
 
 ptr_operator_ts: ptr_operator
 			{
-			  $$ = get_type_stack ();
+			  $$ = cpstate->type_stack.create ();
 			  cpstate->type_stacks.emplace_back ($$);
 			}
 	;
 
 abs_decl:	ptr_operator_ts direct_abs_decl
-			{ $$ = append_type_stack ($2, $1); }
+			{ $$ = $2->append ($1); }
 	|	ptr_operator_ts
 	|	direct_abs_decl
 	;
@@ -1211,31 +1220,31 @@  direct_abs_decl: '(' abs_decl ')'
 			{ $$ = $2; }
 	|	direct_abs_decl array_mod
 			{
-			  push_type_stack ($1);
-			  push_type_int ($2);
-			  push_type (tp_array);
-			  $$ = get_type_stack ();
+			  cpstate->type_stack.push ($1);
+			  cpstate->type_stack.push ($2);
+			  cpstate->type_stack.push (tp_array);
+			  $$ = cpstate->type_stack.create ();
 			  cpstate->type_stacks.emplace_back ($$);
 			}
 	|	array_mod
 			{
-			  push_type_int ($1);
-			  push_type (tp_array);
-			  $$ = get_type_stack ();
+			  cpstate->type_stack.push ($1);
+			  cpstate->type_stack.push (tp_array);
+			  $$ = cpstate->type_stack.create ();
 			  cpstate->type_stacks.emplace_back ($$);
 			}
 
 	| 	direct_abs_decl func_mod
 			{
-			  push_type_stack ($1);
-			  push_typelist ($2);
-			  $$ = get_type_stack ();
+			  cpstate->type_stack.push ($1);
+			  cpstate->type_stack.push ($2);
+			  $$ = cpstate->type_stack.create ();
 			  cpstate->type_stacks.emplace_back ($$);
 			}
 	|	func_mod
 			{
-			  push_typelist ($1);
-			  $$ = get_type_stack ();
+			  cpstate->type_stack.push ($1);
+			  $$ = cpstate->type_stack.create ();
 			  cpstate->type_stacks.emplace_back ($$);
 			}
 	;
@@ -1489,9 +1498,9 @@  typebase
 			     pstate->expression_context_block);
 			}
 	| const_or_volatile_or_space_identifier_noopt typebase
-			{ $$ = follow_types ($2); }
+			{ $$ = cpstate->type_stack.follow_types ($2); }
 	| typebase const_or_volatile_or_space_identifier_noopt
-			{ $$ = follow_types ($1); }
+			{ $$ = cpstate->type_stack.follow_types ($1); }
 	;
 
 type_name:	TYPENAME
@@ -1552,13 +1561,13 @@  nonempty_typelist
 ptype	:	typebase
 	|	ptype abs_decl
 		{
-		  push_type_stack ($2);
-		  $$ = follow_types ($1);
+		  cpstate->type_stack.push ($2);
+		  $$ = cpstate->type_stack.follow_types ($1);
 		}
 	;
 
 conversion_type_id: typebase conversion_declarator
-		{ $$ = follow_types ($1); }
+		{ $$ = cpstate->type_stack.follow_types ($1); }
 	;
 
 conversion_declarator:  /* Nothing.  */
@@ -1570,13 +1579,13 @@  const_and_volatile: 	CONST_KEYWORD VOLATILE_KEYWORD
 	;
 
 const_or_volatile_noopt:  	const_and_volatile
-			{ insert_type (tp_const);
-			  insert_type (tp_volatile);
+			{ cpstate->type_stack.insert (tp_const);
+			  cpstate->type_stack.insert (tp_volatile);
 			}
 	| 		CONST_KEYWORD
-			{ insert_type (tp_const); }
+			{ cpstate->type_stack.insert (tp_const); }
 	| 		VOLATILE_KEYWORD
-			{ insert_type (tp_volatile); }
+			{ cpstate->type_stack.insert (tp_volatile); }
 	;
 
 oper:	OPERATOR NEW
diff --git a/gdb/d-exp.y b/gdb/d-exp.y
index 4d51cfdcb71..ca9aaf85802 100644
--- a/gdb/d-exp.y
+++ b/gdb/d-exp.y
@@ -51,6 +51,7 @@ 
 #include "objfiles.h" /* For have_full_symbols and have_partial_symbols */
 #include "charset.h"
 #include "block.h"
+#include "type-stack.h"
 
 #define parse_type(ps) builtin_type (ps->gdbarch ())
 #define parse_d_type(ps) builtin_d_type (ps->gdbarch ())
@@ -65,6 +66,9 @@ 
 
 static struct parser_state *pstate = NULL;
 
+/* The current type stack.  */
+static struct type_stack *type_stack;
+
 int yyparse (void);
 
 static int yylex (void);
@@ -606,7 +610,7 @@  TypeExp:
 		  write_exp_elt_type (pstate, $1);
 		  write_exp_elt_opcode (pstate, OP_TYPE); }
 |	BasicType BasicType2
-		{ $$ = follow_types ($1);
+		{ $$ = type_stack->follow_types ($1);
 		  write_exp_elt_opcode (pstate, OP_TYPE);
 		  write_exp_elt_type (pstate, $$);
 		  write_exp_elt_opcode (pstate, OP_TYPE);
@@ -615,15 +619,15 @@  TypeExp:
 
 BasicType2:
 	'*'
-		{ push_type (tp_pointer); }
+		{ type_stack->push (tp_pointer); }
 |	'*' BasicType2
-		{ push_type (tp_pointer); }
+		{ type_stack->push (tp_pointer); }
 |	'[' INTEGER_LITERAL ']'
-		{ push_type_int ($2.val);
-		  push_type (tp_array); }
+		{ type_stack->push ($2.val);
+		  type_stack->push (tp_array); }
 |	'[' INTEGER_LITERAL ']' BasicType2
-		{ push_type_int ($2.val);
-		  push_type (tp_array); }
+		{ type_stack->push ($2.val);
+		  type_stack->push (tp_array); }
 ;
 
 BasicType:
@@ -1619,6 +1623,10 @@  d_parse (struct parser_state *par_state)
   scoped_restore restore_yydebug = make_scoped_restore (&yydebug,
 							parser_debug);
 
+  struct type_stack stack;
+  scoped_restore restore_type_stack = make_scoped_restore (&type_stack,
+							   &stack);
+
   /* Initialize some state used by the lexer.  */
   last_was_structop = 0;
   saw_name_at_eof = 0;
diff --git a/gdb/f-exp.y b/gdb/f-exp.y
index da4732237d3..403dfa20687 100644
--- a/gdb/f-exp.y
+++ b/gdb/f-exp.y
@@ -54,6 +54,7 @@ 
 #include "block.h"
 #include <ctype.h>
 #include <algorithm>
+#include "type-stack.h"
 
 #define parse_type(ps) builtin_type (ps->gdbarch ())
 #define parse_f_type(ps) builtin_f_type (ps->gdbarch ())
@@ -71,6 +72,9 @@  static struct parser_state *pstate = NULL;
 /* Depth of parentheses.  */
 static int paren_depth;
 
+/* The current type stack.  */
+static struct type_stack *type_stack;
+
 int yyparse (void);
 
 static int yylex (void);
@@ -515,7 +519,7 @@  ptype	:	typebase
 		  struct type *range_type;
 		  
 		  while (!done)
-		    switch (pop_type ())
+		    switch (type_stack->pop ())
 		      {
 		      case tp_end:
 			done = 1;
@@ -527,7 +531,7 @@  ptype	:	typebase
 			follow_type = lookup_lvalue_reference_type (follow_type);
 			break;
 		      case tp_array:
-			array_size = pop_type_int ();
+			array_size = type_stack->pop_int ();
 			if (array_size != -1)
 			  {
 			    range_type =
@@ -547,7 +551,7 @@  ptype	:	typebase
 			break;
 		      case tp_kind:
 			{
-			  int kind_val = pop_type_int ();
+			  int kind_val = type_stack->pop_int ();
 			  follow_type
 			    = convert_to_kind_type (follow_type, kind_val);
 			}
@@ -558,13 +562,13 @@  ptype	:	typebase
 	;
 
 abs_decl:	'*'
-			{ push_type (tp_pointer); $$ = 0; }
+			{ type_stack->push (tp_pointer); $$ = 0; }
 	|	'*' abs_decl
-			{ push_type (tp_pointer); $$ = $2; }
+			{ type_stack->push (tp_pointer); $$ = $2; }
 	|	'&'
-			{ push_type (tp_reference); $$ = 0; }
+			{ type_stack->push (tp_reference); $$ = 0; }
 	|	'&' abs_decl
-			{ push_type (tp_reference); $$ = $2; }
+			{ type_stack->push (tp_reference); $$ = $2; }
 	|	direct_abs_decl
 	;
 
@@ -575,9 +579,9 @@  direct_abs_decl: '(' abs_decl ')'
 	|	'*' INT
 			{ push_kind_type ($2.val, $2.type); }
 	| 	direct_abs_decl func_mod
-			{ push_type (tp_function); }
+			{ type_stack->push (tp_function); }
 	|	func_mod
-			{ push_type (tp_function); }
+			{ type_stack->push (tp_function); }
 	;
 
 func_mod:	'(' ')'
@@ -821,8 +825,8 @@  push_kind_type (LONGEST val, struct type *type)
       ival = static_cast <int> (val);
     }
 
-  push_type_int (ival);
-  push_type (tp_kind);
+  type_stack->push (ival);
+  type_stack->push (tp_kind);
 }
 
 /* Called when a type has a '(kind=N)' modifier after it, for example
@@ -1333,6 +1337,10 @@  f_parse (struct parser_state *par_state)
   pstate = par_state;
   paren_depth = 0;
 
+  struct type_stack stack;
+  scoped_restore restore_type_stack = make_scoped_restore (&type_stack,
+							   &stack);
+
   return yyparse ();
 }
 
diff --git a/gdb/parse.c b/gdb/parse.c
index 7984a324fe0..89a29f0f602 100644
--- a/gdb/parse.c
+++ b/gdb/parse.c
@@ -67,7 +67,6 @@  const struct exp_descriptor exp_descriptor_standard =
 
 /* Global variables declared in parser-defs.h (and commented there).  */
 innermost_block_tracker innermost_block;
-static struct type_stack type_stack;
 
 
 static unsigned int expressiondebug = 0;
@@ -1073,7 +1072,6 @@  parse_exp_in_context (const char **stringptr, CORE_ADDR pc,
   const struct language_defn *lang = NULL;
   int subexp;
 
-  type_stack.elements.clear ();
   innermost_block.reset (tracker_types);
 
   if (*stringptr == 0 || **stringptr == 0)
@@ -1287,337 +1285,6 @@  parse_float (const char *p, int len,
   return target_float_from_string (data, type, std::string (p, len));
 }
 
-/* Stuff for maintaining a stack of types.  Currently just used by C, but
-   probably useful for any language which declares its types "backwards".  */
-
-/* A helper function for insert_type and insert_type_address_space.
-   This does work of expanding the type stack and inserting the new
-   element, ELEMENT, into the stack at location SLOT.  */
-
-static void
-insert_into_type_stack (int slot, union type_stack_elt element)
-{
-  gdb_assert (slot <= type_stack.elements.size ());
-  type_stack.elements.insert (type_stack.elements.begin () + slot, element);
-}
-
-/* Insert a new type, TP, at the bottom of the type stack.  If TP is
-   tp_pointer, tp_reference or tp_rvalue_reference, it is inserted at the
-   bottom.  If TP is a qualifier, it is inserted at slot 1 (just above a
-   previous tp_pointer) if there is anything on the stack, or simply pushed
-   if the stack is empty.  Other values for TP are invalid.  */
-
-void
-insert_type (enum type_pieces tp)
-{
-  union type_stack_elt element;
-  int slot;
-
-  gdb_assert (tp == tp_pointer || tp == tp_reference
-	      || tp == tp_rvalue_reference || tp == tp_const
-	      || tp == tp_volatile);
-
-  /* If there is anything on the stack (we know it will be a
-     tp_pointer), insert the qualifier above it.  Otherwise, simply
-     push this on the top of the stack.  */
-  if (!type_stack.elements.empty () && (tp == tp_const || tp == tp_volatile))
-    slot = 1;
-  else
-    slot = 0;
-
-  element.piece = tp;
-  insert_into_type_stack (slot, element);
-}
-
-void
-push_type (enum type_pieces tp)
-{
-  type_stack_elt elt;
-  elt.piece = tp;
-  type_stack.elements.push_back (elt);
-}
-
-void
-push_type_int (int n)
-{
-  type_stack_elt elt;
-  elt.int_val = n;
-  type_stack.elements.push_back (elt);
-}
-
-/* Insert a tp_space_identifier and the corresponding address space
-   value into the stack.  STRING is the name of an address space, as
-   recognized by address_space_name_to_int.  If the stack is empty,
-   the new elements are simply pushed.  If the stack is not empty,
-   this function assumes that the first item on the stack is a
-   tp_pointer, and the new values are inserted above the first
-   item.  */
-
-void
-insert_type_address_space (struct expr_builder *pstate, char *string)
-{
-  union type_stack_elt element;
-  int slot;
-
-  /* If there is anything on the stack (we know it will be a
-     tp_pointer), insert the address space qualifier above it.
-     Otherwise, simply push this on the top of the stack.  */
-  if (!type_stack.elements.empty ())
-    slot = 1;
-  else
-    slot = 0;
-
-  element.piece = tp_space_identifier;
-  insert_into_type_stack (slot, element);
-  element.int_val = address_space_name_to_int (pstate->gdbarch (),
-					       string);
-  insert_into_type_stack (slot, element);
-}
-
-enum type_pieces
-pop_type (void)
-{
-  if (!type_stack.elements.empty ())
-    {
-      type_stack_elt elt = type_stack.elements.back ();
-      type_stack.elements.pop_back ();
-      return elt.piece;
-    }
-  return tp_end;
-}
-
-int
-pop_type_int (void)
-{
-  if (!type_stack.elements.empty ())
-    {
-      type_stack_elt elt = type_stack.elements.back ();
-      type_stack.elements.pop_back ();
-      return elt.int_val;
-    }
-  /* "Can't happen".  */
-  return 0;
-}
-
-/* Pop a type list element from the global type stack.  */
-
-static std::vector<struct type *> *
-pop_typelist (void)
-{
-  gdb_assert (!type_stack.elements.empty ());
-  type_stack_elt elt = type_stack.elements.back ();
-  type_stack.elements.pop_back ();
-  return elt.typelist_val;
-}
-
-/* Pop a type_stack element from the global type stack.  */
-
-static struct type_stack *
-pop_type_stack (void)
-{
-  gdb_assert (!type_stack.elements.empty ());
-  type_stack_elt elt = type_stack.elements.back ();
-  type_stack.elements.pop_back ();
-  return elt.stack_val;
-}
-
-/* Append the elements of the type stack FROM to the type stack TO.
-   Always returns TO.  */
-
-struct type_stack *
-append_type_stack (struct type_stack *to, struct type_stack *from)
-{
-  to->elements.insert (to->elements.end (), from->elements.begin (),
-		       from->elements.end ());
-  return to;
-}
-
-/* Push the type stack STACK as an element on the global type stack.  */
-
-void
-push_type_stack (struct type_stack *stack)
-{
-  type_stack_elt elt;
-  elt.stack_val = stack;
-  type_stack.elements.push_back (elt);
-  push_type (tp_type_stack);
-}
-
-/* Copy the global type stack into a newly allocated type stack and
-   return it.  The global stack is cleared.  The returned type stack
-   must be freed with delete.  */
-
-struct type_stack *
-get_type_stack (void)
-{
-  struct type_stack *result = new struct type_stack (std::move (type_stack));
-  type_stack.elements.clear ();
-  return result;
-}
-
-/* Push a function type with arguments onto the global type stack.
-   LIST holds the argument types.  If the final item in LIST is NULL,
-   then the function will be varargs.  */
-
-void
-push_typelist (std::vector<struct type *> *list)
-{
-  type_stack_elt elt;
-  elt.typelist_val = list;
-  type_stack.elements.push_back (elt);
-  push_type (tp_function_with_arguments);
-}
-
-/* Pop the type stack and return a type_instance_flags that
-   corresponds the const/volatile qualifiers on the stack.  This is
-   called by the C++ parser when parsing methods types, and as such no
-   other kind of type in the type stack is expected.  */
-
-type_instance_flags
-follow_type_instance_flags ()
-{
-  type_instance_flags flags = 0;
-
-  for (;;)
-    switch (pop_type ())
-      {
-      case tp_end:
-	return flags;
-      case tp_const:
-	flags |= TYPE_INSTANCE_FLAG_CONST;
-	break;
-      case tp_volatile:
-	flags |= TYPE_INSTANCE_FLAG_VOLATILE;
-	break;
-      default:
-	gdb_assert_not_reached ("unrecognized tp_ value in follow_types");
-      }
-}
-
-
-/* Pop the type stack and return the type which corresponds to FOLLOW_TYPE
-   as modified by all the stuff on the stack.  */
-struct type *
-follow_types (struct type *follow_type)
-{
-  int done = 0;
-  int make_const = 0;
-  int make_volatile = 0;
-  int make_addr_space = 0;
-  int array_size;
-
-  while (!done)
-    switch (pop_type ())
-      {
-      case tp_end:
-	done = 1;
-	if (make_const)
-	  follow_type = make_cv_type (make_const, 
-				      TYPE_VOLATILE (follow_type), 
-				      follow_type, 0);
-	if (make_volatile)
-	  follow_type = make_cv_type (TYPE_CONST (follow_type), 
-				      make_volatile, 
-				      follow_type, 0);
-	if (make_addr_space)
-	  follow_type = make_type_with_address_space (follow_type, 
-						      make_addr_space);
-	make_const = make_volatile = 0;
-	make_addr_space = 0;
-	break;
-      case tp_const:
-	make_const = 1;
-	break;
-      case tp_volatile:
-	make_volatile = 1;
-	break;
-      case tp_space_identifier:
-	make_addr_space = pop_type_int ();
-	break;
-      case tp_pointer:
-	follow_type = lookup_pointer_type (follow_type);
-	if (make_const)
-	  follow_type = make_cv_type (make_const, 
-				      TYPE_VOLATILE (follow_type), 
-				      follow_type, 0);
-	if (make_volatile)
-	  follow_type = make_cv_type (TYPE_CONST (follow_type), 
-				      make_volatile, 
-				      follow_type, 0);
-	if (make_addr_space)
-	  follow_type = make_type_with_address_space (follow_type, 
-						      make_addr_space);
-	make_const = make_volatile = 0;
-	make_addr_space = 0;
-	break;
-      case tp_reference:
-	 follow_type = lookup_lvalue_reference_type (follow_type);
-	 goto process_reference;
-	case tp_rvalue_reference:
-	 follow_type = lookup_rvalue_reference_type (follow_type);
-	process_reference:
-	 if (make_const)
-	   follow_type = make_cv_type (make_const,
-				       TYPE_VOLATILE (follow_type),
-				       follow_type, 0);
-	 if (make_volatile)
-	   follow_type = make_cv_type (TYPE_CONST (follow_type),
-				       make_volatile,
-				       follow_type, 0);
-	 if (make_addr_space)
-	   follow_type = make_type_with_address_space (follow_type,
-						       make_addr_space);
-	make_const = make_volatile = 0;
-	make_addr_space = 0;
-	break;
-      case tp_array:
-	array_size = pop_type_int ();
-	/* FIXME-type-allocation: need a way to free this type when we are
-	   done with it.  */
-	follow_type =
-	  lookup_array_range_type (follow_type,
-				   0, array_size >= 0 ? array_size - 1 : 0);
-	if (array_size < 0)
-	  TYPE_HIGH_BOUND_KIND (TYPE_INDEX_TYPE (follow_type))
-	    = PROP_UNDEFINED;
-	break;
-      case tp_function:
-	/* FIXME-type-allocation: need a way to free this type when we are
-	   done with it.  */
-	follow_type = lookup_function_type (follow_type);
-	break;
-
-      case tp_function_with_arguments:
-	{
-	  std::vector<struct type *> *args = pop_typelist ();
-
-	  follow_type
-	    = lookup_function_type_with_arguments (follow_type,
-						   args->size (),
-						   args->data ());
-	}
-	break;
-
-      case tp_type_stack:
-	{
-	  struct type_stack *stack = pop_type_stack ();
-	  /* Sort of ugly, but not really much worse than the
-	     alternatives.  */
-	  struct type_stack save = type_stack;
-
-	  type_stack = *stack;
-	  follow_type = follow_types (follow_type);
-	  gdb_assert (type_stack.elements.empty ());
-
-	  type_stack = save;
-	}
-	break;
-      default:
-	gdb_assert_not_reached ("unrecognized tp_ value in follow_types");
-      }
-  return follow_type;
-}
-
 /* This function avoids direct calls to fprintf 
    in the parser generated debug code.  */
 void
diff --git a/gdb/parser-defs.h b/gdb/parser-defs.h
index 2c1ea15d05e..edbd3b7b673 100644
--- a/gdb/parser-defs.h
+++ b/gdb/parser-defs.h
@@ -299,40 +299,6 @@  struct objc_class_str
     int theclass;
   };
 
-/* For parsing of complicated types.
-   An array should be preceded in the list by the size of the array.  */
-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_type_stack,
-    tp_kind
-  };
-/* The stack can contain either an enum type_pieces or an int.  */
-union type_stack_elt
-  {
-    enum type_pieces piece;
-    int int_val;
-    struct type_stack *stack_val;
-    std::vector<struct type *> *typelist_val;
-  };
-
-/* The type stack is an instance of this structure.  */
-
-struct type_stack
-{
-  /* Elements on the stack.  */
-  std::vector<union type_stack_elt> elements;
-};
-
 /* Reverse an expression from suffix form (in which it is constructed)
    to prefix form (in which we can conveniently print or execute it).
    Ordinarily this always returns -1.  However, if LAST_STRUCT
@@ -376,27 +342,6 @@  extern const char *find_template_name_end (const char *);
 
 extern char *copy_name (struct stoken);
 
-extern void insert_type (enum type_pieces);
-
-extern void push_type (enum type_pieces);
-
-extern void push_type_int (int);
-
-extern void insert_type_address_space (struct expr_builder *, char *);
-
-extern enum type_pieces pop_type (void);
-
-extern int pop_type_int (void);
-
-extern struct type_stack *get_type_stack (void);
-
-extern struct type_stack *append_type_stack (struct type_stack *to,
-					     struct type_stack *from);
-
-extern void push_type_stack (struct type_stack *stack);
-
-extern void push_typelist (std::vector<struct type *> *typelist);
-
 extern int dump_subexp (struct expression *, struct ui_file *, int);
 
 extern int dump_subexp_body_standard (struct expression *, 
@@ -414,10 +359,6 @@  extern int operator_check_standard (struct expression *exp, int pos,
 
 extern const char *op_name_standard (enum exp_opcode);
 
-extern struct type *follow_types (struct type *);
-
-extern type_instance_flags follow_type_instance_flags ();
-
 extern void null_post_parser (expression_up *, int, int);
 
 extern bool parse_float (const char *p, int len,
diff --git a/gdb/type-stack.c b/gdb/type-stack.c
new file mode 100644
index 00000000000..cb0c147d307
--- /dev/null
+++ b/gdb/type-stack.c
@@ -0,0 +1,209 @@ 
+/* Type stack for GDB parser.
+
+   Copyright (C) 1986-2019 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "type-stack.h"
+
+#include "gdbtypes.h"
+#include "parser-defs.h"
+
+/* See type-stack.h.  */
+
+void
+type_stack::insert (enum type_pieces tp)
+{
+  union type_stack_elt element;
+  int slot;
+
+  gdb_assert (tp == tp_pointer || tp == tp_reference
+	      || tp == tp_rvalue_reference || tp == tp_const
+	      || tp == tp_volatile);
+
+  /* If there is anything on the stack (we know it will be a
+     tp_pointer), insert the qualifier above it.  Otherwise, simply
+     push this on the top of the stack.  */
+  if (!m_elements.empty () && (tp == tp_const || tp == tp_volatile))
+    slot = 1;
+  else
+    slot = 0;
+
+  element.piece = tp;
+  insert_into (slot, element);
+}
+
+/* See type-stack.h.  */
+
+void
+type_stack::insert (struct expr_builder *pstate, char *string)
+{
+  union type_stack_elt element;
+  int slot;
+
+  /* If there is anything on the stack (we know it will be a
+     tp_pointer), insert the address space qualifier above it.
+     Otherwise, simply push this on the top of the stack.  */
+  if (!m_elements.empty ())
+    slot = 1;
+  else
+    slot = 0;
+
+  element.piece = tp_space_identifier;
+  insert_into (slot, element);
+  element.int_val = address_space_name_to_int (pstate->gdbarch (),
+					       string);
+  insert_into (slot, element);
+}
+
+/* See type-stack.h.  */
+
+type_instance_flags
+type_stack::follow_type_instance_flags ()
+{
+  type_instance_flags flags = 0;
+
+  for (;;)
+    switch (pop ())
+      {
+      case tp_end:
+	return flags;
+      case tp_const:
+	flags |= TYPE_INSTANCE_FLAG_CONST;
+	break;
+      case tp_volatile:
+	flags |= TYPE_INSTANCE_FLAG_VOLATILE;
+	break;
+      default:
+	gdb_assert_not_reached ("unrecognized tp_ value in follow_types");
+      }
+}
+
+/* See type-stack.h.  */
+
+struct type *
+type_stack::follow_types (struct type *follow_type)
+{
+  int done = 0;
+  int make_const = 0;
+  int make_volatile = 0;
+  int make_addr_space = 0;
+  int array_size;
+
+  while (!done)
+    switch (pop ())
+      {
+      case tp_end:
+	done = 1;
+	if (make_const)
+	  follow_type = make_cv_type (make_const, 
+				      TYPE_VOLATILE (follow_type), 
+				      follow_type, 0);
+	if (make_volatile)
+	  follow_type = make_cv_type (TYPE_CONST (follow_type), 
+				      make_volatile, 
+				      follow_type, 0);
+	if (make_addr_space)
+	  follow_type = make_type_with_address_space (follow_type, 
+						      make_addr_space);
+	make_const = make_volatile = 0;
+	make_addr_space = 0;
+	break;
+      case tp_const:
+	make_const = 1;
+	break;
+      case tp_volatile:
+	make_volatile = 1;
+	break;
+      case tp_space_identifier:
+	make_addr_space = pop_int ();
+	break;
+      case tp_pointer:
+	follow_type = lookup_pointer_type (follow_type);
+	if (make_const)
+	  follow_type = make_cv_type (make_const, 
+				      TYPE_VOLATILE (follow_type), 
+				      follow_type, 0);
+	if (make_volatile)
+	  follow_type = make_cv_type (TYPE_CONST (follow_type), 
+				      make_volatile, 
+				      follow_type, 0);
+	if (make_addr_space)
+	  follow_type = make_type_with_address_space (follow_type, 
+						      make_addr_space);
+	make_const = make_volatile = 0;
+	make_addr_space = 0;
+	break;
+      case tp_reference:
+	 follow_type = lookup_lvalue_reference_type (follow_type);
+	 goto process_reference;
+	case tp_rvalue_reference:
+	 follow_type = lookup_rvalue_reference_type (follow_type);
+	process_reference:
+	 if (make_const)
+	   follow_type = make_cv_type (make_const,
+				       TYPE_VOLATILE (follow_type),
+				       follow_type, 0);
+	 if (make_volatile)
+	   follow_type = make_cv_type (TYPE_CONST (follow_type),
+				       make_volatile,
+				       follow_type, 0);
+	 if (make_addr_space)
+	   follow_type = make_type_with_address_space (follow_type,
+						       make_addr_space);
+	make_const = make_volatile = 0;
+	make_addr_space = 0;
+	break;
+      case tp_array:
+	array_size = pop_int ();
+	/* FIXME-type-allocation: need a way to free this type when we are
+	   done with it.  */
+	follow_type =
+	  lookup_array_range_type (follow_type,
+				   0, array_size >= 0 ? array_size - 1 : 0);
+	if (array_size < 0)
+	  TYPE_HIGH_BOUND_KIND (TYPE_INDEX_TYPE (follow_type))
+	    = PROP_UNDEFINED;
+	break;
+      case tp_function:
+	/* FIXME-type-allocation: need a way to free this type when we are
+	   done with it.  */
+	follow_type = lookup_function_type (follow_type);
+	break;
+
+      case tp_function_with_arguments:
+	{
+	  std::vector<struct type *> *args = pop_typelist ();
+
+	  follow_type
+	    = lookup_function_type_with_arguments (follow_type,
+						   args->size (),
+						   args->data ());
+	}
+	break;
+
+      case tp_type_stack:
+	{
+	  struct type_stack *stack = pop_type_stack ();
+	  follow_type = stack->follow_types (follow_type);
+	}
+	break;
+      default:
+	gdb_assert_not_reached ("unrecognized tp_ value in follow_types");
+      }
+  return follow_type;
+}
diff --git a/gdb/type-stack.h b/gdb/type-stack.h
new file mode 100644
index 00000000000..a2ac0a604a3
--- /dev/null
+++ b/gdb/type-stack.h
@@ -0,0 +1,205 @@ 
+/* Type stack for GDB parser.
+
+   Copyright (C) 1986-2019 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef TYPE_STACK_H
+#define TYPE_STACK_H
+
+#include <vector>
+
+struct type;
+struct expr_builder;
+
+/* For parsing of complicated types.
+   An array should be preceded in the list by the size of the array.  */
+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_type_stack,
+    tp_kind
+  };
+
+/* The stack can contain either an enum type_pieces or an int.  */
+union type_stack_elt
+  {
+    enum type_pieces piece;
+    int int_val;
+    struct type_stack *stack_val;
+    std::vector<struct type *> *typelist_val;
+  };
+
+/* The type stack is an instance of this structure.  */
+
+struct type_stack
+{
+public:
+
+  type_stack ()
+  {
+  }
+
+  DISABLE_COPY_AND_ASSIGN (type_stack);
+
+  type_stack *create ()
+  {
+    type_stack *result = new type_stack ();
+    result->m_elements = std::move (m_elements);
+    return result;
+  }
+
+  /* Insert a new type, TP, at the bottom of the type stack.  If TP is
+     tp_pointer, tp_reference or tp_rvalue_reference, it is inserted at the
+     bottom.  If TP is a qualifier, it is inserted at slot 1 (just above a
+     previous tp_pointer) if there is anything on the stack, or simply pushed
+     if the stack is empty.  Other values for TP are invalid.  */
+
+  void insert (enum type_pieces tp);
+
+  void push (enum type_pieces tp)
+  {
+    type_stack_elt elt;
+    elt.piece = tp;
+    m_elements.push_back (elt);
+  }
+
+  void push (int n)
+  {
+    type_stack_elt elt;
+    elt.int_val = n;
+    m_elements.push_back (elt);
+  }
+
+  /* Push the type stack STACK as an element on this type stack.  */
+
+  void push (struct type_stack *stack)
+  {
+    type_stack_elt elt;
+    elt.stack_val = stack;
+    m_elements.push_back (elt);
+    push (tp_type_stack);
+  }
+
+  /* Push a function type with arguments onto the global 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)
+  {
+    type_stack_elt elt;
+    elt.typelist_val = list;
+    m_elements.push_back (elt);
+    push (tp_function_with_arguments);
+  }
+
+  enum type_pieces pop ()
+  {
+    if (m_elements.empty ())
+      return tp_end;
+    type_stack_elt elt = m_elements.back ();
+    m_elements.pop_back ();
+    return elt.piece;
+  }
+
+  int pop_int ()
+  {
+    if (m_elements.empty ())
+      {
+	/* "Can't happen".  */
+	return 0;
+      }
+    type_stack_elt elt = m_elements.back ();
+    m_elements.pop_back ();
+    return elt.int_val;
+  }
+
+  std::vector<struct type *> *pop_typelist ()
+  {
+    gdb_assert (!m_elements.empty ());
+    type_stack_elt elt = m_elements.back ();
+    m_elements.pop_back ();
+    return elt.typelist_val;
+  }
+
+  /* Pop a type_stack element.  */
+
+  struct type_stack *pop_type_stack ()
+  {
+    gdb_assert (!m_elements.empty ());
+    type_stack_elt elt = m_elements.back ();
+    m_elements.pop_back ();
+    return elt.stack_val;
+  }
+
+  /* Insert a tp_space_identifier and the corresponding address space
+     value into the stack.  STRING is the name of an address space, as
+     recognized by address_space_name_to_int.  If the stack is empty,
+     the new elements are simply pushed.  If the stack is not empty,
+     this function assumes that the first item on the stack is a
+     tp_pointer, and the new values are inserted above the first
+     item.  */
+
+  void insert (struct expr_builder *pstate, char *string);
+
+  /* Append the elements of the type stack FROM to the type stack
+     THIS.  Always returns THIS.  */
+
+  struct type_stack *append (struct type_stack *from)
+  {
+    m_elements.insert (m_elements.end (), from->m_elements.begin (),
+		       from->m_elements.end ());
+    return this;
+  }
+
+  /* Pop the type stack and return a type_instance_flags that
+     corresponds the const/volatile qualifiers on the stack.  This is
+     called by the C++ parser when parsing methods types, and as such no
+     other kind of type in the type stack is expected.  */
+
+  type_instance_flags follow_type_instance_flags ();
+
+  /* Pop the type stack and return the type which corresponds to
+     FOLLOW_TYPE as modified by all the stuff on the stack.  */
+  struct type *follow_types (struct type *follow_type);
+
+private:
+
+  /* A helper function for insert_type and insert_type_address_space.
+     This does work of expanding the type stack and inserting the new
+     element, ELEMENT, into the stack at location SLOT.  */
+
+  void insert_into (int slot, union type_stack_elt element)
+  {
+    gdb_assert (slot <= m_elements.size ());
+    m_elements.insert (m_elements.begin () + slot, element);
+  }
+
+
+  /* Elements on the stack.  */
+  std::vector<union type_stack_elt> m_elements;
+};
+
+#endif /* TYPE_STACK_H */