This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH 3/5] Fix typename parsing regression


This fixes the typename parsing regressions I introduced.

Basically the issue was one of dealing properly with precedence in
typenames.  I looked at a few solutions, but the simplest was to give
the parser the ability to package up the current type stack as an
object, and then push it onto the global type stack as a kind of
subroutine.

Built and regtested on x86-64 Fedora 16.
New regression tests included.

	* c-exp.y (%union) <type_stack>: New field.
	(abs_decl, direct_abs_decl): Use <type_stack> type.  Update.
	(ptr_operator_ts): New production.
	(ptype): Update.
	* parse.c (type_stack_reserve): New function.
	(check_type_stack_depth): Use it.
	(pop_type_stack, append_type_stack, push_type_stack)
	(get_type_stack, type_stack_cleanup): New functions.
	(follow_types): Handle tp_type_stack.
	(_initialize_parse): Simplify initialization.
	* parser-defs.h (enum type_pieces) <tp_type_stack>: New
	constant.
	(union type_stack_elt) <stack_val>: New field.
	(get_type_stack, append_type_stack, push_type_stack)
	(type_stack_cleanup): Declare.

	* gdb.base/whatis.exp: Add tests.
---
 gdb/c-exp.y                       |   38 +++++++++++--
 gdb/parse.c                       |  107 +++++++++++++++++++++++++++++++++---
 gdb/parser-defs.h                 |   13 ++++-
 gdb/testsuite/gdb.base/whatis.exp |   12 ++++
 4 files changed, 155 insertions(+), 15 deletions(-)

diff --git a/gdb/c-exp.y b/gdb/c-exp.y
index f86f76f..5ea5704 100644
--- a/gdb/c-exp.y
+++ b/gdb/c-exp.y
@@ -157,6 +157,8 @@ void yyerror (char *);
     struct stoken_vector svec;
     struct type **tvec;
     int *ivec;
+
+    struct type_stack *type_stack;
   }
 
 %{
@@ -176,6 +178,8 @@ static struct stoken operator_stoken (const char *);
 %type <lval> array_mod
 %type <tval> conversion_type_id
 
+%type <type_stack> ptr_operator_ts abs_decl direct_abs_decl
+
 %token <typed_val_int> INT
 %token <typed_val_float> FLOAT
 %token <typed_val_decfloat> DECFLOAT
@@ -963,27 +967,48 @@ ptr_operator:
 			{ insert_type (tp_reference); }
 	;
 
-abs_decl:	ptr_operator direct_abs_decl
-	|	ptr_operator
+ptr_operator_ts: ptr_operator
+			{
+			  $$ = get_type_stack ();
+			  /* This cleanup is eventually run by
+			     c_parse.  */
+			  make_cleanup (type_stack_cleanup, $$);
+			}
+	;
+
+abs_decl:	ptr_operator_ts direct_abs_decl
+			{ $$ = append_type_stack ($2, $1); }
+	|	ptr_operator_ts 
 	|	direct_abs_decl
 	;
 
 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 ();
 			}
 	|	array_mod
 			{
 			  push_type_int ($1);
 			  push_type (tp_array);
+			  $$ = get_type_stack ();
 			}
 
 	| 	direct_abs_decl func_mod
-			{ push_type (tp_function); }
+			{
+			  push_type_stack ($1);
+			  push_type (tp_function);
+			  $$ = get_type_stack ();
+			}
 	|	func_mod
-			{ push_type (tp_function); }
+			{
+			  push_type (tp_function);
+			  $$ = get_type_stack ();
+			}
 	;
 
 array_mod:	'[' ']'
@@ -1206,7 +1231,10 @@ nonempty_typelist
 
 ptype	:	typebase
 	|	ptype abs_decl
-		{ $$ = follow_types ($1); }
+		{
+		  push_type_stack ($2);
+		  $$ = follow_types ($1);
+		}
 	;
 
 conversion_type_id: typebase conversion_declarator
diff --git a/gdb/parse.c b/gdb/parse.c
index 83f7fec..b1ad832 100644
--- a/gdb/parse.c
+++ b/gdb/parse.c
@@ -1358,18 +1358,29 @@ parse_c_float (struct gdbarch *gdbarch, const char *p, int len,
 /* Stuff for maintaining a stack of types.  Currently just used by C, but
    probably useful for any language which declares its types "backwards".  */
 
+/* Ensure that there are HOWMUCH open slots on the type stack STACK.  */
+
 static void
-check_type_stack_depth (void)
+type_stack_reserve (struct type_stack *stack, int howmuch)
 {
-  if (type_stack.depth == type_stack.size)
+  if (stack->depth + howmuch >= stack->size)
     {
-      type_stack.size *= 2;
-      type_stack.elements
-	= xrealloc (type_stack.elements,
-		    type_stack.size * sizeof (union type_stack_elt));
+      stack->size *= 2;
+      if (stack->size < howmuch)
+	stack->size = howmuch;
+      stack->elements = xrealloc (stack->elements,
+				  stack->size * sizeof (union type_stack_elt));
     }
 }
 
+/* Ensure that there is a single open slot in the global type stack.  */
+
+static void
+check_type_stack_depth (void)
+{
+  type_stack_reserve (&type_stack, 1);
+}
+
 /* 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.  */
@@ -1472,6 +1483,68 @@ pop_type_int (void)
   return 0;
 }
 
