[PATCH 1/3] introduce UNOP_CAST_TYPE and UNOP_MEMVAL_TYPE

Tom Tromey tromey@redhat.com
Thu Jul 19 15:33:00 GMT 2012


This patch introduces UNOP_CAST_TYPE and UNOP_MEMVAL_TYPE.  These are
like UNOP_CAST and UNOP_MEMVAL, but take the type argument as an
expression.

This patch is just preparation for a subsequent patch, which uses this
new functionality to (mostly) implement typeof.  typeof needs to take
an expression as an argument; and because expression type resolution
is generally deferred to evaluation time in gdb, typeof must also be
implemented this way.

This patch also changes the representation of UNOP_REINTERPRET_CAST
and UNOP_DYNAMIC_CAST to follow.  These are only ever generated by the
C++ parser and it seemed simplest to just have a single representation
for them.

Finally, this fixes a latent bug in watchpoint_exp_is_const that I
noticed while writing this patch.

	* ax-gdb.c (gen_expr): Handle UNOP_CAST_TYPE, UNOP_MEMVAL_TYPE.
	* breakpoint.c (watchpoint_exp_is_const): Handle UNOP_CAST_TYPE,
	UNOP_REINTERPRET_CAST, UNOP_DYNAMIC_CAST.
	* c-exp.y (exp): Emit UNOP_MEMVAL_TYPE, UNOP_CAST_TYPE.  Update
	for changes to UNOP_REINTERPRET_CAST, UNOP_DYNAMIC_CAST.  Use
	type_exp production where appropriate.
	* eval.c (evaluate_subexp_standard) <UNOP_CAST_TYPE>: New case.
	<UNOP_DYNAMIC_CAST, UNOP_REINTERPRET_CAST>: Update.
	<UNOP_MEMVAL_TYPE>: New case.
	(evaluate_subexp_for_address) <UNOP_MEMVAL_TYPE>: New case.
	(evaluate_subexp_for_sizeof) <UNOP_MEMVAL_TYPE>: New case.
	* expprint.c (print_subexp_standard) <UNOP_CAST_TYPE>: New case.
	<UNOP_MEMVAL_TYPE>: New case.
	(dump_subexp_body_standard) <UNOP_DYNAMIC_CAST,
	UNOP_REINTERPRET_CAST>: Update.
	<UNOP_CAST_TYPE, UNOP_MEMVAL_TYPE>: New cases.
	* parse.c (operator_length_standard) <UNOP_DYNAMIC_CAST,
	UNOP_REINTERPRET_CAST>: Update.
	<UNOP_CAST_TYPE, UNOP_MEMVAL_TYPE>: New cases.
	* stack.c (return_command): Also check for UNOP_CAST_TYPE.
	* std-operator.def (UNOP_CAST_TYPE, UNOP_MEMVAL_TYPE): New
	constants.
---
 gdb/ax-gdb.c         |   42 ++++++++++++++++++++++++++++++++++++++++++
 gdb/breakpoint.c     |    4 ++++
 gdb/c-exp.y          |   36 ++++++++++++------------------------
 gdb/eval.c           |   47 +++++++++++++++++++++++++++++++++++++++++++----
 gdb/expprint.c       |   40 ++++++++++++++++++++++++++++++++++++----
 gdb/parse.c          |   12 ++++++++----
 gdb/stack.c          |    3 ++-
 gdb/std-operator.def |    6 ++++++
 8 files changed, 153 insertions(+), 37 deletions(-)

diff --git a/gdb/ax-gdb.c b/gdb/ax-gdb.c
index 845153d..2db56bf 100644
--- a/gdb/ax-gdb.c
+++ b/gdb/ax-gdb.c
@@ -2076,6 +2076,23 @@ gen_expr (struct expression *exp, union exp_element **pc,
       }
       break;
 