+/* Pop a type_stack element from the global type stack.  */
+
+static struct type_stack *
+pop_type_stack (void)
+{
+  gdb_assert (type_stack.depth);
+  return type_stack.elements[--type_stack.depth].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)
+{
+  type_stack_reserve (to, from->depth);
+
+  memcpy (&to->elements[to->depth], &from->elements[0],
+	  from->depth * sizeof (union type_stack_elt));
+  to->depth += from->depth;
+
+  return to;
+}
+
+/* Push the type stack STACK as an element on the global type stack.  */
+
+void
+push_type_stack (struct type_stack *stack)
+{
+  check_type_stack_depth ();
+  type_stack.elements[type_stack.depth++].stack_val = stack;
+  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 type_stack_cleanup.  */
+
+struct type_stack *
+get_type_stack (void)
+{
+  struct type_stack *result = XNEW (struct type_stack);
+
+  *result = type_stack;
+  type_stack.depth = 0;
+  type_stack.size = 0;
+  type_stack.elements = NULL;
+
+  return result;
+}
+
+/* A cleanup function that destroys a single type stack.  */
+
+void
+type_stack_cleanup (void *arg)
+{
+  struct type_stack *stack = arg;
+
+  xfree (stack->elements);
+  xfree (stack);
+}
+
 /* Pop the type stack and return the type which corresponds to FOLLOW_TYPE
    as modified by all the stuff on the stack.  */
 struct type *
@@ -1558,6 +1631,23 @@ follow_types (struct type *follow_type)
 	   done with it.  */
 	follow_type = lookup_function_type (follow_type);
 	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.depth == 0);
+
+	  type_stack = save;
+	}
+	break;
+      default:
+	gdb_assert_not_reached ("unrecognized tp_ value in follow_types");
       }
   return follow_type;
 }
@@ -1725,10 +1815,9 @@ exp_uses_objfile (struct expression *exp, struct objfile *objfile)
 void
 _initialize_parse (void)
 {
-  type_stack.size = 80;
+  type_stack.size = 0;
   type_stack.depth = 0;
-  type_stack.elements = xmalloc (type_stack.size
-				 * sizeof (union type_stack_elt));
+  type_stack.elements = NULL;
 
   add_setshow_zinteger_cmd ("expression", class_maintenance,
 			    &expressiondebug,
diff --git a/gdb/parser-defs.h b/gdb/parser-defs.h
index de283d0..0649189 100644
--- a/gdb/parser-defs.h
+++ b/gdb/parser-defs.h
@@ -119,13 +119,15 @@ enum type_pieces
     tp_function, 
     tp_const, 
     tp_volatile, 
-    tp_space_identifier
+    tp_space_identifier,
+    tp_type_stack
   };
 /* 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;
   };
 
 /* The type stack is an instance of this structure.  */
@@ -214,6 +216,15 @@ 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 type_stack_cleanup (void *arg);
+
 extern int length_of_subexp (struct expression *, int);
 
 extern int dump_subexp (struct expression *, struct ui_file *, int);
diff --git a/gdb/testsuite/gdb.base/whatis.exp b/gdb/testsuite/gdb.base/whatis.exp
index dda3a02..71f2e79 100644
--- a/gdb/testsuite/gdb.base/whatis.exp
+++ b/gdb/testsuite/gdb.base/whatis.exp
@@ -479,3 +479,15 @@ gdb_test "whatis void (** const)()" \
 gdb_test "whatis void (* const *)()" \
   "type = void \\(\\* const \\*\\)\\(\\)" \
   "whatis applied to pointer to const pointer to function"
+
+gdb_test "whatis int *(*)()" \
+    "type = int \\*\\(\\*\\)\\(\\)" \
+    "whatis applied to pointer to function returning pointer to int"
+
+gdb_test "whatis int *(**)()" \
+    "type = int \\*\\(\\*\\*\\)\\(\\)" \
+    "whatis applied to pointer to pointer to function returning pointer to int"
+
+gdb_test "whatis char (*(*)())\[23\]" \
+    "type = char \\(\\*\\(\\*\\)\\(\\)\\)\\\[23\\\]" \
+    "whatis applied to pointer to function returning pointer to array"
-- 
1.7.7.6


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]