+    case UNOP_CAST_TYPE:
+      {
+	int offset;
+	struct value *val;
+	struct type *type;
+
+	++*pc;
+	offset = *pc - exp->elts;
+	val = evaluate_subexp (NULL, exp, &offset, EVAL_AVOID_SIDE_EFFECTS);
+	type = value_type (val);
+	*pc = &exp->elts[offset];
+
+	gen_expr (exp, pc, ax, value);
+	gen_cast (ax, value, type);
+      }
+      break;
+
     case UNOP_MEMVAL:
       {
 	struct type *type = check_typedef ((*pc)[1].type);
@@ -2094,6 +2111,31 @@ gen_expr (struct expression *exp, union exp_element **pc,
       }
       break;
 
+    case UNOP_MEMVAL_TYPE:
+      {
+	int offset;
+	struct value *val;
+	struct type *type;
+
+	++*pc;
+	offset = *pc - exp->elts;
+	val = evaluate_subexp (NULL, exp, &offset, EVAL_AVOID_SIDE_EFFECTS);
+	type = value_type (val);
+	*pc = &exp->elts[offset];
+
+	gen_expr (exp, pc, ax, value);
+
+	/* If we have an axs_rvalue or an axs_lvalue_memory, then we
+	   already have the right value on the stack.  For
+	   axs_lvalue_register, we must convert.  */
+	if (value->kind == axs_lvalue_register)
+	  require_rvalue (ax, value);
+
+	value->type = type;
+	value->kind = axs_lvalue_memory;
+      }
+      break;
+
     case UNOP_PLUS:
       (*pc)++;
       /* + FOO is equivalent to 0 + FOO, which can be optimized.  */
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 665a18d..72eb673 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -10163,6 +10163,10 @@ watchpoint_exp_is_const (const struct expression *exp)
 	case UNOP_ADDR:
 	case UNOP_HIGH:
 	case UNOP_CAST:
+
+	case UNOP_CAST_TYPE:
+	case UNOP_REINTERPRET_CAST:
+	case UNOP_DYNAMIC_CAST:
 	  /* Unary, binary and ternary operators: We have to check
 	     their operands.  If they are constant, then so is the
 	     result of that operation.  For instance, if A and B are
diff --git a/gdb/c-exp.y b/gdb/c-exp.y
index 0613799..e36a0fb 100644
--- a/gdb/c-exp.y
+++ b/gdb/c-exp.y
@@ -471,16 +471,12 @@ exp	:	lcurly arglist rcurly	%prec ARROW
 			  write_exp_elt_opcode (OP_ARRAY); }
 	;
 
-exp	:	lcurly type rcurly exp  %prec UNARY
-			{ write_exp_elt_opcode (UNOP_MEMVAL);
-			  write_exp_elt_type ($2);
-			  write_exp_elt_opcode (UNOP_MEMVAL); }
+exp	:	lcurly type_exp rcurly exp  %prec UNARY
+			{ write_exp_elt_opcode (UNOP_MEMVAL_TYPE); }
 	;
 
-exp	:	'(' type ')' exp  %prec UNARY
-			{ write_exp_elt_opcode (UNOP_CAST);
-			  write_exp_elt_type ($2);
-			  write_exp_elt_opcode (UNOP_CAST); }
+exp	:	'(' type_exp ')' exp  %prec UNARY
+			{ write_exp_elt_opcode (UNOP_CAST_TYPE); }
 	;
 
 exp	:	'(' exp1 ')'
@@ -639,30 +635,22 @@ exp	:	SIZEOF '(' type ')'	%prec UNARY
 			  write_exp_elt_opcode (OP_LONG); }
 	;
 
-exp	:	REINTERPRET_CAST '<' type '>' '(' exp ')' %prec UNARY
-			{ write_exp_elt_opcode (UNOP_REINTERPRET_CAST);
-			  write_exp_elt_type ($3);
-			  write_exp_elt_opcode (UNOP_REINTERPRET_CAST); }
+exp	:	REINTERPRET_CAST '<' type_exp '>' '(' exp ')' %prec UNARY
+			{ write_exp_elt_opcode (UNOP_REINTERPRET_CAST); }
 	;
 
-exp	:	STATIC_CAST '<' type '>' '(' exp ')' %prec UNARY
-			{ write_exp_elt_opcode (UNOP_CAST);
-			  write_exp_elt_type ($3);
-			  write_exp_elt_opcode (UNOP_CAST); }
+exp	:	STATIC_CAST '<' type_exp '>' '(' exp ')' %prec UNARY
+			{ write_exp_elt_opcode (UNOP_CAST_TYPE); }
 	;
 
-exp	:	DYNAMIC_CAST '<' type '>' '(' exp ')' %prec UNARY
-			{ write_exp_elt_opcode (UNOP_DYNAMIC_CAST);
-			  write_exp_elt_type ($3);
-			  write_exp_elt_opcode (UNOP_DYNAMIC_CAST); }
+exp	:	DYNAMIC_CAST '<' type_exp '>' '(' exp ')' %prec UNARY
+			{ write_exp_elt_opcode (UNOP_DYNAMIC_CAST); }
 	;
 
-exp	:	CONST_CAST '<' type '>' '(' exp ')' %prec UNARY
+exp	:	CONST_CAST '<' type_exp '>' '(' exp ')' %prec UNARY
 			{ /* We could do more error checking here, but
 			     it doesn't seem worthwhile.  */
-			  write_exp_elt_opcode (UNOP_CAST);
-			  write_exp_elt_type ($3);
-			  write_exp_elt_opcode (UNOP_CAST); }
+			  write_exp_elt_opcode (UNOP_CAST_TYPE); }
 	;
 
 string_exp:
diff --git a/gdb/eval.c b/gdb/eval.c
index 7d3a8b9..a012873 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -2707,17 +2707,27 @@ evaluate_subexp_standard (struct type *expect_type,
 	arg1 = value_cast (type, arg1);
       return arg1;
 
+    case UNOP_CAST_TYPE:
+      arg1 = evaluate_subexp (NULL, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
+      type = value_type (arg1);
+      arg1 = evaluate_subexp (type, exp, pos, noside);
+      if (noside == EVAL_SKIP)
+	goto nosideret;
+      if (type != value_type (arg1))
+	arg1 = value_cast (type, arg1);
+      return arg1;
+
     case UNOP_DYNAMIC_CAST:
-      (*pos) += 2;
-      type = exp->elts[pc + 1].type;
+      arg1 = evaluate_subexp (NULL, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
+      type = value_type (arg1);
       arg1 = evaluate_subexp (type, exp, pos, noside);
       if (noside == EVAL_SKIP)
 	goto nosideret;
       return value_dynamic_cast (type, arg1);
 
     case UNOP_REINTERPRET_CAST:
-      (*pos) += 2;
-      type = exp->elts[pc + 1].type;
+      arg1 = evaluate_subexp (NULL, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
+      type = value_type (arg1);
       arg1 = evaluate_subexp (type, exp, pos, noside);
       if (noside == EVAL_SKIP)
 	goto nosideret;
@@ -2734,6 +2744,18 @@ evaluate_subexp_standard (struct type *expect_type,
 	return value_at_lazy (exp->elts[pc + 1].type,
 			      value_as_address (arg1));
 
+    case UNOP_MEMVAL_TYPE:
+      arg1 = evaluate_subexp (NULL, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
+      type = value_type (arg1);
+      arg1 = evaluate_subexp (expect_type, exp, pos, noside);
+      if (noside == EVAL_SKIP)
+	goto nosideret;
+      if (noside == EVAL_AVOID_SIDE_EFFECTS)
+	return value_zero (exp->elts[pc + 1].type, lval_memory);
+      else
+	return value_at_lazy (exp->elts[pc + 1].type,
+			      value_as_address (arg1));
+
     case UNOP_MEMVAL_TLS:
       (*pos) += 3;
       arg1 = evaluate_subexp (expect_type, exp, pos, noside);
@@ -2936,6 +2958,17 @@ evaluate_subexp_for_address (struct expression *exp, int *pos,
       return value_cast (lookup_pointer_type (exp->elts[pc + 1].type),
 			 evaluate_subexp (NULL_TYPE, exp, pos, noside));
 
+    case UNOP_MEMVAL_TYPE:
+      {
+	struct type *type;
+
+	(*pos) += 1;
+	x = evaluate_subexp (NULL_TYPE, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
+	type = value_type (x);
+	return value_cast (lookup_pointer_type (type),
+			   evaluate_subexp (NULL_TYPE, exp, pos, noside));
+      }
+
     case OP_VAR_VALUE:
       var = exp->elts[pc + 2].symbol;
 
@@ -3078,6 +3111,12 @@ evaluate_subexp_for_sizeof (struct expression *exp, int *pos)
       type = check_typedef (exp->elts[pc + 1].type);
       return value_from_longest (size_type, (LONGEST) TYPE_LENGTH (type));
 
+    case UNOP_MEMVAL_TYPE:
+      (*pos) += 1;
+      val = evaluate_subexp (NULL, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
+      type = check_typedef (value_type (val));
+      return value_from_longest (size_type, (LONGEST) TYPE_LENGTH (type));
+
     case OP_VAR_VALUE:
       (*pos) += 4;
       type = check_typedef (SYMBOL_TYPE (exp->elts[pc + 2].symbol));
diff --git a/gdb/expprint.c b/gdb/expprint.c
index 6915d43..c3f6697 100644
--- a/gdb/expprint.c
+++ b/gdb/expprint.c
@@ -429,13 +429,25 @@ print_subexp_standard (struct expression *exp, int *pos,
 	fputs_filtered (")", stream);
       return;
 
+    case UNOP_CAST_TYPE:
+      (*pos) += 1;
+      if ((int) prec > (int) PREC_PREFIX)
+	fputs_filtered ("(", stream);
+      fputs_filtered ("(", stream);
+      print_subexp (exp, pos, stream, PREC_PREFIX);
+      fputs_filtered (") ", stream);
+      print_subexp (exp, pos, stream, PREC_PREFIX);
+      if ((int) prec > (int) PREC_PREFIX)
+	fputs_filtered (")", stream);
+      return;
+
     case UNOP_DYNAMIC_CAST:
     case UNOP_REINTERPRET_CAST:
       fputs_filtered (opcode == UNOP_DYNAMIC_CAST ? "dynamic_cast"
 		      : "reinterpret_cast", stream);
       fputs_filtered ("<", stream);
-      (*pos) += 2;
-      type_print (exp->elts[pc + 1].type, "", stream, 0);
+      (*pos) += 1;
+      print_subexp (exp, pos, stream, PREC_PREFIX);
       fputs_filtered ("> (", stream);
       print_subexp (exp, pos, stream, PREC_PREFIX);
       fputs_filtered (")", stream);
@@ -471,6 +483,18 @@ print_subexp_standard (struct expression *exp, int *pos,
 	fputs_filtered (")", stream);
       return;
 
+    case UNOP_MEMVAL_TYPE:
+      (*pos) += 1;
+      if ((int) prec > (int) PREC_PREFIX)
+	fputs_filtered ("(", stream);
+      fputs_filtered ("{", stream);
+      print_subexp (exp, pos, stream, PREC_PREFIX);
+      fputs_filtered ("} ", stream);
+      print_subexp (exp, pos, stream, PREC_PREFIX);
+      if ((int) prec > (int) PREC_PREFIX)
+	fputs_filtered (")", stream);
+      return;
+
     case UNOP_MEMVAL_TLS:
       (*pos) += 3;
       if ((int) prec > (int) PREC_PREFIX)
@@ -910,10 +934,18 @@ dump_subexp_body_standard (struct expression *exp,
 	  elt = dump_subexp (exp, stream, elt);
       }
       break;
-    case UNOP_MEMVAL:
-    case UNOP_CAST:
     case UNOP_DYNAMIC_CAST:
     case UNOP_REINTERPRET_CAST:
+    case UNOP_CAST_TYPE:
+    case UNOP_MEMVAL_TYPE:
+      ++elt;
+      fprintf_filtered (stream, " (");
+      elt = dump_subexp (exp, stream, elt);
+      fprintf_filtered (stream, ")");
+      elt = dump_subexp (exp, stream, elt);
+      break;
+    case UNOP_MEMVAL:
+    case UNOP_CAST:
       fprintf_filtered (stream, "Type @");
       gdb_print_host_address (exp->elts[elt].type, stream);
       fprintf_filtered (stream, " (");
diff --git a/gdb/parse.c b/gdb/parse.c
index 529c517..1f9addf 100644
--- a/gdb/parse.c
+++ b/gdb/parse.c
@@ -910,10 +910,16 @@ operator_length_standard (const struct expression *expr, int endpos,
       oplen = 3;
       break;
 
-    case BINOP_VAL:
-    case UNOP_CAST:
+    case UNOP_CAST_TYPE:
     case UNOP_DYNAMIC_CAST:
     case UNOP_REINTERPRET_CAST:
+    case UNOP_MEMVAL_TYPE:
+      oplen = 1;
+      args = 2;
+      break;
+
+    case BINOP_VAL:
+    case UNOP_CAST:
     case UNOP_MEMVAL:
       oplen = 3;
       args = 1;
@@ -1732,8 +1738,6 @@ operator_check_standard (struct expression *exp, int pos,
     case OP_SCOPE:
     case OP_TYPE:
     case UNOP_CAST:
-    case UNOP_DYNAMIC_CAST:
-    case UNOP_REINTERPRET_CAST:
     case UNOP_MAX:
     case UNOP_MEMVAL:
     case UNOP_MIN:
diff --git a/gdb/stack.c b/gdb/stack.c
index 35d379d..51747ea 100644
--- a/gdb/stack.c
+++ b/gdb/stack.c
@@ -2308,7 +2308,8 @@ return_command (char *retval_exp, int from_tty)
 	return_type = TYPE_TARGET_TYPE (SYMBOL_TYPE (thisfun));
       if (return_type == NULL)
       	{
-	  if (retval_expr->elts[0].opcode != UNOP_CAST)
+	  if (retval_expr->elts[0].opcode != UNOP_CAST
+	      && retval_expr->elts[0].opcode != UNOP_CAST_TYPE)
 	    error (_("Return value type not available for selected "
 		     "stack frame.\n"
 		     "Please use an explicit cast of the value to return."));
diff --git a/gdb/std-operator.def b/gdb/std-operator.def
index f2f650b..9c6a01b 100644
--- a/gdb/std-operator.def
+++ b/gdb/std-operator.def
@@ -216,6 +216,9 @@ OP (OP_ARRAY)
    It casts the value of the following subexpression.  */
 OP (UNOP_CAST)
 
+/* Like UNOP_CAST, but the type is a subexpression.  */
+OP (UNOP_CAST_TYPE)
+
 /* The C++ dynamic_cast operator.  */
 OP (UNOP_DYNAMIC_CAST)
 
@@ -235,6 +238,9 @@ OP (UNOP_MEMVAL)
    following subexpression from the TLS specified by `struct objfile'.  */
 OP (UNOP_MEMVAL_TLS)
 
+/* Like UNOP_MEMVAL, but the type is supplied as a subexpression.  */
+OP (UNOP_MEMVAL_TYPE)
+
 /* UNOP_... operate on one value from a following subexpression
    and replace it with a result.  They take no immediate arguments.  */
 
-- 
1.7.7.6



More information about the Gdb-patches mailing list