public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 000/203] Refactor expressions
@ 2021-01-01 21:44 Tom Tromey
  2021-01-01 21:44 ` [PATCH 001/203] Split out eval_op_scope Tom Tromey
                   ` (203 more replies)
  0 siblings, 204 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:44 UTC (permalink / raw)
  To: gdb-patches

I have long thought that struct expression is the worst data structure
in GDB.  In fact, I've sometimes told people it is the worst data
structure I've encountered in my career.  I've wanted to rewrite it
for many years, and this year I finally found a workable plan and the
motivation to do so.  This series is the result.

The new approach is what I consider to be the most obvious data
structure to use here: a base class represents a single node of an
expression tree, and concrete subclasses implement the various
operations.  Each object maintains its own storage.  In the end,
'struct expression' is just a simple wrapper around the root node of a
tree.  The weird things in the current code -- the strange way storage
is handled, and the need to "rotate" the expression after creation --
are gone.

The series is, of course, extremely long.  This is partly due to my
desire to split it up so that each patch is reasonably understandable,
but also partly because it is just unavoidable.

Conceptually it can be divided into multiple sub-series.  I didn't
submit these separately, though, as they don't really make sense
independently.  I've already submitted any patch that was truly
separate.  (These aren't all in yet, though, and this series depends
on them.)

Here are the sub-series:

1. Split functions out from the evaluators.

   Each evaluator function is fairly long, and mixes knowledge about
   the structure of the expression (how the exp_elements are laid out)
   with knowledge of the semantics of the operation.

   This part of the series, which is about 70 patches, splits out the
   semantics of most operations into their own functions.  These
   functions can be then be reused -- which is helpful for ensuring
   that changes don't sneak in.

   In this part of the series, sometimes the newly-introduced
   functions have extraneous arguments.  This was done partly so that
   some could be reused by generic code in part 2; but also partly
   because it was just simpler to write patches by rote.

2. Introduce 'class operation' and its subclasses.

   This sub-series is around 100 patches.  It introduces the new base
   class for an expression operation, and then proceeds to add
   operations for every necessary opcode.  In some cases multiple such
   operations are needed -- for example when multiple languages
   implement an opcode in different ways.

   Some discussion of the design & tradeoffs appear in the "Introduce
   class operation" patch.

3. Convert existing code to use operations.

   This is a short sub-series of around 10 patches.  Each parser is
   converted separately, as are DTrace and SystemTap probes

4. Delete obsolete code.

   The final 20 patches or so are concerned with removing all the code
   that is now obsolete, and with doing some minor tidying of the
   result.

The overall approach here is to replace the current data structure --
but only the data structure.  I didn't generally try to clean up
things that seemed a bit weird.

I also didn't try to add new features, like async evaluation.  After
starting the project, I felt that trying to combine this refactoring
with another, different one would be too difficult.

This is all on the branch t/expression-rewrite-incr in my github.

Regression tested on x86-64 Fedora 32.  I also built it on PPC Linux
to ensure that the ppc-linux-nat.c changes would build.

Tom



^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 001/203] Split out eval_op_scope
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
@ 2021-01-01 21:44 ` Tom Tromey
  2021-01-01 21:44 ` [PATCH 002/203] Split out eval_op_var_entry_value Tom Tromey
                   ` (202 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:44 UTC (permalink / raw)
  To: gdb-patches

This splits OP_SCOPE into a new function for future use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* eval.c (eval_op_scope): New function.
	(evaluate_subexp_standard): Use it.
---
 gdb/ChangeLog |  5 +++++
 gdb/eval.c    | 27 +++++++++++++++++++--------
 2 files changed, 24 insertions(+), 8 deletions(-)

diff --git a/gdb/eval.c b/gdb/eval.c
index e63511b7005..74123b0d13f 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1179,6 +1179,22 @@ is_integral_or_integral_reference (struct type *type)
 	  && is_integral_type (TYPE_TARGET_TYPE (type)));
 }
 
+/* Helper function that implements the body of OP_SCOPE.  */
+
+static struct value *
+eval_op_scope (struct type *expect_type, struct expression *exp,
+	       enum noside noside,
+	       struct type *type, const char *string)
+{
+  if (noside == EVAL_SKIP)
+    return eval_skip_value (exp);
+  struct value *arg1 = value_aggregate_elt (type, string, expect_type,
+					    0, noside);
+  if (arg1 == NULL)
+    error (_("There is no field named %s"), string);
+  return arg1;
+}
+
 struct value *
 evaluate_subexp_standard (struct type *expect_type,
 			  struct expression *exp, int *pos,
@@ -1205,14 +1221,9 @@ evaluate_subexp_standard (struct type *expect_type,
     case OP_SCOPE:
       tem = longest_to_int (exp->elts[pc + 2].longconst);
       (*pos) += 4 + BYTES_TO_EXP_ELEM (tem + 1);
-      if (noside == EVAL_SKIP)
-	return eval_skip_value (exp);
-      arg1 = value_aggregate_elt (exp->elts[pc + 1].type,
-				  &exp->elts[pc + 3].string,
-				  expect_type, 0, noside);
-      if (arg1 == NULL)
-	error (_("There is no field named %s"), &exp->elts[pc + 3].string);
-      return arg1;
+      return eval_op_scope (expect_type, exp, noside,
+			    exp->elts[pc + 1].type,
+			    &exp->elts[pc + 3].string);
 
     case OP_LONG:
       (*pos) += 3;
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 002/203] Split out eval_op_var_entry_value
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
  2021-01-01 21:44 ` [PATCH 001/203] Split out eval_op_scope Tom Tromey
@ 2021-01-01 21:44 ` Tom Tromey
  2021-01-01 21:44 ` [PATCH 003/203] Split out eval_op_var_msym_value Tom Tromey
                   ` (201 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:44 UTC (permalink / raw)
  To: gdb-patches

This splits OP_VAR_ENTRY_VALUE into a new function for future use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* eval.c (eval_op_var_entry_value): New function.
	(evaluate_subexp_standard): Use it.
---
 gdb/ChangeLog |  5 +++++
 gdb/eval.c    | 34 +++++++++++++++++++++-------------
 2 files changed, 26 insertions(+), 13 deletions(-)

diff --git a/gdb/eval.c b/gdb/eval.c
index 74123b0d13f..745333d31f9 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1195,6 +1195,26 @@ eval_op_scope (struct type *expect_type, struct expression *exp,
   return arg1;
 }
 
+/* Helper function that implements the body of OP_VAR_ENTRY_VALUE.  */
+
+static struct value *
+eval_op_var_entry_value (struct type *expect_type, struct expression *exp,
+			 enum noside noside, symbol *sym)
+{
+  if (noside == EVAL_SKIP)
+    return eval_skip_value (exp);
+  if (noside == EVAL_AVOID_SIDE_EFFECTS)
+    return value_zero (SYMBOL_TYPE (sym), not_lval);
+
+  if (SYMBOL_COMPUTED_OPS (sym) == NULL
+      || SYMBOL_COMPUTED_OPS (sym)->read_variable_at_entry == NULL)
+    error (_("Symbol \"%s\" does not have any specific entry value"),
+	   sym->print_name ());
+
+  struct frame_info *frame = get_selected_frame (NULL);
+  return SYMBOL_COMPUTED_OPS (sym)->read_variable_at_entry (sym, frame);
+}
+
 struct value *
 evaluate_subexp_standard (struct type *expect_type,
 			  struct expression *exp, int *pos,
@@ -1270,23 +1290,11 @@ evaluate_subexp_standard (struct type *expect_type,
 
     case OP_VAR_ENTRY_VALUE:
       (*pos) += 2;
-      if (noside == EVAL_SKIP)
-	return eval_skip_value (exp);
 
       {
 	struct symbol *sym = exp->elts[pc + 1].symbol;
-	struct frame_info *frame;
-
-	if (noside == EVAL_AVOID_SIDE_EFFECTS)
-	  return value_zero (SYMBOL_TYPE (sym), not_lval);
-
-	if (SYMBOL_COMPUTED_OPS (sym) == NULL
-	    || SYMBOL_COMPUTED_OPS (sym)->read_variable_at_entry == NULL)
-	  error (_("Symbol \"%s\" does not have any specific entry value"),
-		 sym->print_name ());
 
-	frame = get_selected_frame (NULL);
-	return SYMBOL_COMPUTED_OPS (sym)->read_variable_at_entry (sym, frame);
+	return eval_op_var_entry_value (expect_type, exp, noside, sym);
       }
 
     case OP_FUNC_STATIC_VAR:
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 003/203] Split out eval_op_var_msym_value
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
  2021-01-01 21:44 ` [PATCH 001/203] Split out eval_op_scope Tom Tromey
  2021-01-01 21:44 ` [PATCH 002/203] Split out eval_op_var_entry_value Tom Tromey
@ 2021-01-01 21:44 ` Tom Tromey
  2021-01-04 11:43   ` Andrew Burgess
  2021-01-01 21:44 ` [PATCH 004/203] Split out eval_op_func_static_var Tom Tromey
                   ` (200 subsequent siblings)
  203 siblings, 1 reply; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:44 UTC (permalink / raw)
  To: gdb-patches

This splits OP_VAR_MSYM_VALUE into a new function for future use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* eval.c (eval_op_var_msym_value): New function.
	(evaluate_subexp_standard): Use it.
---
 gdb/ChangeLog |  5 +++++
 gdb/eval.c    | 26 +++++++++++++++++---------
 2 files changed, 22 insertions(+), 9 deletions(-)

diff --git a/gdb/eval.c b/gdb/eval.c
index 745333d31f9..e896baa3dec 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1215,6 +1215,20 @@ eval_op_var_entry_value (struct type *expect_type, struct expression *exp,
   return SYMBOL_COMPUTED_OPS (sym)->read_variable_at_entry (sym, frame);
 }
 
+static struct value *
+eval_op_var_msym_value (struct type *expect_type, struct expression *exp,
+			enum noside noside,
+			minimal_symbol *msymbol, struct objfile *objfile)
+{
+  value *val = evaluate_var_msym_value (noside, objfile, msymbol);
+
+  struct type *type = value_type (val);
+  if (type->code () == TYPE_CODE_ERROR
+      && (noside != EVAL_AVOID_SIDE_EFFECTS || pc != 0))
+    error_unknown_type (msymbol->print_name ());
+  return val;
+}
+
 struct value *
 evaluate_subexp_standard (struct type *expect_type,
 			  struct expression *exp, int *pos,
@@ -1277,15 +1291,9 @@ evaluate_subexp_standard (struct type *expect_type,
 	(*pos) += 3;
 
 	minimal_symbol *msymbol = exp->elts[pc + 2].msymbol;
-	value *val = evaluate_var_msym_value (noside,
-					      exp->elts[pc + 1].objfile,
-					      msymbol);
-
-	type = value_type (val);
-	if (type->code () == TYPE_CODE_ERROR
-	    && (noside != EVAL_AVOID_SIDE_EFFECTS || pc != 0))
-	  error_unknown_type (msymbol->print_name ());
-	return val;
+	return eval_op_var_msym_value (expect_type, exp, noside,
+				       msymbol,
+				       exp->elts[pc + 1].objfile);
       }
 
     case OP_VAR_ENTRY_VALUE:
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 004/203] Split out eval_op_func_static_var
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (2 preceding siblings ...)
  2021-01-01 21:44 ` [PATCH 003/203] Split out eval_op_var_msym_value Tom Tromey
@ 2021-01-01 21:44 ` Tom Tromey
  2021-01-01 21:44 ` [PATCH 005/203] Split out eval_op_register Tom Tromey
                   ` (199 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:44 UTC (permalink / raw)
  To: gdb-patches

This splits OP_FUNC_STATIC_VAR into a new function for future use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* eval.c (eval_op_func_static_var): New function.
	(evaluate_subexp_standard): Use it.
---
 gdb/ChangeLog |  5 +++++
 gdb/eval.c    | 27 +++++++++++++++++----------
 2 files changed, 22 insertions(+), 10 deletions(-)

diff --git a/gdb/eval.c b/gdb/eval.c
index e896baa3dec..5312525e850 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1229,6 +1229,21 @@ eval_op_var_msym_value (struct type *expect_type, struct expression *exp,
   return val;
 }
 
+static struct value *
+eval_op_func_static_var (struct type *expect_type, struct expression *exp,
+			 enum noside noside,
+			 value *func, const char *var)
+{
+  if (noside == EVAL_SKIP)
+    return eval_skip_value (exp);
+  CORE_ADDR addr = value_address (func);
+  const block *blk = block_for_pc (addr);
+  struct block_symbol sym = lookup_symbol (var, blk, VAR_DOMAIN, NULL);
+  if (sym.symbol == NULL)
+    error (_("No symbol \"%s\" in specified context."), var);
+  return evaluate_var_value (noside, sym.block, sym.symbol);
+}
+
 struct value *
 evaluate_subexp_standard (struct type *expect_type,
 			  struct expression *exp, int *pos,
@@ -1313,17 +1328,9 @@ evaluate_subexp_standard (struct type *expect_type,
 
       {
 	value *func = evaluate_subexp_standard (NULL, exp, pos, noside);
-	CORE_ADDR addr = value_address (func);
-
-	const block *blk = block_for_pc (addr);
-	const char *var = &exp->elts[pc + 2].string;
-
-	struct block_symbol sym = lookup_symbol (var, blk, VAR_DOMAIN, NULL);
-
-	if (sym.symbol == NULL)
-	  error (_("No symbol \"%s\" in specified context."), var);
 
-	return evaluate_var_value (noside, sym.block, sym.symbol);
+	return eval_op_func_static_var (expect_type, exp, noside, func,
+					&exp->elts[pc + 2].string);
       }
 
     case OP_LAST:
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 005/203] Split out eval_op_register
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (3 preceding siblings ...)
  2021-01-01 21:44 ` [PATCH 004/203] Split out eval_op_func_static_var Tom Tromey
@ 2021-01-01 21:44 ` Tom Tromey
  2021-01-01 21:44 ` [PATCH 006/203] Split out eval_op_string Tom Tromey
                   ` (198 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:44 UTC (permalink / raw)
  To: gdb-patches

This splits OP_REGISTER into a new function for future use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* eval.c (eval_op_register): New function.
	(evaluate_subexp_standard): Use it.
---
 gdb/ChangeLog |  5 +++++
 gdb/eval.c    | 50 +++++++++++++++++++++++++++++---------------------
 2 files changed, 34 insertions(+), 21 deletions(-)

diff --git a/gdb/eval.c b/gdb/eval.c
index 5312525e850..cff323bba46 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1244,6 +1244,34 @@ eval_op_func_static_var (struct type *expect_type, struct expression *exp,
   return evaluate_var_value (noside, sym.block, sym.symbol);
 }
 
+static struct value *
+eval_op_register (struct type *expect_type, struct expression *exp,
+		  enum noside noside, const char *name)
+{
+  int regno;
+  struct value *val;
+
+  regno = user_reg_map_name_to_regnum (exp->gdbarch,
+				       name, strlen (name));
+  if (regno == -1)
+    error (_("Register $%s not available."), name);
+
+  /* In EVAL_AVOID_SIDE_EFFECTS mode, we only need to return
+     a value with the appropriate register type.  Unfortunately,
+     we don't have easy access to the type of user registers.
+     So for these registers, we fetch the register value regardless
+     of the evaluation mode.  */
+  if (noside == EVAL_AVOID_SIDE_EFFECTS
+      && regno < gdbarch_num_cooked_regs (exp->gdbarch))
+    val = value_zero (register_type (exp->gdbarch, regno), not_lval);
+  else
+    val = value_of_register (regno, get_selected_frame (NULL));
+  if (val == NULL)
+    error (_("Value of register %s not available."), name);
+  else
+    return val;
+}
+
 struct value *
 evaluate_subexp_standard (struct type *expect_type,
 			  struct expression *exp, int *pos,
@@ -1341,29 +1369,9 @@ evaluate_subexp_standard (struct type *expect_type,
     case OP_REGISTER:
       {
 	const char *name = &exp->elts[pc + 2].string;
-	int regno;
-	struct value *val;
 
 	(*pos) += 3 + BYTES_TO_EXP_ELEM (exp->elts[pc + 1].longconst + 1);
-	regno = user_reg_map_name_to_regnum (exp->gdbarch,
-					     name, strlen (name));
-	if (regno == -1)
-	  error (_("Register $%s not available."), name);
-
-	/* In EVAL_AVOID_SIDE_EFFECTS mode, we only need to return
-	   a value with the appropriate register type.  Unfortunately,
-	   we don't have easy access to the type of user registers.
-	   So for these registers, we fetch the register value regardless
-	   of the evaluation mode.  */
-	if (noside == EVAL_AVOID_SIDE_EFFECTS
-	    && regno < gdbarch_num_cooked_regs (exp->gdbarch))
-	  val = value_zero (register_type (exp->gdbarch, regno), not_lval);
-	else
-	  val = value_of_register (regno, get_selected_frame (NULL));
-	if (val == NULL)
-	  error (_("Value of register %s not available."), name);
-	else
-	  return val;
+	return eval_op_register (expect_type, exp, noside, name);
       }
     case OP_BOOL:
       (*pos) += 2;
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 006/203] Split out eval_op_string
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (4 preceding siblings ...)
  2021-01-01 21:44 ` [PATCH 005/203] Split out eval_op_register Tom Tromey
@ 2021-01-01 21:44 ` Tom Tromey
  2021-01-01 21:44 ` [PATCH 007/203] Split out eval_op_objc_selector Tom Tromey
                   ` (197 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:44 UTC (permalink / raw)
  To: gdb-patches

This splits OP_STRING into a new function for future use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* eval.c (eval_op_string): New function.
	(evaluate_subexp_standard): Use it.
---
 gdb/ChangeLog |  5 +++++
 gdb/eval.c    | 17 +++++++++++++----
 2 files changed, 18 insertions(+), 4 deletions(-)

diff --git a/gdb/eval.c b/gdb/eval.c
index cff323bba46..3bdc2094d49 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1272,6 +1272,17 @@ eval_op_register (struct type *expect_type, struct expression *exp,
     return val;
 }
 
+static struct value *
+eval_op_string (struct type *expect_type, struct expression *exp,
+		enum noside noside, int len, const char *string)
+{
+  if (noside == EVAL_SKIP)
+    return eval_skip_value (exp);
+  struct type *type = language_string_char_type (exp->language_defn,
+						 exp->gdbarch);
+  return value_string (string, len, type);
+}
+
 struct value *
 evaluate_subexp_standard (struct type *expect_type,
 			  struct expression *exp, int *pos,
@@ -1386,10 +1397,8 @@ evaluate_subexp_standard (struct type *expect_type,
     case OP_STRING:
       tem = longest_to_int (exp->elts[pc + 1].longconst);
       (*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1);
-      if (noside == EVAL_SKIP)
-	return eval_skip_value (exp);
-      type = language_string_char_type (exp->language_defn, exp->gdbarch);
-      return value_string (&exp->elts[pc + 2].string, tem, type);
+      return eval_op_string (expect_type, exp, noside, tem,
+			     &exp->elts[pc + 2].string);
 
     case OP_OBJC_NSSTRING:		/* Objective C Foundation Class
 					   NSString constant.  */
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 007/203] Split out eval_op_objc_selector
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (5 preceding siblings ...)
  2021-01-01 21:44 ` [PATCH 006/203] Split out eval_op_string Tom Tromey
@ 2021-01-01 21:44 ` Tom Tromey
  2021-01-01 21:44 ` [PATCH 008/203] Split out eval_op_concat Tom Tromey
                   ` (196 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:44 UTC (permalink / raw)
  To: gdb-patches

This splits OP_OBJC_SELECTOR into a new function for future use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* eval.c (eval_op_objc_selector): New function.
	(evaluate_subexp_standard): Use it.
---
 gdb/ChangeLog |  5 +++++
 gdb/eval.c    | 21 ++++++++++++++-------
 2 files changed, 19 insertions(+), 7 deletions(-)

diff --git a/gdb/eval.c b/gdb/eval.c
index 3bdc2094d49..ebab2c8fdbb 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1283,6 +1283,19 @@ eval_op_string (struct type *expect_type, struct expression *exp,
   return value_string (string, len, type);
 }
 
+static struct value *
+eval_op_objc_selector (struct type *expect_type, struct expression *exp,
+		       enum noside noside,
+		       const char *sel)
+{
+  if (noside == EVAL_SKIP)
+    return eval_skip_value (exp);
+
+  struct type *selector_type = builtin_type (exp->gdbarch)->builtin_data_ptr;
+  return value_from_longest (selector_type,
+			     lookup_child_selector (exp->gdbarch, sel));
+}
+
 struct value *
 evaluate_subexp_standard (struct type *expect_type,
 			  struct expression *exp, int *pos,
@@ -1566,18 +1579,12 @@ evaluate_subexp_standard (struct type *expect_type,
       {				/* Objective C @selector operator.  */
 	char *sel = &exp->elts[pc + 2].string;
 	int len = longest_to_int (exp->elts[pc + 1].longconst);
-	struct type *selector_type;
 
 	(*pos) += 3 + BYTES_TO_EXP_ELEM (len + 1);
-	if (noside == EVAL_SKIP)
-	  return eval_skip_value (exp);
-
 	if (sel[len] != 0)
 	  sel[len] = 0;		/* Make sure it's terminated.  */
 
-	selector_type = builtin_type (exp->gdbarch)->builtin_data_ptr;
-	return value_from_longest (selector_type,
-				   lookup_child_selector (exp->gdbarch, sel));
+	return eval_op_objc_selector (expect_type, exp, noside, sel);
       }
 
     case OP_OBJC_MSGCALL:
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 008/203] Split out eval_op_concat
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (6 preceding siblings ...)
  2021-01-01 21:44 ` [PATCH 007/203] Split out eval_op_objc_selector Tom Tromey
@ 2021-01-01 21:44 ` Tom Tromey
  2021-01-01 21:44 ` [PATCH 009/203] what is this code for Tom Tromey
                   ` (195 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:44 UTC (permalink / raw)
  To: gdb-patches

This splits BINOP_CONCAT into a new function for future use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* eval.c (eval_op_concat): New function.
	(evaluate_subexp_standard): Use it.
---
 gdb/ChangeLog |  5 +++++
 gdb/eval.c    | 20 ++++++++++++++------
 2 files changed, 19 insertions(+), 6 deletions(-)

diff --git a/gdb/eval.c b/gdb/eval.c
index ebab2c8fdbb..b00139ca36f 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1296,6 +1296,19 @@ eval_op_objc_selector (struct type *expect_type, struct expression *exp,
 			     lookup_child_selector (exp->gdbarch, sel));
 }
 
+static struct value *
+eval_op_concat (struct type *expect_type, struct expression *exp,
+		enum noside noside,
+		enum exp_opcode op, struct value *arg1, struct value *arg2)
+{
+  if (noside == EVAL_SKIP)
+    return eval_skip_value (exp);
+  if (binop_user_defined_p (op, arg1, arg2))
+    return value_x_binop (arg1, arg2, op, OP_NULL, noside);
+  else
+    return value_concat (arg1, arg2);
+}
+
 struct value *
 evaluate_subexp_standard (struct type *expect_type,
 			  struct expression *exp, int *pos,
@@ -2013,12 +2026,7 @@ evaluate_subexp_standard (struct type *expect_type,
     case BINOP_CONCAT:
       arg1 = evaluate_subexp_with_coercion (exp, pos, noside);
       arg2 = evaluate_subexp_with_coercion (exp, pos, noside);
-      if (noside == EVAL_SKIP)
-	return eval_skip_value (exp);
-      if (binop_user_defined_p (op, arg1, arg2))
-	return value_x_binop (arg1, arg2, op, OP_NULL, noside);
-      else
-	return value_concat (arg1, arg2);
+      return eval_op_concat (expect_type, exp, noside, op, arg1, arg2);
 
     case BINOP_ASSIGN:
       arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 009/203] what is this code for
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (7 preceding siblings ...)
  2021-01-01 21:44 ` [PATCH 008/203] Split out eval_op_concat Tom Tromey
@ 2021-01-01 21:44 ` Tom Tromey
  2021-01-03  6:00   ` Joel Brobecker
  2021-01-01 21:44 ` [PATCH 010/203] Split out eval_op_ternop Tom Tromey
                   ` (194 subsequent siblings)
  203 siblings, 1 reply; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:44 UTC (permalink / raw)
  To: gdb-patches

---
 gdb/eval.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gdb/eval.c b/gdb/eval.c
index b00139ca36f..f2507f25f44 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1224,7 +1224,7 @@ eval_op_var_msym_value (struct type *expect_type, struct expression *exp,
 
   struct type *type = value_type (val);
   if (type->code () == TYPE_CODE_ERROR
-      && (noside != EVAL_AVOID_SIDE_EFFECTS || pc != 0))
+      && (noside != EVAL_AVOID_SIDE_EFFECTS))
     error_unknown_type (msymbol->print_name ());
   return val;
 }
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 010/203] Split out eval_op_ternop
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (8 preceding siblings ...)
  2021-01-01 21:44 ` [PATCH 009/203] what is this code for Tom Tromey
@ 2021-01-01 21:44 ` Tom Tromey
  2021-01-01 21:44 ` [PATCH 011/203] Split out eval_op_structop_struct Tom Tromey
                   ` (193 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:44 UTC (permalink / raw)
  To: gdb-patches

This splits TERNOP_SLICE into a new function for future use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* eval.c (eval_op_ternop): New function.
	(evaluate_subexp_standard): Use it.
---
 gdb/ChangeLog |  5 +++++
 gdb/eval.c    | 24 +++++++++++++++++-------
 2 files changed, 22 insertions(+), 7 deletions(-)

diff --git a/gdb/eval.c b/gdb/eval.c
index f2507f25f44..f4af89bf928 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1309,6 +1309,20 @@ eval_op_concat (struct type *expect_type, struct expression *exp,
     return value_concat (arg1, arg2);
 }
 
+/* A helper function for TERNOP_SLICE.  */
+
+static struct value *
+eval_op_ternop (struct type *expect_type, struct expression *exp,
+		enum noside noside,
+		struct value *array, struct value *low, struct value *upper)
+{
+  if (noside == EVAL_SKIP)
+    return eval_skip_value (exp);
+  int lowbound = value_as_long (low);
+  int upperbound = value_as_long (upper);
+  return value_slice (array, lowbound, upperbound - lowbound + 1);
+}
+
 struct value *
 evaluate_subexp_standard (struct type *expect_type,
 			  struct expression *exp, int *pos,
@@ -1564,13 +1578,9 @@ evaluate_subexp_standard (struct type *expect_type,
     case TERNOP_SLICE:
       {
 	struct value *array = evaluate_subexp (nullptr, exp, pos, noside);
-	int lowbound
-	  = value_as_long (evaluate_subexp (nullptr, exp, pos, noside));
-	int upper = value_as_long (evaluate_subexp (nullptr, exp, pos, noside));
-
-	if (noside == EVAL_SKIP)
-	  return eval_skip_value (exp);
-	return value_slice (array, lowbound, upper - lowbound + 1);
+	struct value *low = evaluate_subexp (nullptr, exp, pos, noside);
+	struct value *upper = evaluate_subexp (nullptr, exp, pos, noside);
+	return eval_op_ternop (expect_type, exp, noside, array, low, upper);
       }
 
     case TERNOP_COND:
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 011/203] Split out eval_op_structop_struct
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (9 preceding siblings ...)
  2021-01-01 21:44 ` [PATCH 010/203] Split out eval_op_ternop Tom Tromey
@ 2021-01-01 21:44 ` Tom Tromey
  2021-01-01 21:44 ` [PATCH 012/203] Split out eval_op_structop_ptr Tom Tromey
                   ` (192 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:44 UTC (permalink / raw)
  To: gdb-patches

This splits STRUCTOP_STRUCT into a new function for future use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* eval.c (eval_op_structop_struct): New function.
	(evaluate_subexp_standard): Use it.
---
 gdb/ChangeLog |  5 +++++
 gdb/eval.c    | 25 ++++++++++++++++++-------
 2 files changed, 23 insertions(+), 7 deletions(-)

diff --git a/gdb/eval.c b/gdb/eval.c
index f4af89bf928..b815f16ee1c 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1323,6 +1323,22 @@ eval_op_ternop (struct type *expect_type, struct expression *exp,
   return value_slice (array, lowbound, upperbound - lowbound + 1);
 }
 
+/* A helper function for STRUCTOP_STRUCT.  */
+
+static struct value *
+eval_op_structop_struct (struct type *expect_type, struct expression *exp,
+			 enum noside noside,
+			 struct value *arg1, const char *string)
+{
+  if (noside == EVAL_SKIP)
+    return eval_skip_value (exp);
+  struct value *arg3 = value_struct_elt (&arg1, NULL, string,
+					 NULL, "structure");
+  if (noside == EVAL_AVOID_SIDE_EFFECTS)
+    arg3 = value_zero (value_type (arg3), VALUE_LVAL (arg3));
+  return arg3;
+}
+
 struct value *
 evaluate_subexp_standard (struct type *expect_type,
 			  struct expression *exp, int *pos,
@@ -1914,13 +1930,8 @@ evaluate_subexp_standard (struct type *expect_type,
       tem = longest_to_int (exp->elts[pc + 1].longconst);
       (*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1);
       arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      if (noside == EVAL_SKIP)
-	return eval_skip_value (exp);
-      arg3 = value_struct_elt (&arg1, NULL, &exp->elts[pc + 2].string,
-			       NULL, "structure");
-      if (noside == EVAL_AVOID_SIDE_EFFECTS)
-	arg3 = value_zero (value_type (arg3), VALUE_LVAL (arg3));
-      return arg3;
+      return eval_op_structop_struct (expect_type, exp, noside, arg1,
+				      &exp->elts[pc + 2].string);
 
     case STRUCTOP_PTR:
       tem = longest_to_int (exp->elts[pc + 1].longconst);
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 012/203] Split out eval_op_structop_ptr
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (10 preceding siblings ...)
  2021-01-01 21:44 ` [PATCH 011/203] Split out eval_op_structop_struct Tom Tromey
@ 2021-01-01 21:44 ` Tom Tromey
  2021-01-01 21:44 ` [PATCH 013/203] Split out eval_op_member Tom Tromey
                   ` (191 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:44 UTC (permalink / raw)
  To: gdb-patches

This splits STRUCTOP_PTR into a new function for future use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* eval.c (eval_op_structop_ptr): New function.
	(evaluate_subexp_standard): Use it.
---
 gdb/ChangeLog |   5 +++
 gdb/eval.c    | 111 +++++++++++++++++++++++++++-----------------------
 2 files changed, 66 insertions(+), 50 deletions(-)

diff --git a/gdb/eval.c b/gdb/eval.c
index b815f16ee1c..8164f2f4e3a 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1339,6 +1339,65 @@ eval_op_structop_struct (struct type *expect_type, struct expression *exp,
   return arg3;
 }
 
+/* A helper function for STRUCTOP_PTR.  */
+
+static struct value *
+eval_op_structop_ptr (struct type *expect_type, struct expression *exp,
+		      enum noside noside, enum exp_opcode op,
+		      struct value *arg1, const char *string)
+{
+  if (noside == EVAL_SKIP)
+    return eval_skip_value (exp);
+
+  /* Check to see if operator '->' has been overloaded.  If so replace
+     arg1 with the value returned by evaluating operator->().  */
+  while (unop_user_defined_p (op, arg1))
+    {
+      struct value *value = NULL;
+      try
+	{
+	  value = value_x_unop (arg1, op, noside);
+	}
+
+      catch (const gdb_exception_error &except)
+	{
+	  if (except.error == NOT_FOUND_ERROR)
+	    break;
+	  else
+	    throw;
+	}
+
+      arg1 = value;
+    }
+
+  /* JYG: if print object is on we need to replace the base type
+     with rtti type in order to continue on with successful
+     lookup of member / method only available in the rtti type.  */
+  {
+    struct type *arg_type = value_type (arg1);
+    struct type *real_type;
+    int full, using_enc;
+    LONGEST top;
+    struct value_print_options opts;
+
+    get_user_print_options (&opts);
+    if (opts.objectprint && TYPE_TARGET_TYPE (arg_type)
+	&& (TYPE_TARGET_TYPE (arg_type)->code () == TYPE_CODE_STRUCT))
+      {
+	real_type = value_rtti_indirect_type (arg1, &full, &top,
+					      &using_enc);
+	if (real_type)
+	  arg1 = value_cast (real_type, arg1);
+      }
+  }
+
+  struct value *arg3 = value_struct_elt (&arg1, NULL, string,
+					 NULL, "structure pointer");
+  if (noside == EVAL_AVOID_SIDE_EFFECTS)
+    arg3 = value_zero (value_type (arg3), VALUE_LVAL (arg3));
+  return arg3;
+}
+
 struct value *
 evaluate_subexp_standard (struct type *expect_type,
 			  struct expression *exp, int *pos,
@@ -1937,56 +1996,8 @@ evaluate_subexp_standard (struct type *expect_type,
       tem = longest_to_int (exp->elts[pc + 1].longconst);
       (*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1);
       arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      if (noside == EVAL_SKIP)
-	return eval_skip_value (exp);
-
-      /* Check to see if operator '->' has been overloaded.  If so replace
-	 arg1 with the value returned by evaluating operator->().  */
-      while (unop_user_defined_p (op, arg1))
-	{
-	  struct value *value = NULL;
-	  try
-	    {
-	      value = value_x_unop (arg1, op, noside);
-	    }
-
-	  catch (const gdb_exception_error &except)
-	    {
-	      if (except.error == NOT_FOUND_ERROR)
-		break;
-	      else
-		throw;
-	    }
-
-	  arg1 = value;
-	}
-
-      /* JYG: if print object is on we need to replace the base type
-	 with rtti type in order to continue on with successful
-	 lookup of member / method only available in the rtti type.  */
-      {
-	struct type *arg_type = value_type (arg1);
-	struct type *real_type;
-	int full, using_enc;
-	LONGEST top;
-	struct value_print_options opts;
-
-	get_user_print_options (&opts);
-	if (opts.objectprint && TYPE_TARGET_TYPE (arg_type)
-	    && (TYPE_TARGET_TYPE (arg_type)->code () == TYPE_CODE_STRUCT))
-	  {
-	    real_type = value_rtti_indirect_type (arg1, &full, &top,
-						  &using_enc);
-	    if (real_type)
-		arg1 = value_cast (real_type, arg1);
-	  }
-      }
-
-      arg3 = value_struct_elt (&arg1, NULL, &exp->elts[pc + 2].string,
-			       NULL, "structure pointer");
-      if (noside == EVAL_AVOID_SIDE_EFFECTS)
-	arg3 = value_zero (value_type (arg3), VALUE_LVAL (arg3));
-      return arg3;
+      return eval_op_structop_ptr (expect_type, exp, noside, op, arg1,
+				   &exp->elts[pc + 2].string);
 
     case STRUCTOP_MEMBER:
     case STRUCTOP_MPTR:
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 013/203] Split out eval_op_member
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (11 preceding siblings ...)
  2021-01-01 21:44 ` [PATCH 012/203] Split out eval_op_structop_ptr Tom Tromey
@ 2021-01-01 21:44 ` Tom Tromey
  2021-01-01 21:44 ` [PATCH 014/203] Split out eval_op_add Tom Tromey
                   ` (190 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:44 UTC (permalink / raw)
  To: gdb-patches

This splits STRUCTOP_MEMBER into a new function for future use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* eval.c (eval_op_member): New function.
	(evaluate_subexp_standard): Use it.
---
 gdb/ChangeLog |  5 ++++
 gdb/eval.c    | 76 +++++++++++++++++++++++++++++----------------------
 2 files changed, 49 insertions(+), 32 deletions(-)

diff --git a/gdb/eval.c b/gdb/eval.c
index 8164f2f4e3a..cc05b331b19 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1398,6 +1398,49 @@ eval_op_structop_ptr (struct type *expect_type, struct expression *exp,
   return arg3;
 }
 
+/* A helper function for STRUCTOP_MEMBER.  */
+
+static struct value *
+eval_op_member (struct type *expect_type, struct expression *exp,
+		enum noside noside,
+		struct value *arg1, struct value *arg2)
+{
+  long mem_offset;
+
+  if (noside == EVAL_SKIP)
+    return eval_skip_value (exp);
+
+  struct value *arg3;
+  struct type *type = check_typedef (value_type (arg2));
+  switch (type->code ())
+    {
+    case TYPE_CODE_METHODPTR:
+      if (noside == EVAL_AVOID_SIDE_EFFECTS)
+	return value_zero (TYPE_TARGET_TYPE (type), not_lval);
+      else
+	{
+	  arg2 = cplus_method_ptr_to_value (&arg1, arg2);
+	  gdb_assert (value_type (arg2)->code () == TYPE_CODE_PTR);
+	  return value_ind (arg2);
+	}
+
+    case TYPE_CODE_MEMBERPTR:
+      /* Now, convert these values to an address.  */
+      arg1 = value_cast_pointers (lookup_pointer_type (TYPE_SELF_TYPE (type)),
+				  arg1, 1);
+
+      mem_offset = value_as_long (arg2);
+
+      arg3 = value_from_pointer (lookup_pointer_type (TYPE_TARGET_TYPE (type)),
+				 value_as_long (arg1) + mem_offset);
+      return value_ind (arg3);
+
+    default:
+      error (_("non-pointer-to-member value used "
+	       "in pointer-to-member construct"));
+    }
+}
+
 struct value *
 evaluate_subexp_standard (struct type *expect_type,
 			  struct expression *exp, int *pos,
@@ -1413,7 +1456,6 @@ evaluate_subexp_standard (struct type *expect_type,
   int nargs;
   struct value **argvec;
   int ix;
-  long mem_offset;
   struct type **arg_types;
 
   pc = (*pos)++;
@@ -2008,37 +2050,7 @@ evaluate_subexp_standard (struct type *expect_type,
 
       arg2 = evaluate_subexp (nullptr, exp, pos, noside);
 
-      if (noside == EVAL_SKIP)
-	return eval_skip_value (exp);
-
-      type = check_typedef (value_type (arg2));
-      switch (type->code ())
-	{
-	case TYPE_CODE_METHODPTR:
-	  if (noside == EVAL_AVOID_SIDE_EFFECTS)
-	    return value_zero (TYPE_TARGET_TYPE (type), not_lval);
-	  else
-	    {
-	      arg2 = cplus_method_ptr_to_value (&arg1, arg2);
-	      gdb_assert (value_type (arg2)->code () == TYPE_CODE_PTR);
-	      return value_ind (arg2);
-	    }
-
-	case TYPE_CODE_MEMBERPTR:
-	  /* Now, convert these values to an address.  */
-	  arg1 = value_cast_pointers (lookup_pointer_type (TYPE_SELF_TYPE (type)),
-				      arg1, 1);
-
-	  mem_offset = value_as_long (arg2);
-
-	  arg3 = value_from_pointer (lookup_pointer_type (TYPE_TARGET_TYPE (type)),
-				     value_as_long (arg1) + mem_offset);
-	  return value_ind (arg3);
-
-	default:
-	  error (_("non-pointer-to-member value used "
-		   "in pointer-to-member construct"));
-	}
+      return eval_op_member (expect_type, exp, noside, arg1, arg2);
 
     case TYPE_INSTANCE:
       {
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 014/203] Split out eval_op_add
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (12 preceding siblings ...)
  2021-01-01 21:44 ` [PATCH 013/203] Split out eval_op_member Tom Tromey
@ 2021-01-01 21:44 ` Tom Tromey
  2021-01-01 21:44 ` [PATCH 015/203] Split out eval_op_sub Tom Tromey
                   ` (189 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:44 UTC (permalink / raw)
  To: gdb-patches

This splits BINOP_ADD into a new function for future use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* eval.c (eval_op_add): New function.
	(evaluate_subexp_standard): Use it.
---
 gdb/ChangeLog |  5 +++++
 gdb/eval.c    | 40 +++++++++++++++++++++++++---------------
 2 files changed, 30 insertions(+), 15 deletions(-)

diff --git a/gdb/eval.c b/gdb/eval.c
index cc05b331b19..f6d92dd9824 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1441,6 +1441,30 @@ eval_op_member (struct type *expect_type, struct expression *exp,
     }
 }
 
+/* A helper function for BINOP_ADD.  */
+
+static struct value *
+eval_op_add (struct type *expect_type, struct expression *exp,
+	     enum noside noside, enum exp_opcode op,
+	     struct value *arg1, struct value *arg2)
+{
+  if (noside == EVAL_SKIP)
+    return eval_skip_value (exp);
+  if (binop_user_defined_p (op, arg1, arg2))
+    return value_x_binop (arg1, arg2, op, OP_NULL, noside);
+  else if (ptrmath_type_p (exp->language_defn, value_type (arg1))
+	   && is_integral_or_integral_reference (value_type (arg2)))
+    return value_ptradd (arg1, value_as_long (arg2));
+  else if (ptrmath_type_p (exp->language_defn, value_type (arg2))
+	   && is_integral_or_integral_reference (value_type (arg1)))
+    return value_ptradd (arg2, value_as_long (arg1));
+  else
+    {
+      binop_promote (exp->language_defn, exp->gdbarch, &arg1, &arg2);
+      return value_binop (arg1, arg2, BINOP_ADD);
+    }
+}
+
 struct value *
 evaluate_subexp_standard (struct type *expect_type,
 			  struct expression *exp, int *pos,
@@ -2127,21 +2151,7 @@ evaluate_subexp_standard (struct type *expect_type,
     case BINOP_ADD:
       arg1 = evaluate_subexp_with_coercion (exp, pos, noside);
       arg2 = evaluate_subexp_with_coercion (exp, pos, noside);
-      if (noside == EVAL_SKIP)
-	return eval_skip_value (exp);
-      if (binop_user_defined_p (op, arg1, arg2))
-	return value_x_binop (arg1, arg2, op, OP_NULL, noside);
-      else if (ptrmath_type_p (exp->language_defn, value_type (arg1))
-	       && is_integral_or_integral_reference (value_type (arg2)))
-	return value_ptradd (arg1, value_as_long (arg2));
-      else if (ptrmath_type_p (exp->language_defn, value_type (arg2))
-	       && is_integral_or_integral_reference (value_type (arg1)))
-	return value_ptradd (arg2, value_as_long (arg1));
-      else
-	{
-	  binop_promote (exp->language_defn, exp->gdbarch, &arg1, &arg2);
-	  return value_binop (arg1, arg2, BINOP_ADD);
-	}
+      return eval_op_add (expect_type, exp, noside, op, arg1, arg2);
 
     case BINOP_SUB:
       arg1 = evaluate_subexp_with_coercion (exp, pos, noside);
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 015/203] Split out eval_op_sub
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (13 preceding siblings ...)
  2021-01-01 21:44 ` [PATCH 014/203] Split out eval_op_add Tom Tromey
@ 2021-01-01 21:44 ` Tom Tromey
  2021-01-01 21:44 ` [PATCH 016/203] Split out eval_op_binary Tom Tromey
                   ` (188 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:44 UTC (permalink / raw)
  To: gdb-patches

This splits BINOP_SUB into a new function for future use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* eval.c (eval_op_sub): New function.
	(evaluate_subexp_standard): Use it.
---
 gdb/ChangeLog |  5 +++++
 gdb/eval.c    | 48 +++++++++++++++++++++++++++++-------------------
 2 files changed, 34 insertions(+), 19 deletions(-)

diff --git a/gdb/eval.c b/gdb/eval.c
index f6d92dd9824..a94f61b0cec 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1465,6 +1465,34 @@ eval_op_add (struct type *expect_type, struct expression *exp,
     }
 }
 
+/* A helper function for BINOP_SUB.  */
+
+static struct value *
+eval_op_sub (struct type *expect_type, struct expression *exp,
+	     enum noside noside, enum exp_opcode op,
+	     struct value *arg1, struct value *arg2)
+{
+  if (noside == EVAL_SKIP)
+    return eval_skip_value (exp);
+  if (binop_user_defined_p (op, arg1, arg2))
+    return value_x_binop (arg1, arg2, op, OP_NULL, noside);
+  else if (ptrmath_type_p (exp->language_defn, value_type (arg1))
+	   && ptrmath_type_p (exp->language_defn, value_type (arg2)))
+    {
+      /* FIXME -- should be ptrdiff_t */
+      struct type *type = builtin_type (exp->gdbarch)->builtin_long;
+      return value_from_longest (type, value_ptrdiff (arg1, arg2));
+    }
+  else if (ptrmath_type_p (exp->language_defn, value_type (arg1))
+	   && is_integral_or_integral_reference (value_type (arg2)))
+    return value_ptradd (arg1, - value_as_long (arg2));
+  else
+    {
+      binop_promote (exp->language_defn, exp->gdbarch, &arg1, &arg2);
+      return value_binop (arg1, arg2, BINOP_SUB);
+    }
+}
+
 struct value *
 evaluate_subexp_standard (struct type *expect_type,
 			  struct expression *exp, int *pos,
@@ -2156,25 +2184,7 @@ evaluate_subexp_standard (struct type *expect_type,
     case BINOP_SUB:
       arg1 = evaluate_subexp_with_coercion (exp, pos, noside);
       arg2 = evaluate_subexp_with_coercion (exp, pos, noside);
-      if (noside == EVAL_SKIP)
-	return eval_skip_value (exp);
-      if (binop_user_defined_p (op, arg1, arg2))
-	return value_x_binop (arg1, arg2, op, OP_NULL, noside);
-      else if (ptrmath_type_p (exp->language_defn, value_type (arg1))
-	       && ptrmath_type_p (exp->language_defn, value_type (arg2)))
-	{
-	  /* FIXME -- should be ptrdiff_t */
-	  type = builtin_type (exp->gdbarch)->builtin_long;
-	  return value_from_longest (type, value_ptrdiff (arg1, arg2));
-	}
-      else if (ptrmath_type_p (exp->language_defn, value_type (arg1))
-	       && is_integral_or_integral_reference (value_type (arg2)))
-	return value_ptradd (arg1, - value_as_long (arg2));
-      else
-	{
-	  binop_promote (exp->language_defn, exp->gdbarch, &arg1, &arg2);
-	  return value_binop (arg1, arg2, BINOP_SUB);
-	}
+      return eval_op_sub (expect_type, exp, noside, op, arg1, arg2);
 
     case BINOP_EXP:
     case BINOP_MUL:
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 016/203] Split out eval_op_binary
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (14 preceding siblings ...)
  2021-01-01 21:44 ` [PATCH 015/203] Split out eval_op_sub Tom Tromey
@ 2021-01-01 21:44 ` Tom Tromey
  2021-01-01 21:44 ` [PATCH 017/203] Split out eval_op_subscript Tom Tromey
                   ` (187 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:44 UTC (permalink / raw)
  To: gdb-patches

This splits out a new eval_op_binary helper function.  This function
can handle several different binary operations:

    case BINOP_EXP:
    case BINOP_MUL:
    case BINOP_DIV:
    case BINOP_INTDIV:
    case BINOP_REM:
    case BINOP_MOD:
    case BINOP_LSH:
    case BINOP_RSH:
    case BINOP_BITWISE_AND:
    case BINOP_BITWISE_IOR:
    case BINOP_BITWISE_XOR:

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* eval.c (eval_op_binary): New function.
	(evaluate_subexp_standard): Use it.
---
 gdb/ChangeLog |  5 +++
 gdb/eval.c    | 86 ++++++++++++++++++++++++++++-----------------------
 2 files changed, 53 insertions(+), 38 deletions(-)

diff --git a/gdb/eval.c b/gdb/eval.c
index a94f61b0cec..5f9d5413498 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1493,6 +1493,53 @@ eval_op_sub (struct type *expect_type, struct expression *exp,
     }
 }
 
+/* Helper function for several different binary operations.  */
+
+static struct value *
+eval_op_binary (struct type *expect_type, struct expression *exp,
+		enum noside noside, enum exp_opcode op,
+		struct value *arg1, struct value *arg2)
+{
+  if (noside == EVAL_SKIP)
+    return eval_skip_value (exp);
+  if (binop_user_defined_p (op, arg1, arg2))
+    return value_x_binop (arg1, arg2, op, OP_NULL, noside);
+  else
+    {
+      /* If EVAL_AVOID_SIDE_EFFECTS and we're dividing by zero,
+	 fudge arg2 to avoid division-by-zero, the caller is
+	 (theoretically) only looking for the type of the result.  */
+      if (noside == EVAL_AVOID_SIDE_EFFECTS
+	  /* ??? Do we really want to test for BINOP_MOD here?
+	     The implementation of value_binop gives it a well-defined
+	     value.  */
+	  && (op == BINOP_DIV
+	      || op == BINOP_INTDIV
+	      || op == BINOP_REM
+	      || op == BINOP_MOD)
+	  && value_logical_not (arg2))
+	{
+	  struct value *v_one;
+
+	  v_one = value_one (value_type (arg2));
+	  binop_promote (exp->language_defn, exp->gdbarch, &arg1, &v_one);
+	  return value_binop (arg1, v_one, op);
+	}
+      else
+	{
+	  /* For shift and integer exponentiation operations,
+	     only promote the first argument.  */
+	  if ((op == BINOP_LSH || op == BINOP_RSH || op == BINOP_EXP)
+	      && is_integral_type (value_type (arg2)))
+	    unop_promote (exp->language_defn, exp->gdbarch, &arg1);
+	  else
+	    binop_promote (exp->language_defn, exp->gdbarch, &arg1, &arg2);
+
+	  return value_binop (arg1, arg2, op);
+	}
+    }
+}
+
 struct value *
 evaluate_subexp_standard (struct type *expect_type,
 			  struct expression *exp, int *pos,
@@ -2199,44 +2246,7 @@ evaluate_subexp_standard (struct type *expect_type,
     case BINOP_BITWISE_XOR:
       arg1 = evaluate_subexp (nullptr, exp, pos, noside);
       arg2 = evaluate_subexp (nullptr, exp, pos, noside);
-      if (noside == EVAL_SKIP)
-	return eval_skip_value (exp);
-      if (binop_user_defined_p (op, arg1, arg2))
-	return value_x_binop (arg1, arg2, op, OP_NULL, noside);
-      else
-	{
-	  /* If EVAL_AVOID_SIDE_EFFECTS and we're dividing by zero,
-	     fudge arg2 to avoid division-by-zero, the caller is
-	     (theoretically) only looking for the type of the result.  */
-	  if (noside == EVAL_AVOID_SIDE_EFFECTS
-	      /* ??? Do we really want to test for BINOP_MOD here?
-		 The implementation of value_binop gives it a well-defined
-		 value.  */
-	      && (op == BINOP_DIV
-		  || op == BINOP_INTDIV
-		  || op == BINOP_REM
-		  || op == BINOP_MOD)
-	      && value_logical_not (arg2))
-	    {
-	      struct value *v_one;
-
-	      v_one = value_one (value_type (arg2));
-	      binop_promote (exp->language_defn, exp->gdbarch, &arg1, &v_one);
-	      return value_binop (arg1, v_one, op);
-	    }
-	  else
-	    {
-	      /* For shift and integer exponentiation operations,
-		 only promote the first argument.  */
-	      if ((op == BINOP_LSH || op == BINOP_RSH || op == BINOP_EXP)
-		  && is_integral_type (value_type (arg2)))
-		unop_promote (exp->language_defn, exp->gdbarch, &arg1);
-	      else
-		binop_promote (exp->language_defn, exp->gdbarch, &arg1, &arg2);
-
-	      return value_binop (arg1, arg2, op);
-	    }
-	}
+      return eval_op_binary (expect_type, exp, noside, op, arg1, arg2);
 
     case BINOP_SUBSCRIPT:
       arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 017/203] Split out eval_op_subscript
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (15 preceding siblings ...)
  2021-01-01 21:44 ` [PATCH 016/203] Split out eval_op_binary Tom Tromey
@ 2021-01-01 21:44 ` Tom Tromey
  2021-01-01 21:44 ` [PATCH 018/203] Split out eval_op_equal Tom Tromey
                   ` (186 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:44 UTC (permalink / raw)
  To: gdb-patches

This splits BINOP_SUBSCRIPT into a new function for future use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* eval.c (eval_op_subscript): New function.
	(evaluate_subexp_standard): Use it.
---
 gdb/ChangeLog |  5 ++++
 gdb/eval.c    | 63 ++++++++++++++++++++++++++++++---------------------
 2 files changed, 42 insertions(+), 26 deletions(-)

diff --git a/gdb/eval.c b/gdb/eval.c
index 5f9d5413498..dc27d501003 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1540,6 +1540,42 @@ eval_op_binary (struct type *expect_type, struct expression *exp,
     }
 }
 
+/* A helper function for BINOP_SUBSCRIPT.  */
+
+static struct value *
+eval_op_subscript (struct type *expect_type, struct expression *exp,
+		   enum noside noside, enum exp_opcode op,
+		   struct value *arg1, struct value *arg2)
+{
+  if (noside == EVAL_SKIP)
+    return eval_skip_value (exp);
+  if (binop_user_defined_p (op, arg1, arg2))
+    return value_x_binop (arg1, arg2, op, OP_NULL, noside);
+  else
+    {
+      /* If the user attempts to subscript something that is not an
+	 array or pointer type (like a plain int variable for example),
+	 then report this as an error.  */
+
+      arg1 = coerce_ref (arg1);
+      struct type *type = check_typedef (value_type (arg1));
+      if (type->code () != TYPE_CODE_ARRAY
+	  && type->code () != TYPE_CODE_PTR)
+	{
+	  if (type->name ())
+	    error (_("cannot subscript something of type `%s'"),
+		   type->name ());
+	  else
+	    error (_("cannot subscript requested type"));
+	}
+
+      if (noside == EVAL_AVOID_SIDE_EFFECTS)
+	return value_zero (TYPE_TARGET_TYPE (type), VALUE_LVAL (arg1));
+      else
+	return value_subscript (arg1, value_as_long (arg2));
+    }
+}
+
 struct value *
 evaluate_subexp_standard (struct type *expect_type,
 			  struct expression *exp, int *pos,
@@ -2251,33 +2287,8 @@ evaluate_subexp_standard (struct type *expect_type,
     case BINOP_SUBSCRIPT:
       arg1 = evaluate_subexp (nullptr, exp, pos, noside);
       arg2 = evaluate_subexp (nullptr, exp, pos, noside);
-      if (noside == EVAL_SKIP)
-	return eval_skip_value (exp);
-      if (binop_user_defined_p (op, arg1, arg2))
-	return value_x_binop (arg1, arg2, op, OP_NULL, noside);
-      else
-	{
-	  /* If the user attempts to subscript something that is not an
-	     array or pointer type (like a plain int variable for example),
-	     then report this as an error.  */
+      return eval_op_subscript (expect_type, exp, noside, op, arg1, arg2);
 
-	  arg1 = coerce_ref (arg1);
-	  type = check_typedef (value_type (arg1));
-	  if (type->code () != TYPE_CODE_ARRAY
-	      && type->code () != TYPE_CODE_PTR)
-	    {
-	      if (type->name ())
-		error (_("cannot subscript something of type `%s'"),
-		       type->name ());
-	      else
-		error (_("cannot subscript requested type"));
-	    }
-
-	  if (noside == EVAL_AVOID_SIDE_EFFECTS)
-	    return value_zero (TYPE_TARGET_TYPE (type), VALUE_LVAL (arg1));
-	  else
-	    return value_subscript (arg1, value_as_long (arg2));
-	}
     case MULTI_SUBSCRIPT:
       (*pos) += 2;
       nargs = longest_to_int (exp->elts[pc + 1].longconst);
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 018/203] Split out eval_op_equal
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (16 preceding siblings ...)
  2021-01-01 21:44 ` [PATCH 017/203] Split out eval_op_subscript Tom Tromey
@ 2021-01-01 21:44 ` Tom Tromey
  2021-01-01 21:44 ` [PATCH 019/203] Split out eval_op_notequal Tom Tromey
                   ` (185 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:44 UTC (permalink / raw)
  To: gdb-patches

This splits BINOP_EQUAL into a new function for future use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* eval.c (eval_op_equal): New function.
	(evaluate_subexp_standard): Use it.
---
 gdb/ChangeLog |  5 +++++
 gdb/eval.c    | 37 ++++++++++++++++++++++++-------------
 2 files changed, 29 insertions(+), 13 deletions(-)

diff --git a/gdb/eval.c b/gdb/eval.c
index dc27d501003..229feb97aa9 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1576,6 +1576,29 @@ eval_op_subscript (struct type *expect_type, struct expression *exp,
     }
 }
 
+/* A helper function for BINOP_EQUAL.  */
+
+static struct value *
+eval_op_equal (struct type *expect_type, struct expression *exp,
+	       enum noside noside, enum exp_opcode op,
+	       struct value *arg1, struct value *arg2)
+{
+  if (noside == EVAL_SKIP)
+    return eval_skip_value (exp);
+  if (binop_user_defined_p (op, arg1, arg2))
+    {
+      return value_x_binop (arg1, arg2, op, OP_NULL, noside);
+    }
+  else
+    {
+      binop_promote (exp->language_defn, exp->gdbarch, &arg1, &arg2);
+      int tem = value_equal (arg1, arg2);
+      struct type *type = language_bool_type (exp->language_defn,
+					      exp->gdbarch);
+      return value_from_longest (type, (LONGEST) tem);
+    }
+}
+
 struct value *
 evaluate_subexp_standard (struct type *expect_type,
 			  struct expression *exp, int *pos,
@@ -2387,19 +2410,7 @@ evaluate_subexp_standard (struct type *expect_type,
     case BINOP_EQUAL:
       arg1 = evaluate_subexp (nullptr, exp, pos, noside);
       arg2 = evaluate_subexp (value_type (arg1), exp, pos, noside);
-      if (noside == EVAL_SKIP)
-	return eval_skip_value (exp);
-      if (binop_user_defined_p (op, arg1, arg2))
-	{
-	  return value_x_binop (arg1, arg2, op, OP_NULL, noside);
-	}
-      else
-	{
-	  binop_promote (exp->language_defn, exp->gdbarch, &arg1, &arg2);
-	  tem = value_equal (arg1, arg2);
-	  type = language_bool_type (exp->language_defn, exp->gdbarch);
-	  return value_from_longest (type, (LONGEST) tem);
-	}
+      return eval_op_equal (expect_type, exp, noside, op, arg1, arg2);
 
     case BINOP_NOTEQUAL:
       arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 019/203] Split out eval_op_notequal
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (17 preceding siblings ...)
  2021-01-01 21:44 ` [PATCH 018/203] Split out eval_op_equal Tom Tromey
@ 2021-01-01 21:44 ` Tom Tromey
  2021-01-01 21:44 ` [PATCH 020/203] Split out eval_op_less Tom Tromey
                   ` (184 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:44 UTC (permalink / raw)
  To: gdb-patches

This splits BINOP_NOTEQUAL into a new function for future use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* eval.c (eval_op_notequal): New function.
	(evaluate_subexp_standard): Use it.
---
 gdb/ChangeLog |  5 +++++
 gdb/eval.c    | 37 ++++++++++++++++++++++++-------------
 2 files changed, 29 insertions(+), 13 deletions(-)

diff --git a/gdb/eval.c b/gdb/eval.c
index 229feb97aa9..e11de2d96c1 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1599,6 +1599,29 @@ eval_op_equal (struct type *expect_type, struct expression *exp,
     }
 }
 
+/* A helper function for BINOP_NOTEQUAL.  */
+
+static struct value *
+eval_op_notequal (struct type *expect_type, struct expression *exp,
+		  enum noside noside, enum exp_opcode op,
+		  struct value *arg1, struct value *arg2)
+{
+  if (noside == EVAL_SKIP)
+    return eval_skip_value (exp);
+  if (binop_user_defined_p (op, arg1, arg2))
+    {
+      return value_x_binop (arg1, arg2, op, OP_NULL, noside);
+    }
+  else
+    {
+      binop_promote (exp->language_defn, exp->gdbarch, &arg1, &arg2);
+      int tem = value_equal (arg1, arg2);
+      struct type *type = language_bool_type (exp->language_defn,
+					      exp->gdbarch);
+      return value_from_longest (type, (LONGEST) ! tem);
+    }
+}
+
 struct value *
 evaluate_subexp_standard (struct type *expect_type,
 			  struct expression *exp, int *pos,
@@ -2415,19 +2438,7 @@ evaluate_subexp_standard (struct type *expect_type,
     case BINOP_NOTEQUAL:
       arg1 = evaluate_subexp (nullptr, exp, pos, noside);
       arg2 = evaluate_subexp (value_type (arg1), exp, pos, noside);
-      if (noside == EVAL_SKIP)
-	return eval_skip_value (exp);
-      if (binop_user_defined_p (op, arg1, arg2))
-	{
-	  return value_x_binop (arg1, arg2, op, OP_NULL, noside);
-	}
-      else
-	{
-	  binop_promote (exp->language_defn, exp->gdbarch, &arg1, &arg2);
-	  tem = value_equal (arg1, arg2);
-	  type = language_bool_type (exp->language_defn, exp->gdbarch);
-	  return value_from_longest (type, (LONGEST) ! tem);
-	}
+      return eval_op_notequal (expect_type, exp, noside, op, arg1, arg2);
 
     case BINOP_LESS:
       arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 020/203] Split out eval_op_less
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (18 preceding siblings ...)
  2021-01-01 21:44 ` [PATCH 019/203] Split out eval_op_notequal Tom Tromey
@ 2021-01-01 21:44 ` Tom Tromey
  2021-01-01 21:44 ` [PATCH 021/203] Split out eval_op_gtr Tom Tromey
                   ` (183 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:44 UTC (permalink / raw)
  To: gdb-patches

This splits BINOP_LESS into a new function for future use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* eval.c (eval_op_less): New function.
	(evaluate_subexp_standard): Use it.
---
 gdb/ChangeLog |  5 +++++
 gdb/eval.c    | 37 ++++++++++++++++++++++++-------------
 2 files changed, 29 insertions(+), 13 deletions(-)

diff --git a/gdb/eval.c b/gdb/eval.c
index e11de2d96c1..801cddcd311 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1622,6 +1622,29 @@ eval_op_notequal (struct type *expect_type, struct expression *exp,
     }
 }
 
+/* A helper function for BINOP_LESS.  */
+
+static struct value *
+eval_op_less (struct type *expect_type, struct expression *exp,
+	      enum noside noside, enum exp_opcode op,
+	      struct value *arg1, struct value *arg2)
+{
+  if (noside == EVAL_SKIP)
+    return eval_skip_value (exp);
+  if (binop_user_defined_p (op, arg1, arg2))
+    {
+      return value_x_binop (arg1, arg2, op, OP_NULL, noside);
+    }
+  else
+    {
+      binop_promote (exp->language_defn, exp->gdbarch, &arg1, &arg2);
+      int tem = value_less (arg1, arg2);
+      struct type *type = language_bool_type (exp->language_defn,
+					      exp->gdbarch);
+      return value_from_longest (type, (LONGEST) tem);
+    }
+}
+
 struct value *
 evaluate_subexp_standard (struct type *expect_type,
 			  struct expression *exp, int *pos,
@@ -2443,19 +2466,7 @@ evaluate_subexp_standard (struct type *expect_type,
     case BINOP_LESS:
       arg1 = evaluate_subexp (nullptr, exp, pos, noside);
       arg2 = evaluate_subexp (value_type (arg1), exp, pos, noside);
-      if (noside == EVAL_SKIP)
-	return eval_skip_value (exp);
-      if (binop_user_defined_p (op, arg1, arg2))
-	{
-	  return value_x_binop (arg1, arg2, op, OP_NULL, noside);
-	}
-      else
-	{
-	  binop_promote (exp->language_defn, exp->gdbarch, &arg1, &arg2);
-	  tem = value_less (arg1, arg2);
-	  type = language_bool_type (exp->language_defn, exp->gdbarch);
-	  return value_from_longest (type, (LONGEST) tem);
-	}
+      return eval_op_less (expect_type, exp, noside, op, arg1, arg2);
 
     case BINOP_GTR:
       arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 021/203] Split out eval_op_gtr
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (19 preceding siblings ...)
  2021-01-01 21:44 ` [PATCH 020/203] Split out eval_op_less Tom Tromey
@ 2021-01-01 21:44 ` Tom Tromey
  2021-01-01 21:44 ` [PATCH 022/203] Split out eval_op_geq Tom Tromey
                   ` (182 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:44 UTC (permalink / raw)
  To: gdb-patches

This splits BINOP_GTR into a new function for future use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* eval.c (eval_op_gtr): New function.
	(evaluate_subexp_standard): Use it.
---
 gdb/ChangeLog |  5 +++++
 gdb/eval.c    | 37 ++++++++++++++++++++++++-------------
 2 files changed, 29 insertions(+), 13 deletions(-)

diff --git a/gdb/eval.c b/gdb/eval.c
index 801cddcd311..3b702d3a3e6 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1645,6 +1645,29 @@ eval_op_less (struct type *expect_type, struct expression *exp,
     }
 }
 
+/* A helper function for BINOP_GTR.  */
+
+static struct value *
+eval_op_gtr (struct type *expect_type, struct expression *exp,
+	     enum noside noside, enum exp_opcode op,
+	     struct value *arg1, struct value *arg2)
+{
+  if (noside == EVAL_SKIP)
+    return eval_skip_value (exp);
+  if (binop_user_defined_p (op, arg1, arg2))
+    {
+      return value_x_binop (arg1, arg2, op, OP_NULL, noside);
+    }
+  else
+    {
+      binop_promote (exp->language_defn, exp->gdbarch, &arg1, &arg2);
+      int tem = value_less (arg2, arg1);
+      struct type *type = language_bool_type (exp->language_defn,
+					      exp->gdbarch);
+      return value_from_longest (type, (LONGEST) tem);
+    }
+}
+
 struct value *
 evaluate_subexp_standard (struct type *expect_type,
 			  struct expression *exp, int *pos,
@@ -2471,19 +2494,7 @@ evaluate_subexp_standard (struct type *expect_type,
     case BINOP_GTR:
       arg1 = evaluate_subexp (nullptr, exp, pos, noside);
       arg2 = evaluate_subexp (value_type (arg1), exp, pos, noside);
-      if (noside == EVAL_SKIP)
-	return eval_skip_value (exp);
-      if (binop_user_defined_p (op, arg1, arg2))
-	{
-	  return value_x_binop (arg1, arg2, op, OP_NULL, noside);
-	}
-      else
-	{
-	  binop_promote (exp->language_defn, exp->gdbarch, &arg1, &arg2);
-	  tem = value_less (arg2, arg1);
-	  type = language_bool_type (exp->language_defn, exp->gdbarch);
-	  return value_from_longest (type, (LONGEST) tem);
-	}
+      return eval_op_gtr (expect_type, exp, noside, op, arg1, arg2);
 
     case BINOP_GEQ:
       arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 022/203] Split out eval_op_geq
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (20 preceding siblings ...)
  2021-01-01 21:44 ` [PATCH 021/203] Split out eval_op_gtr Tom Tromey
@ 2021-01-01 21:44 ` Tom Tromey
  2021-01-01 21:44 ` [PATCH 023/203] Split out eval_op_leq Tom Tromey
                   ` (181 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:44 UTC (permalink / raw)
  To: gdb-patches

This splits BINOP_GEQ into a new function for future use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* eval.c (eval_op_geq): New function.
	(evaluate_subexp_standard): Use it.
---
 gdb/ChangeLog |  5 +++++
 gdb/eval.c    | 37 ++++++++++++++++++++++++-------------
 2 files changed, 29 insertions(+), 13 deletions(-)

diff --git a/gdb/eval.c b/gdb/eval.c
index 3b702d3a3e6..0cad57dd405 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1668,6 +1668,29 @@ eval_op_gtr (struct type *expect_type, struct expression *exp,
     }
 }
 
+/* A helper function for BINOP_GEQ.  */
+
+static struct value *
+eval_op_geq (struct type *expect_type, struct expression *exp,
+	     enum noside noside, enum exp_opcode op,
+	     struct value *arg1, struct value *arg2)
+{
+  if (noside == EVAL_SKIP)
+    return eval_skip_value (exp);
+  if (binop_user_defined_p (op, arg1, arg2))
+    {
+      return value_x_binop (arg1, arg2, op, OP_NULL, noside);
+    }
+  else
+    {
+      binop_promote (exp->language_defn, exp->gdbarch, &arg1, &arg2);
+      int tem = value_less (arg2, arg1) || value_equal (arg1, arg2);
+      struct type *type = language_bool_type (exp->language_defn,
+					      exp->gdbarch);
+      return value_from_longest (type, (LONGEST) tem);
+    }
+}
+
 struct value *
 evaluate_subexp_standard (struct type *expect_type,
 			  struct expression *exp, int *pos,
@@ -2499,19 +2522,7 @@ evaluate_subexp_standard (struct type *expect_type,
     case BINOP_GEQ:
       arg1 = evaluate_subexp (nullptr, exp, pos, noside);
       arg2 = evaluate_subexp (value_type (arg1), exp, pos, noside);
-      if (noside == EVAL_SKIP)
-	return eval_skip_value (exp);
-      if (binop_user_defined_p (op, arg1, arg2))
-	{
-	  return value_x_binop (arg1, arg2, op, OP_NULL, noside);
-	}
-      else
-	{
-	  binop_promote (exp->language_defn, exp->gdbarch, &arg1, &arg2);
-	  tem = value_less (arg2, arg1) || value_equal (arg1, arg2);
-	  type = language_bool_type (exp->language_defn, exp->gdbarch);
-	  return value_from_longest (type, (LONGEST) tem);
-	}
+      return eval_op_geq (expect_type, exp, noside, op, arg1, arg2);
 
     case BINOP_LEQ:
       arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 023/203] Split out eval_op_leq
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (21 preceding siblings ...)
  2021-01-01 21:44 ` [PATCH 022/203] Split out eval_op_geq Tom Tromey
@ 2021-01-01 21:44 ` Tom Tromey
  2021-01-01 21:44 ` [PATCH 024/203] Split out eval_op_repeat Tom Tromey
                   ` (180 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:44 UTC (permalink / raw)
  To: gdb-patches

This splits BINOP_LEQ into a new function for future use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* eval.c (eval_op_leq): New function.
	(evaluate_subexp_standard): Use it.
---
 gdb/ChangeLog |  5 +++++
 gdb/eval.c    | 37 ++++++++++++++++++++++++-------------
 2 files changed, 29 insertions(+), 13 deletions(-)

diff --git a/gdb/eval.c b/gdb/eval.c
index 0cad57dd405..5f96d430945 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1691,6 +1691,29 @@ eval_op_geq (struct type *expect_type, struct expression *exp,
     }
 }
 
+/* A helper function for BINOP_LEQ.  */
+
+static struct value *
+eval_op_leq (struct type *expect_type, struct expression *exp,
+	     enum noside noside, enum exp_opcode op,
+	     struct value *arg1, struct value *arg2)
+{
+  if (noside == EVAL_SKIP)
+    return eval_skip_value (exp);
+  if (binop_user_defined_p (op, arg1, arg2))
+    {
+      return value_x_binop (arg1, arg2, op, OP_NULL, noside);
+    }
+  else
+    {
+      binop_promote (exp->language_defn, exp->gdbarch, &arg1, &arg2);
+      int tem = value_less (arg1, arg2) || value_equal (arg1, arg2);
+      struct type *type = language_bool_type (exp->language_defn,
+					      exp->gdbarch);
+      return value_from_longest (type, (LONGEST) tem);
+    }
+}
+
 struct value *
 evaluate_subexp_standard (struct type *expect_type,
 			  struct expression *exp, int *pos,
@@ -2527,19 +2550,7 @@ evaluate_subexp_standard (struct type *expect_type,
     case BINOP_LEQ:
       arg1 = evaluate_subexp (nullptr, exp, pos, noside);
       arg2 = evaluate_subexp (value_type (arg1), exp, pos, noside);
-      if (noside == EVAL_SKIP)
-	return eval_skip_value (exp);
-      if (binop_user_defined_p (op, arg1, arg2))
-	{
-	  return value_x_binop (arg1, arg2, op, OP_NULL, noside);
-	}
-      else
-	{
-	  binop_promote (exp->language_defn, exp->gdbarch, &arg1, &arg2);
-	  tem = value_less (arg1, arg2) || value_equal (arg1, arg2);
-	  type = language_bool_type (exp->language_defn, exp->gdbarch);
-	  return value_from_longest (type, (LONGEST) tem);
-	}
+      return eval_op_leq (expect_type, exp, noside, op, arg1, arg2);
 
     case BINOP_REPEAT:
       arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 024/203] Split out eval_op_repeat
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (22 preceding siblings ...)
  2021-01-01 21:44 ` [PATCH 023/203] Split out eval_op_leq Tom Tromey
@ 2021-01-01 21:44 ` Tom Tromey
  2021-01-01 21:44 ` [PATCH 025/203] Split out eval_op_plus Tom Tromey
                   ` (179 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:44 UTC (permalink / raw)
  To: gdb-patches

This splits BINOP_REPEAT into a new function for future use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* eval.c (eval_op_repeat): New function.
	(evaluate_subexp_standard): Use it.
---
 gdb/ChangeLog |  5 +++++
 gdb/eval.c    | 36 +++++++++++++++++++++++-------------
 2 files changed, 28 insertions(+), 13 deletions(-)

diff --git a/gdb/eval.c b/gdb/eval.c
index 5f96d430945..fdbca1a8e05 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1714,6 +1714,28 @@ eval_op_leq (struct type *expect_type, struct expression *exp,
     }
 }
 
+/* A helper function for BINOP_REPEAT.  */
+
+static struct value *
+eval_op_repeat (struct type *expect_type, struct expression *exp,
+		enum noside noside,
+		struct value *arg1, struct value *arg2)
+{
+  if (noside == EVAL_SKIP)
+    return eval_skip_value (exp);
+  struct type *type = check_typedef (value_type (arg2));
+  if (type->code () != TYPE_CODE_INT
+      && type->code () != TYPE_CODE_ENUM)
+    error (_("Non-integral right operand for \"@\" operator."));
+  if (noside == EVAL_AVOID_SIDE_EFFECTS)
+    {
+      return allocate_repeat_value (value_type (arg1),
+				    longest_to_int (value_as_long (arg2)));
+    }
+  else
+    return value_repeat (arg1, longest_to_int (value_as_long (arg2)));
+}
+
 struct value *
 evaluate_subexp_standard (struct type *expect_type,
 			  struct expression *exp, int *pos,
@@ -2555,19 +2577,7 @@ evaluate_subexp_standard (struct type *expect_type,
     case BINOP_REPEAT:
       arg1 = evaluate_subexp (nullptr, exp, pos, noside);
       arg2 = evaluate_subexp (nullptr, exp, pos, noside);
-      if (noside == EVAL_SKIP)
-	return eval_skip_value (exp);
-      type = check_typedef (value_type (arg2));
-      if (type->code () != TYPE_CODE_INT
-	  && type->code () != TYPE_CODE_ENUM)
-	error (_("Non-integral right operand for \"@\" operator."));
-      if (noside == EVAL_AVOID_SIDE_EFFECTS)
-	{
-	  return allocate_repeat_value (value_type (arg1),
-				     longest_to_int (value_as_long (arg2)));
-	}
-      else
-	return value_repeat (arg1, longest_to_int (value_as_long (arg2)));
+      return eval_op_repeat (expect_type, exp, noside, arg1, arg2);
 
     case BINOP_COMMA:
       evaluate_subexp (nullptr, exp, pos, noside);
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 025/203] Split out eval_op_plus
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (23 preceding siblings ...)
  2021-01-01 21:44 ` [PATCH 024/203] Split out eval_op_repeat Tom Tromey
@ 2021-01-01 21:44 ` Tom Tromey
  2021-01-01 21:44 ` [PATCH 026/203] Split out eval_op_neg Tom Tromey
                   ` (178 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:44 UTC (permalink / raw)
  To: gdb-patches

This splits UNOP_PLUS into a new function for future use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* eval.c (eval_op_plus): New function.
	(evaluate_subexp_standard): Use it.
---
 gdb/ChangeLog |  5 +++++
 gdb/eval.c    | 28 +++++++++++++++++++---------
 2 files changed, 24 insertions(+), 9 deletions(-)

diff --git a/gdb/eval.c b/gdb/eval.c
index fdbca1a8e05..7d9c60a3d94 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1736,6 +1736,24 @@ eval_op_repeat (struct type *expect_type, struct expression *exp,
     return value_repeat (arg1, longest_to_int (value_as_long (arg2)));
 }
 
+/* A helper function for UNOP_PLUS.  */
+
+static struct value *
+eval_op_plus (struct type *expect_type, struct expression *exp,
+	      enum noside noside, enum exp_opcode op,
+	      struct value *arg1)
+{
+  if (noside == EVAL_SKIP)
+    return eval_skip_value (exp);
+  if (unop_user_defined_p (op, arg1))
+    return value_x_unop (arg1, op, noside);
+  else
+    {
+      unop_promote (exp->language_defn, exp->gdbarch, &arg1);
+      return value_pos (arg1);
+    }
+}
+
 struct value *
 evaluate_subexp_standard (struct type *expect_type,
 			  struct expression *exp, int *pos,
@@ -2585,15 +2603,7 @@ evaluate_subexp_standard (struct type *expect_type,
 
     case UNOP_PLUS:
       arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      if (noside == EVAL_SKIP)
-	return eval_skip_value (exp);
-      if (unop_user_defined_p (op, arg1))
-	return value_x_unop (arg1, op, noside);
-      else
-	{
-	  unop_promote (exp->language_defn, exp->gdbarch, &arg1);
-	  return value_pos (arg1);
-	}
+      return eval_op_plus (expect_type, exp, noside, op, arg1);
       
     case UNOP_NEG:
       arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 026/203] Split out eval_op_neg
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (24 preceding siblings ...)
  2021-01-01 21:44 ` [PATCH 025/203] Split out eval_op_plus Tom Tromey
@ 2021-01-01 21:44 ` Tom Tromey
  2021-01-01 21:44 ` [PATCH 027/203] Split out eval_op_complement Tom Tromey
                   ` (177 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:44 UTC (permalink / raw)
  To: gdb-patches

This splits UNOP NEG into a new function for future use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* eval.c (eval_op_neg): New function.
	(evaluate_subexp_standard): Use it.
---
 gdb/ChangeLog |  5 +++++
 gdb/eval.c    | 28 +++++++++++++++++++---------
 2 files changed, 24 insertions(+), 9 deletions(-)

diff --git a/gdb/eval.c b/gdb/eval.c
index 7d9c60a3d94..6bf3e146b06 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1754,6 +1754,24 @@ eval_op_plus (struct type *expect_type, struct expression *exp,
     }
 }
 
+/* A helper function for UNOP_NEG.  */
+
+static struct value *
+eval_op_neg (struct type *expect_type, struct expression *exp,
+	     enum noside noside, enum exp_opcode op,
+	     struct value *arg1)
+{
+  if (noside == EVAL_SKIP)
+    return eval_skip_value (exp);
+  if (unop_user_defined_p (op, arg1))
+    return value_x_unop (arg1, op, noside);
+  else
+    {
+      unop_promote (exp->language_defn, exp->gdbarch, &arg1);
+      return value_neg (arg1);
+    }
+}
+
 struct value *
 evaluate_subexp_standard (struct type *expect_type,
 			  struct expression *exp, int *pos,
@@ -2607,15 +2625,7 @@ evaluate_subexp_standard (struct type *expect_type,
       
     case UNOP_NEG:
       arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      if (noside == EVAL_SKIP)
-	return eval_skip_value (exp);
-      if (unop_user_defined_p (op, arg1))
-	return value_x_unop (arg1, op, noside);
-      else
-	{
-	  unop_promote (exp->language_defn, exp->gdbarch, &arg1);
-	  return value_neg (arg1);
-	}
+      return eval_op_neg (expect_type, exp, noside, op, arg1);
 
     case UNOP_COMPLEMENT:
       /* C++: check for and handle destructor names.  */
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 027/203] Split out eval_op_complement
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (25 preceding siblings ...)
  2021-01-01 21:44 ` [PATCH 026/203] Split out eval_op_neg Tom Tromey
@ 2021-01-01 21:44 ` Tom Tromey
  2021-01-01 21:44 ` [PATCH 028/203] Split out eval_op_lognot Tom Tromey
                   ` (176 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:44 UTC (permalink / raw)
  To: gdb-patches

This splits UNOP_COMPLEMENT into a new function for future use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* eval.c (eval_op_complement): New function.
	(evaluate_subexp_standard): Use it.
---
 gdb/ChangeLog |  5 +++++
 gdb/eval.c    | 28 +++++++++++++++++++---------
 2 files changed, 24 insertions(+), 9 deletions(-)

diff --git a/gdb/eval.c b/gdb/eval.c
index 6bf3e146b06..dbbdf80762c 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1772,6 +1772,24 @@ eval_op_neg (struct type *expect_type, struct expression *exp,
     }
 }
 
+/* A helper function for UNOP_COMPLEMENT.  */
+
+static struct value *
+eval_op_complement (struct type *expect_type, struct expression *exp,
+		    enum noside noside, enum exp_opcode op,
+		    struct value *arg1)
+{
+  if (noside == EVAL_SKIP)
+    return eval_skip_value (exp);
+  if (unop_user_defined_p (UNOP_COMPLEMENT, arg1))
+    return value_x_unop (arg1, UNOP_COMPLEMENT, noside);
+  else
+    {
+      unop_promote (exp->language_defn, exp->gdbarch, &arg1);
+      return value_complement (arg1);
+    }
+}
+
 struct value *
 evaluate_subexp_standard (struct type *expect_type,
 			  struct expression *exp, int *pos,
@@ -2631,15 +2649,7 @@ evaluate_subexp_standard (struct type *expect_type,
       /* C++: check for and handle destructor names.  */
 
       arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      if (noside == EVAL_SKIP)
-	return eval_skip_value (exp);
-      if (unop_user_defined_p (UNOP_COMPLEMENT, arg1))
-	return value_x_unop (arg1, UNOP_COMPLEMENT, noside);
-      else
-	{
-	  unop_promote (exp->language_defn, exp->gdbarch, &arg1);
-	  return value_complement (arg1);
-	}
+      return eval_op_complement (expect_type, exp, noside, op, arg1);
 
     case UNOP_LOGICAL_NOT:
       arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 028/203] Split out eval_op_lognot
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (26 preceding siblings ...)
  2021-01-01 21:44 ` [PATCH 027/203] Split out eval_op_complement Tom Tromey
@ 2021-01-01 21:44 ` Tom Tromey
  2021-01-01 21:44 ` [PATCH 029/203] Split out eval_op_ind Tom Tromey
                   ` (175 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:44 UTC (permalink / raw)
  To: gdb-patches

This splits UNOP_LOGICAL_NOT into a new function for future use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* eval.c (eval_op_lognot): New function.
	(evaluate_subexp_standard): Use it.
---
 gdb/ChangeLog |  5 +++++
 gdb/eval.c    | 29 ++++++++++++++++++++---------
 2 files changed, 25 insertions(+), 9 deletions(-)

diff --git a/gdb/eval.c b/gdb/eval.c
index dbbdf80762c..b2e429b2e8c 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1790,6 +1790,25 @@ eval_op_complement (struct type *expect_type, struct expression *exp,
     }
 }
 
+/* A helper function for UNOP_LOGICAL_NOT.  */
+
+static struct value *
+eval_op_lognot (struct type *expect_type, struct expression *exp,
+		enum noside noside, enum exp_opcode op,
+		struct value *arg1)
+{
+  if (noside == EVAL_SKIP)
+    return eval_skip_value (exp);
+  if (unop_user_defined_p (op, arg1))
+    return value_x_unop (arg1, op, noside);
+  else
+    {
+      struct type *type = language_bool_type (exp->language_defn,
+					      exp->gdbarch);
+      return value_from_longest (type, (LONGEST) value_logical_not (arg1));
+    }
+}
+
 struct value *
 evaluate_subexp_standard (struct type *expect_type,
 			  struct expression *exp, int *pos,
@@ -2653,15 +2672,7 @@ evaluate_subexp_standard (struct type *expect_type,
 
     case UNOP_LOGICAL_NOT:
       arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      if (noside == EVAL_SKIP)
-	return eval_skip_value (exp);
-      if (unop_user_defined_p (op, arg1))
-	return value_x_unop (arg1, op, noside);
-      else
-	{
-	  type = language_bool_type (exp->language_defn, exp->gdbarch);
-	  return value_from_longest (type, (LONGEST) value_logical_not (arg1));
-	}
+      return eval_op_lognot (expect_type, exp, noside, op, arg1);
 
     case UNOP_IND:
       if (expect_type && expect_type->code () == TYPE_CODE_PTR)
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 029/203] Split out eval_op_ind
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (27 preceding siblings ...)
  2021-01-01 21:44 ` [PATCH 028/203] Split out eval_op_lognot Tom Tromey
@ 2021-01-01 21:44 ` Tom Tromey
  2021-01-01 21:44 ` [PATCH 030/203] Split out eval_op_alignof Tom Tromey
                   ` (174 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:44 UTC (permalink / raw)
  To: gdb-patches

This splits UNOP_IND into a new function for future use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* eval.c (eval_op_ind): New function.
	(evaluate_subexp_standard): Use it.
---
 gdb/ChangeLog |  5 ++++
 gdb/eval.c    | 80 +++++++++++++++++++++++++++++----------------------
 2 files changed, 50 insertions(+), 35 deletions(-)

diff --git a/gdb/eval.c b/gdb/eval.c
index b2e429b2e8c..3626c8c9be2 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1809,6 +1809,50 @@ eval_op_lognot (struct type *expect_type, struct expression *exp,
     }
 }
 
+/* A helper function for UNOP_IND.  */
+
+static struct value *
+eval_op_ind (struct type *expect_type, struct expression *exp,
+	     enum noside noside, enum exp_opcode op,
+	     struct value *arg1)
+{
+  struct type *type = check_typedef (value_type (arg1));
+  if (type->code () == TYPE_CODE_METHODPTR
+      || type->code () == TYPE_CODE_MEMBERPTR)
+    error (_("Attempt to dereference pointer "
+	     "to member without an object"));
+  if (noside == EVAL_SKIP)
+    return eval_skip_value (exp);
+  if (unop_user_defined_p (op, arg1))
+    return value_x_unop (arg1, op, noside);
+  else if (noside == EVAL_AVOID_SIDE_EFFECTS)
+    {
+      type = check_typedef (value_type (arg1));
+      if (type->code () == TYPE_CODE_PTR
+	  || TYPE_IS_REFERENCE (type)
+	  /* In C you can dereference an array to get the 1st elt.  */
+	  || type->code () == TYPE_CODE_ARRAY
+	  )
+	return value_zero (TYPE_TARGET_TYPE (type),
+			   lval_memory);
+      else if (type->code () == TYPE_CODE_INT)
+	/* GDB allows dereferencing an int.  */
+	return value_zero (builtin_type (exp->gdbarch)->builtin_int,
+			   lval_memory);
+      else
+	error (_("Attempt to take contents of a non-pointer value."));
+    }
+
+  /* Allow * on an integer so we can cast it to whatever we want.
+     This returns an int, which seems like the most C-like thing to
+     do.  "long long" variables are rare enough that
+     BUILTIN_TYPE_LONGEST would seem to be a mistake.  */
+  if (type->code () == TYPE_CODE_INT)
+    return value_at_lazy (builtin_type (exp->gdbarch)->builtin_int,
+			  (CORE_ADDR) value_as_address (arg1));
+  return value_ind (arg1);
+}
+
 struct value *
 evaluate_subexp_standard (struct type *expect_type,
 			  struct expression *exp, int *pos,
@@ -2678,41 +2722,7 @@ evaluate_subexp_standard (struct type *expect_type,
       if (expect_type && expect_type->code () == TYPE_CODE_PTR)
 	expect_type = TYPE_TARGET_TYPE (check_typedef (expect_type));
       arg1 = evaluate_subexp (expect_type, exp, pos, noside);
-      type = check_typedef (value_type (arg1));
-      if (type->code () == TYPE_CODE_METHODPTR
-	  || type->code () == TYPE_CODE_MEMBERPTR)
-	error (_("Attempt to dereference pointer "
-		 "to member without an object"));
-      if (noside == EVAL_SKIP)
-	return eval_skip_value (exp);
-      if (unop_user_defined_p (op, arg1))
-	return value_x_unop (arg1, op, noside);
-      else if (noside == EVAL_AVOID_SIDE_EFFECTS)
-	{
-	  type = check_typedef (value_type (arg1));
-	  if (type->code () == TYPE_CODE_PTR
-	      || TYPE_IS_REFERENCE (type)
-	  /* In C you can dereference an array to get the 1st elt.  */
-	      || type->code () == TYPE_CODE_ARRAY
-	    )
-	    return value_zero (TYPE_TARGET_TYPE (type),
-			       lval_memory);
-	  else if (type->code () == TYPE_CODE_INT)
-	    /* GDB allows dereferencing an int.  */
-	    return value_zero (builtin_type (exp->gdbarch)->builtin_int,
-			       lval_memory);
-	  else
-	    error (_("Attempt to take contents of a non-pointer value."));
-	}
-
-      /* Allow * on an integer so we can cast it to whatever we want.
-	 This returns an int, which seems like the most C-like thing to
-	 do.  "long long" variables are rare enough that
-	 BUILTIN_TYPE_LONGEST would seem to be a mistake.  */
-      if (type->code () == TYPE_CODE_INT)
-	return value_at_lazy (builtin_type (exp->gdbarch)->builtin_int,
-			      (CORE_ADDR) value_as_address (arg1));
-      return value_ind (arg1);
+      return eval_op_ind (expect_type, exp, noside, op, arg1);
 
     case UNOP_ADDR:
       /* C++: check for and handle pointer to members.  */
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 030/203] Split out eval_op_alignof
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (28 preceding siblings ...)
  2021-01-01 21:44 ` [PATCH 029/203] Split out eval_op_ind Tom Tromey
@ 2021-01-01 21:44 ` Tom Tromey
  2021-01-01 21:44 ` [PATCH 031/203] Split out eval_op_memval Tom Tromey
                   ` (173 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:44 UTC (permalink / raw)
  To: gdb-patches

This splits UNOP_ALIGNOF into a new function for future use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* eval.c (eval_op_alignof): New function.
	(evaluate_subexp_standard): Use it.
---
 gdb/ChangeLog |  5 +++++
 gdb/eval.c    | 28 ++++++++++++++++++----------
 2 files changed, 23 insertions(+), 10 deletions(-)

diff --git a/gdb/eval.c b/gdb/eval.c
index 3626c8c9be2..5d29274b383 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1853,6 +1853,22 @@ eval_op_ind (struct type *expect_type, struct expression *exp,
   return value_ind (arg1);
 }
 
+/* A helper function for UNOP_ALIGNOF.  */
+
+static struct value *
+eval_op_alignof (struct type *expect_type, struct expression *exp,
+		 enum noside noside,
+		 struct value *arg1)
+{
+  struct type *type = value_type (arg1);
+  /* FIXME: This should be size_t.  */
+  struct type *size_type = builtin_type (exp->gdbarch)->builtin_int;
+  ULONGEST align = type_align (type);
+  if (align == 0)
+    error (_("could not determine alignment of type"));
+  return value_from_longest (size_type, align);
+}
+
 struct value *
 evaluate_subexp_standard (struct type *expect_type,
 			  struct expression *exp, int *pos,
@@ -2744,16 +2760,8 @@ evaluate_subexp_standard (struct type *expect_type,
       return evaluate_subexp_for_sizeof (exp, pos, noside);
 
     case UNOP_ALIGNOF:
-      {
-	type = value_type (
-	  evaluate_subexp (nullptr, exp, pos, EVAL_AVOID_SIDE_EFFECTS));
-	/* FIXME: This should be size_t.  */
-	struct type *size_type = builtin_type (exp->gdbarch)->builtin_int;
-	ULONGEST align = type_align (type);
-	if (align == 0)
-	  error (_("could not determine alignment of type"));
-	return value_from_longest (size_type, align);
-      }
+      arg1 = evaluate_subexp (nullptr, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
+      return eval_op_alignof (expect_type, exp, noside, arg1);
 
     case UNOP_CAST:
       (*pos) += 2;
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 031/203] Split out eval_op_memval
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (29 preceding siblings ...)
  2021-01-01 21:44 ` [PATCH 030/203] Split out eval_op_alignof Tom Tromey
@ 2021-01-01 21:44 ` Tom Tromey
  2021-01-01 21:44 ` [PATCH 032/203] Split out eval_op_preinc Tom Tromey
                   ` (172 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:44 UTC (permalink / raw)
  To: gdb-patches

This splits UNOP_MEMVAL into a new function for future use.  This new
function is also used to hande UNOP_MEMVAL_TYPE.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* eval.c (eval_op_memval): New function.
	(evaluate_subexp_standard): Use it.
---
 gdb/ChangeLog |  5 +++++
 gdb/eval.c    | 31 ++++++++++++++++++-------------
 2 files changed, 23 insertions(+), 13 deletions(-)

diff --git a/gdb/eval.c b/gdb/eval.c
index 5d29274b383..54ccf510db2 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1869,6 +1869,21 @@ eval_op_alignof (struct type *expect_type, struct expression *exp,
   return value_from_longest (size_type, align);
 }
 
+/* A helper function for UNOP_MEMVAL.  */
+
+static struct value *
+eval_op_memval (struct type *expect_type, struct expression *exp,
+		enum noside noside,
+		struct value *arg1, struct type *type)
+{
+  if (noside == EVAL_SKIP)
+    return eval_skip_value (exp);
+  if (noside == EVAL_AVOID_SIDE_EFFECTS)
+    return value_zero (type, lval_memory);
+  else
+    return value_at_lazy (type, value_as_address (arg1));
+}
+
 struct value *
 evaluate_subexp_standard (struct type *expect_type,
 			  struct expression *exp, int *pos,
@@ -2792,24 +2807,14 @@ evaluate_subexp_standard (struct type *expect_type,
     case UNOP_MEMVAL:
       (*pos) += 2;
       arg1 = evaluate_subexp (expect_type, exp, pos, noside);
-      if (noside == EVAL_SKIP)
-	return eval_skip_value (exp);
-      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));
+      return eval_op_memval (expect_type, exp, noside, arg1,
+			     exp->elts[pc + 1].type);
 
     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)
-	return eval_skip_value (exp);
-      if (noside == EVAL_AVOID_SIDE_EFFECTS)
-	return value_zero (type, lval_memory);
-      else
-	return value_at_lazy (type, value_as_address (arg1));
+      return eval_op_memval (expect_type, exp, noside, arg1, type);
 
     case UNOP_PREINCREMENT:
       arg1 = evaluate_subexp (expect_type, exp, pos, noside);
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 032/203] Split out eval_op_preinc
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (30 preceding siblings ...)
  2021-01-01 21:44 ` [PATCH 031/203] Split out eval_op_memval Tom Tromey
@ 2021-01-01 21:44 ` Tom Tromey
  2021-01-01 21:44 ` [PATCH 033/203] Split out eval_op_predec Tom Tromey
                   ` (171 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:44 UTC (permalink / raw)
  To: gdb-patches

This splits UNOP_PREINCREMENT into a new function for future use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* eval.c (eval_op_preinc): New function.
	(evaluate_subexp_standard): Use it.
---
 gdb/ChangeLog |  5 +++++
 gdb/eval.c    | 53 +++++++++++++++++++++++++++++++--------------------
 2 files changed, 37 insertions(+), 21 deletions(-)

diff --git a/gdb/eval.c b/gdb/eval.c
index 54ccf510db2..1f916c7d3bb 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1884,6 +1884,37 @@ eval_op_memval (struct type *expect_type, struct expression *exp,
     return value_at_lazy (type, value_as_address (arg1));
 }
 
+/* A helper function for UNOP_PREINCREMENT.  */
+
+static struct value *
+eval_op_preinc (struct type *expect_type, struct expression *exp,
+		enum noside noside, enum exp_opcode op,
+		struct value *arg1)
+{
+  if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS)
+    return arg1;
+  else if (unop_user_defined_p (op, arg1))
+    {
+      return value_x_unop (arg1, op, noside);
+    }
+  else
+    {
+      struct value *arg2;
+      if (ptrmath_type_p (exp->language_defn, value_type (arg1)))
+	arg2 = value_ptradd (arg1, 1);
+      else
+	{
+	  struct value *tmp = arg1;
+
+	  arg2 = value_one (value_type (arg1));
+	  binop_promote (exp->language_defn, exp->gdbarch, &tmp, &arg2);
+	  arg2 = value_binop (tmp, arg2, BINOP_ADD);
+	}
+
+      return value_assign (arg1, arg2);
+    }
+}
+
 struct value *
 evaluate_subexp_standard (struct type *expect_type,
 			  struct expression *exp, int *pos,
@@ -2818,27 +2849,7 @@ evaluate_subexp_standard (struct type *expect_type,
 
     case UNOP_PREINCREMENT:
       arg1 = evaluate_subexp (expect_type, exp, pos, noside);
-      if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS)
-	return arg1;
-      else if (unop_user_defined_p (op, arg1))
-	{
-	  return value_x_unop (arg1, op, noside);
-	}
-      else
-	{
-	  if (ptrmath_type_p (exp->language_defn, value_type (arg1)))
-	    arg2 = value_ptradd (arg1, 1);
-	  else
-	    {
-	      struct value *tmp = arg1;
-
-	      arg2 = value_one (value_type (arg1));
-	      binop_promote (exp->language_defn, exp->gdbarch, &tmp, &arg2);
-	      arg2 = value_binop (tmp, arg2, BINOP_ADD);
-	    }
-
-	  return value_assign (arg1, arg2);
-	}
+      return eval_op_preinc (expect_type, exp, noside, op, arg1);
 
     case UNOP_PREDECREMENT:
       arg1 = evaluate_subexp (expect_type, exp, pos, noside);
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 033/203] Split out eval_op_predec
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (31 preceding siblings ...)
  2021-01-01 21:44 ` [PATCH 032/203] Split out eval_op_preinc Tom Tromey
@ 2021-01-01 21:44 ` Tom Tromey
  2021-01-01 21:44 ` [PATCH 034/203] Split out eval_op_postinc Tom Tromey
                   ` (170 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:44 UTC (permalink / raw)
  To: gdb-patches

This splits UNOP_PREDECREMENT into a new function for future use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* eval.c (eval_op_predec): New file.
	(evaluate_subexp_standard): Use it.
---
 gdb/ChangeLog |  5 +++++
 gdb/eval.c    | 53 +++++++++++++++++++++++++++++++--------------------
 2 files changed, 37 insertions(+), 21 deletions(-)

diff --git a/gdb/eval.c b/gdb/eval.c
index 1f916c7d3bb..c8e2c14b8b0 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1915,6 +1915,37 @@ eval_op_preinc (struct type *expect_type, struct expression *exp,
     }
 }
 
+/* A helper function for UNOP_PREDECREMENT.  */
+
+static struct value *
+eval_op_predec (struct type *expect_type, struct expression *exp,
+		enum noside noside, enum exp_opcode op,
+		struct value *arg1)
+{
+  if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS)
+    return arg1;
+  else if (unop_user_defined_p (op, arg1))
+    {
+      return value_x_unop (arg1, op, noside);
+    }
+  else
+    {
+      struct value *arg2;
+      if (ptrmath_type_p (exp->language_defn, value_type (arg1)))
+	arg2 = value_ptradd (arg1, -1);
+      else
+	{
+	  struct value *tmp = arg1;
+
+	  arg2 = value_one (value_type (arg1));
+	  binop_promote (exp->language_defn, exp->gdbarch, &tmp, &arg2);
+	  arg2 = value_binop (tmp, arg2, BINOP_SUB);
+	}
+
+      return value_assign (arg1, arg2);
+    }
+}
+
 struct value *
 evaluate_subexp_standard (struct type *expect_type,
 			  struct expression *exp, int *pos,
@@ -2853,27 +2884,7 @@ evaluate_subexp_standard (struct type *expect_type,
 
     case UNOP_PREDECREMENT:
       arg1 = evaluate_subexp (expect_type, exp, pos, noside);
-      if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS)
-	return arg1;
-      else if (unop_user_defined_p (op, arg1))
-	{
-	  return value_x_unop (arg1, op, noside);
-	}
-      else
-	{
-	  if (ptrmath_type_p (exp->language_defn, value_type (arg1)))
-	    arg2 = value_ptradd (arg1, -1);
-	  else
-	    {
-	      struct value *tmp = arg1;
-
-	      arg2 = value_one (value_type (arg1));
-	      binop_promote (exp->language_defn, exp->gdbarch, &tmp, &arg2);
-	      arg2 = value_binop (tmp, arg2, BINOP_SUB);
-	    }
-
-	  return value_assign (arg1, arg2);
-	}
+      return eval_op_predec (expect_type, exp, noside, op, arg1);
 
     case UNOP_POSTINCREMENT:
       arg1 = evaluate_subexp (expect_type, exp, pos, noside);
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 034/203] Split out eval_op_postinc
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (32 preceding siblings ...)
  2021-01-01 21:44 ` [PATCH 033/203] Split out eval_op_predec Tom Tromey
@ 2021-01-01 21:44 ` Tom Tromey
  2021-01-01 21:44 ` [PATCH 035/203] Split out eval_op_postdec Tom Tromey
                   ` (169 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:44 UTC (permalink / raw)
  To: gdb-patches

This splits UNOP_POSTINCREMENT into a new function for future use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* eval.c (eval_op_postinc): New function.
	(evaluate_subexp_standard): Use it.
---
 gdb/ChangeLog |  5 +++++
 gdb/eval.c    | 59 ++++++++++++++++++++++++++++++---------------------
 2 files changed, 40 insertions(+), 24 deletions(-)

diff --git a/gdb/eval.c b/gdb/eval.c
index c8e2c14b8b0..82215d32d0d 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1946,6 +1946,40 @@ eval_op_predec (struct type *expect_type, struct expression *exp,
     }
 }
 
+/* A helper function for UNOP_POSTINCREMENT.  */
+
+static struct value *
+eval_op_postinc (struct type *expect_type, struct expression *exp,
+		 enum noside noside, enum exp_opcode op,
+		 struct value *arg1)
+{
+  if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS)
+    return arg1;
+  else if (unop_user_defined_p (op, arg1))
+    {
+      return value_x_unop (arg1, op, noside);
+    }
+  else
+    {
+      struct value *arg3 = value_non_lval (arg1);
+      struct value *arg2;
+
+      if (ptrmath_type_p (exp->language_defn, value_type (arg1)))
+	arg2 = value_ptradd (arg1, 1);
+      else
+	{
+	  struct value *tmp = arg1;
+
+	  arg2 = value_one (value_type (arg1));
+	  binop_promote (exp->language_defn, exp->gdbarch, &tmp, &arg2);
+	  arg2 = value_binop (tmp, arg2, BINOP_ADD);
+	}
+
+      value_assign (arg1, arg2);
+      return arg3;
+    }
+}
+
 struct value *
 evaluate_subexp_standard (struct type *expect_type,
 			  struct expression *exp, int *pos,
@@ -2888,30 +2922,7 @@ evaluate_subexp_standard (struct type *expect_type,
 
     case UNOP_POSTINCREMENT:
       arg1 = evaluate_subexp (expect_type, exp, pos, noside);
-      if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS)
-	return arg1;
-      else if (unop_user_defined_p (op, arg1))
-	{
-	  return value_x_unop (arg1, op, noside);
-	}
-      else
-	{
-	  arg3 = value_non_lval (arg1);
-
-	  if (ptrmath_type_p (exp->language_defn, value_type (arg1)))
-	    arg2 = value_ptradd (arg1, 1);
-	  else
-	    {
-	      struct value *tmp = arg1;
-
-	      arg2 = value_one (value_type (arg1));
-	      binop_promote (exp->language_defn, exp->gdbarch, &tmp, &arg2);
-	      arg2 = value_binop (tmp, arg2, BINOP_ADD);
-	    }
-
-	  value_assign (arg1, arg2);
-	  return arg3;
-	}
+      return eval_op_postinc (expect_type, exp, noside, op, arg1);
 
     case UNOP_POSTDECREMENT:
       arg1 = evaluate_subexp (expect_type, exp, pos, noside);
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 035/203] Split out eval_op_postdec
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (33 preceding siblings ...)
  2021-01-01 21:44 ` [PATCH 034/203] Split out eval_op_postinc Tom Tromey
@ 2021-01-01 21:44 ` Tom Tromey
  2021-01-01 21:44 ` [PATCH 036/203] Split out eval_op_type Tom Tromey
                   ` (168 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:44 UTC (permalink / raw)
  To: gdb-patches

This splits UNOP_POSTDECREMENT into a new function for future use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* eval.c (eval_op_postdec): New function.
	(evaluate_subexp_standard): Use it.
---
 gdb/ChangeLog |  5 +++++
 gdb/eval.c    | 60 ++++++++++++++++++++++++++++++---------------------
 2 files changed, 40 insertions(+), 25 deletions(-)

diff --git a/gdb/eval.c b/gdb/eval.c
index 82215d32d0d..fb9be4e6838 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1980,6 +1980,40 @@ eval_op_postinc (struct type *expect_type, struct expression *exp,
     }
 }
 
+/* A helper function for UNOP_POSTDECREMENT.  */
+
+static struct value *
+eval_op_postdec (struct type *expect_type, struct expression *exp,
+		 enum noside noside, enum exp_opcode op,
+		 struct value *arg1)
+{
+  if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS)
+    return arg1;
+  else if (unop_user_defined_p (op, arg1))
+    {
+      return value_x_unop (arg1, op, noside);
+    }
+  else
+    {
+      struct value *arg3 = value_non_lval (arg1);
+      struct value *arg2;
+
+      if (ptrmath_type_p (exp->language_defn, value_type (arg1)))
+	arg2 = value_ptradd (arg1, -1);
+      else
+	{
+	  struct value *tmp = arg1;
+
+	  arg2 = value_one (value_type (arg1));
+	  binop_promote (exp->language_defn, exp->gdbarch, &tmp, &arg2);
+	  arg2 = value_binop (tmp, arg2, BINOP_SUB);
+	}
+
+      value_assign (arg1, arg2);
+      return arg3;
+    }
+}
+
 struct value *
 evaluate_subexp_standard (struct type *expect_type,
 			  struct expression *exp, int *pos,
@@ -1990,7 +2024,6 @@ evaluate_subexp_standard (struct type *expect_type,
   int pc, oldpos;
   struct value *arg1 = NULL;
   struct value *arg2 = NULL;
-  struct value *arg3;
   struct type *type;
   int nargs;
   struct value **argvec;
@@ -2926,30 +2959,7 @@ evaluate_subexp_standard (struct type *expect_type,
 
     case UNOP_POSTDECREMENT:
       arg1 = evaluate_subexp (expect_type, exp, pos, noside);
-      if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS)
-	return arg1;
-      else if (unop_user_defined_p (op, arg1))
-	{
-	  return value_x_unop (arg1, op, noside);
-	}
-      else
-	{
-	  arg3 = value_non_lval (arg1);
-
-	  if (ptrmath_type_p (exp->language_defn, value_type (arg1)))
-	    arg2 = value_ptradd (arg1, -1);
-	  else
-	    {
-	      struct value *tmp = arg1;
-
-	      arg2 = value_one (value_type (arg1));
-	      binop_promote (exp->language_defn, exp->gdbarch, &tmp, &arg2);
-	      arg2 = value_binop (tmp, arg2, BINOP_SUB);
-	    }
-
-	  value_assign (arg1, arg2);
-	  return arg3;
-	}
+      return eval_op_postdec (expect_type, exp, noside, op, arg1);
 
     case OP_THIS:
       (*pos) += 1;
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 036/203] Split out eval_op_type
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (34 preceding siblings ...)
  2021-01-01 21:44 ` [PATCH 035/203] Split out eval_op_postdec Tom Tromey
@ 2021-01-01 21:44 ` Tom Tromey
  2021-01-01 21:44 ` [PATCH 037/203] Split out eval_op_f_abs Tom Tromey
                   ` (167 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:44 UTC (permalink / raw)
  To: gdb-patches

This splits OP_TYPE into a new function for future use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* eval.c (eval_op_type): New function.
	(evaluate_subexp_standard): Use it.
---
 gdb/ChangeLog |  5 +++++
 gdb/eval.c    | 21 +++++++++++++++------
 2 files changed, 20 insertions(+), 6 deletions(-)

diff --git a/gdb/eval.c b/gdb/eval.c
index fb9be4e6838..2907362f709 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -2014,6 +2014,20 @@ eval_op_postdec (struct type *expect_type, struct expression *exp,
     }
 }
 
+/* A helper function for OP_TYPE.  */
+
+static struct value *
+eval_op_type (struct type *expect_type, struct expression *exp,
+	      enum noside noside, struct type *type)
+{
+  if (noside == EVAL_SKIP)
+    return eval_skip_value (exp);
+  else if (noside == EVAL_AVOID_SIDE_EFFECTS)
+    return allocate_value (type);
+  else
+    error (_("Attempt to use a type name as an expression"));
+}
+
 struct value *
 evaluate_subexp_standard (struct type *expect_type,
 			  struct expression *exp, int *pos,
@@ -2969,12 +2983,7 @@ evaluate_subexp_standard (struct type *expect_type,
       /* The value is not supposed to be used.  This is here to make it
 	 easier to accommodate expressions that contain types.  */
       (*pos) += 2;
-      if (noside == EVAL_SKIP)
-	return eval_skip_value (exp);
-      else if (noside == EVAL_AVOID_SIDE_EFFECTS)
-	return allocate_value (exp->elts[pc + 1].type);
-      else
-	error (_("Attempt to use a type name as an expression"));
+      return eval_op_type (expect_type, exp, noside, exp->elts[pc + 1].type);
 
     case OP_TYPEOF:
     case OP_DECLTYPE:
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 037/203] Split out eval_op_f_abs
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (35 preceding siblings ...)
  2021-01-01 21:44 ` [PATCH 036/203] Split out eval_op_type Tom Tromey
@ 2021-01-01 21:44 ` Tom Tromey
  2021-01-01 21:44 ` [PATCH 038/203] Split out eval_op_f_mod Tom Tromey
                   ` (166 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:44 UTC (permalink / raw)
  To: gdb-patches

This splits UNOP_ABS into a new function for future use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* f-lang.c (eval_op_f_abs): New function.
	(evaluate_subexp_f): Use it.
---
 gdb/ChangeLog |  5 +++++
 gdb/f-lang.c  | 50 ++++++++++++++++++++++++++++++--------------------
 2 files changed, 35 insertions(+), 20 deletions(-)

diff --git a/gdb/f-lang.c b/gdb/f-lang.c
index da66ba8361f..2098a89e133 100644
--- a/gdb/f-lang.c
+++ b/gdb/f-lang.c
@@ -702,6 +702,35 @@ fortran_value_subarray (struct value *array, struct expression *exp,
   return array;
 }
 
+/* A helper function for UNOP_ABS.  */
+
+static struct value *
+eval_op_f_abs (struct type *expect_type, struct expression *exp,
+	       enum noside noside,
+	       struct value *arg1)
+{
+  if (noside == EVAL_SKIP)
+    return eval_skip_value (exp);
+  struct type *type = value_type (arg1);
+  switch (type->code ())
+    {
+    case TYPE_CODE_FLT:
+      {
+	double d
+	  = fabs (target_float_to_host_double (value_contents (arg1),
+					       value_type (arg1)));
+	return value_from_host_double (type, d);
+      }
+    case TYPE_CODE_INT:
+      {
+	LONGEST l = value_as_long (arg1);
+	l = llabs (l);
+	return value_from_longest (type, l);
+      }
+    }
+  error (_("ABS of type %s not supported"), TYPE_SAFE_NAME (type));
+}
+
 /* Special expression evaluation cases for Fortran.  */
 
 static struct value *
@@ -725,26 +754,7 @@ evaluate_subexp_f (struct type *expect_type, struct expression *exp,
 
     case UNOP_ABS:
       arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      if (noside == EVAL_SKIP)
-	return eval_skip_value (exp);
-      type = value_type (arg1);
-      switch (type->code ())
-	{
-	case TYPE_CODE_FLT:
-	  {
-	    double d
-	      = fabs (target_float_to_host_double (value_contents (arg1),
-						   value_type (arg1)));
-	    return value_from_host_double (type, d);
-	  }
-	case TYPE_CODE_INT:
-	  {
-	    LONGEST l = value_as_long (arg1);
-	    l = llabs (l);
-	    return value_from_longest (type, l);
-	  }
-	}
-      error (_("ABS of type %s not supported"), TYPE_SAFE_NAME (type));
+      return eval_op_f_abs (expect_type, exp, noside, arg1);
 
     case BINOP_MOD:
       arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 038/203] Split out eval_op_f_mod
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (36 preceding siblings ...)
  2021-01-01 21:44 ` [PATCH 037/203] Split out eval_op_f_abs Tom Tromey
@ 2021-01-01 21:44 ` Tom Tromey
  2021-01-01 21:44 ` [PATCH 039/203] Split out eval_op_f_ceil Tom Tromey
                   ` (165 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:44 UTC (permalink / raw)
  To: gdb-patches

This splits BINOP_MOD into a new function for future use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* f-lang.c (eval_op_f_mod): New function.
	(evaluate_subexp_f): Use it.
---
 gdb/ChangeLog |  5 ++++
 gdb/f-lang.c  | 68 +++++++++++++++++++++++++++++----------------------
 2 files changed, 44 insertions(+), 29 deletions(-)

diff --git a/gdb/f-lang.c b/gdb/f-lang.c
index 2098a89e133..5dcbb8194fa 100644
--- a/gdb/f-lang.c
+++ b/gdb/f-lang.c
@@ -731,6 +731,44 @@ eval_op_f_abs (struct type *expect_type, struct expression *exp,
   error (_("ABS of type %s not supported"), TYPE_SAFE_NAME (type));
 }
 
+/* A helper function for BINOP_MOD.  */
+
+static struct value *
+eval_op_f_mod (struct type *expect_type, struct expression *exp,
+	       enum noside noside,
+	       struct value *arg1, struct value *arg2)
+{
+  if (noside == EVAL_SKIP)
+    return eval_skip_value (exp);
+  struct type *type = value_type (arg1);
+  if (type->code () != value_type (arg2)->code ())
+    error (_("non-matching types for parameters to MOD ()"));
+  switch (type->code ())
+    {
+    case TYPE_CODE_FLT:
+      {
+	double d1
+	  = target_float_to_host_double (value_contents (arg1),
+					 value_type (arg1));
+	double d2
+	  = target_float_to_host_double (value_contents (arg2),
+					 value_type (arg2));
+	double d3 = fmod (d1, d2);
+	return value_from_host_double (type, d3);
+      }
+    case TYPE_CODE_INT:
+      {
+	LONGEST v1 = value_as_long (arg1);
+	LONGEST v2 = value_as_long (arg2);
+	if (v2 == 0)
+	  error (_("calling MOD (N, 0) is undefined"));
+	LONGEST v3 = v1 - (v1 / v2) * v2;
+	return value_from_longest (value_type (arg1), v3);
+      }
+    }
+  error (_("MOD of type %s not supported"), TYPE_SAFE_NAME (type));
+}
+
 /* Special expression evaluation cases for Fortran.  */
 
 static struct value *
@@ -759,35 +797,7 @@ evaluate_subexp_f (struct type *expect_type, struct expression *exp,
     case BINOP_MOD:
       arg1 = evaluate_subexp (nullptr, exp, pos, noside);
       arg2 = evaluate_subexp (value_type (arg1), exp, pos, noside);
-      if (noside == EVAL_SKIP)
-	return eval_skip_value (exp);
-      type = value_type (arg1);
-      if (type->code () != value_type (arg2)->code ())
-	error (_("non-matching types for parameters to MOD ()"));
-      switch (type->code ())
-	{
-	case TYPE_CODE_FLT:
-	  {
-	    double d1
-	      = target_float_to_host_double (value_contents (arg1),
-					     value_type (arg1));
-	    double d2
-	      = target_float_to_host_double (value_contents (arg2),
-					     value_type (arg2));
-	    double d3 = fmod (d1, d2);
-	    return value_from_host_double (type, d3);
-	  }
-	case TYPE_CODE_INT:
-	  {
-	    LONGEST v1 = value_as_long (arg1);
-	    LONGEST v2 = value_as_long (arg2);
-	    if (v2 == 0)
-	      error (_("calling MOD (N, 0) is undefined"));
-	    LONGEST v3 = v1 - (v1 / v2) * v2;
-	    return value_from_longest (value_type (arg1), v3);
-	  }
-	}
-      error (_("MOD of type %s not supported"), TYPE_SAFE_NAME (type));
+      return eval_op_f_mod (expect_type, exp, noside, arg1, arg2);
 
     case UNOP_FORTRAN_CEILING:
       {
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 039/203] Split out eval_op_f_ceil
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (37 preceding siblings ...)
  2021-01-01 21:44 ` [PATCH 038/203] Split out eval_op_f_mod Tom Tromey
@ 2021-01-01 21:44 ` Tom Tromey
  2021-01-01 21:44 ` [PATCH 040/203] Split out eval_op_f_floor Tom Tromey
                   ` (164 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:44 UTC (permalink / raw)
  To: gdb-patches

This splits UNOP_FORTRAN_CEILING into a new function for future use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* f-lang.c (eval_op_f_ceil): New function.
	(evaluate_subexp_f): Use it.
---
 gdb/ChangeLog |  5 +++++
 gdb/f-lang.c  | 34 +++++++++++++++++++++-------------
 2 files changed, 26 insertions(+), 13 deletions(-)

diff --git a/gdb/f-lang.c b/gdb/f-lang.c
index 5dcbb8194fa..ca676044ee3 100644
--- a/gdb/f-lang.c
+++ b/gdb/f-lang.c
@@ -769,6 +769,25 @@ eval_op_f_mod (struct type *expect_type, struct expression *exp,
   error (_("MOD of type %s not supported"), TYPE_SAFE_NAME (type));
 }
 
+/* A helper function for UNOP_FORTRAN_CEILING.  */
+
+static struct value *
+eval_op_f_ceil (struct type *expect_type, struct expression *exp,
+		enum noside noside,
+		struct value *arg1)
+{
+  if (noside == EVAL_SKIP)
+    return eval_skip_value (exp);
+  struct type *type = value_type (arg1);
+  if (type->code () != TYPE_CODE_FLT)
+    error (_("argument to CEILING must be of type float"));
+  double val
+    = target_float_to_host_double (value_contents (arg1),
+				   value_type (arg1));
+  val = ceil (val);
+  return value_from_host_double (type, val);
+}
+
 /* Special expression evaluation cases for Fortran.  */
 
 static struct value *
@@ -800,19 +819,8 @@ evaluate_subexp_f (struct type *expect_type, struct expression *exp,
       return eval_op_f_mod (expect_type, exp, noside, arg1, arg2);
 
     case UNOP_FORTRAN_CEILING:
-      {
-	arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-	if (noside == EVAL_SKIP)
-	  return eval_skip_value (exp);
-	type = value_type (arg1);
-	if (type->code () != TYPE_CODE_FLT)
-	  error (_("argument to CEILING must be of type float"));
-	double val
-	  = target_float_to_host_double (value_contents (arg1),
-					 value_type (arg1));
-	val = ceil (val);
-	return value_from_host_double (type, val);
-      }
+      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
+      return eval_op_f_ceil (expect_type, exp, noside, arg1);
 
     case UNOP_FORTRAN_FLOOR:
       {
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 040/203] Split out eval_op_f_floor
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (38 preceding siblings ...)
  2021-01-01 21:44 ` [PATCH 039/203] Split out eval_op_f_ceil Tom Tromey
@ 2021-01-01 21:44 ` Tom Tromey
  2021-01-01 21:44 ` [PATCH 041/203] Split out eval_op_f_modulo Tom Tromey
                   ` (163 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:44 UTC (permalink / raw)
  To: gdb-patches

This splits UNOP_FORTRAN_FLOOR into a new function for future use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* f-lang.c (eval_op_f_floor): New function.
	(evaluate_subexp_f): Use it.
---
 gdb/ChangeLog |  5 +++++
 gdb/f-lang.c  | 34 +++++++++++++++++++++-------------
 2 files changed, 26 insertions(+), 13 deletions(-)

diff --git a/gdb/f-lang.c b/gdb/f-lang.c
index ca676044ee3..df77a852fbc 100644
--- a/gdb/f-lang.c
+++ b/gdb/f-lang.c
@@ -788,6 +788,25 @@ eval_op_f_ceil (struct type *expect_type, struct expression *exp,
   return value_from_host_double (type, val);
 }
 
+/* A helper function for UNOP_FORTRAN_FLOOR.  */
+
+static struct value *
+eval_op_f_floor (struct type *expect_type, struct expression *exp,
+		 enum noside noside,
+		 struct value *arg1)
+{
+  if (noside == EVAL_SKIP)
+    return eval_skip_value (exp);
+  struct type *type = value_type (arg1);
+  if (type->code () != TYPE_CODE_FLT)
+    error (_("argument to FLOOR must be of type float"));
+  double val
+    = target_float_to_host_double (value_contents (arg1),
+				   value_type (arg1));
+  val = floor (val);
+  return value_from_host_double (type, val);
+}
+
 /* Special expression evaluation cases for Fortran.  */
 
 static struct value *
@@ -823,19 +842,8 @@ evaluate_subexp_f (struct type *expect_type, struct expression *exp,
       return eval_op_f_ceil (expect_type, exp, noside, arg1);
 
     case UNOP_FORTRAN_FLOOR:
-      {
-	arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-	if (noside == EVAL_SKIP)
-	  return eval_skip_value (exp);
-	type = value_type (arg1);
-	if (type->code () != TYPE_CODE_FLT)
-	  error (_("argument to FLOOR must be of type float"));
-	double val
-	  = target_float_to_host_double (value_contents (arg1),
-					 value_type (arg1));
-	val = floor (val);
-	return value_from_host_double (type, val);
-      }
+      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
+      return eval_op_f_floor (expect_type, exp, noside, arg1);
 
     case BINOP_FORTRAN_MODULO:
       {
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 041/203] Split out eval_op_f_modulo
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (39 preceding siblings ...)
  2021-01-01 21:44 ` [PATCH 040/203] Split out eval_op_f_floor Tom Tromey
@ 2021-01-01 21:44 ` Tom Tromey
  2021-01-01 21:44 ` [PATCH 042/203] Split out eval_op_f_cmplx Tom Tromey
                   ` (162 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:44 UTC (permalink / raw)
  To: gdb-patches

This splits BINOP_FORTRAN_MODULO into a new function for future use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* f-lang.c (eval_op_f_modulo): New function.
	(evaluate_subexp_f): Use it.
---
 gdb/ChangeLog |  5 ++++
 gdb/f-lang.c  | 80 ++++++++++++++++++++++++++++-----------------------
 2 files changed, 49 insertions(+), 36 deletions(-)

diff --git a/gdb/f-lang.c b/gdb/f-lang.c
index df77a852fbc..b127f6edf05 100644
--- a/gdb/f-lang.c
+++ b/gdb/f-lang.c
@@ -807,6 +807,47 @@ eval_op_f_floor (struct type *expect_type, struct expression *exp,
   return value_from_host_double (type, val);
 }
 
+/* A helper function for BINOP_FORTRAN_MODULO.  */
+
+static struct value *
+eval_op_f_modulo (struct type *expect_type, struct expression *exp,
+		  enum noside noside,
+		  struct value *arg1, struct value *arg2)
+{
+  if (noside == EVAL_SKIP)
+    return eval_skip_value (exp);
+  struct type *type = value_type (arg1);
+  if (type->code () != value_type (arg2)->code ())
+    error (_("non-matching types for parameters to MODULO ()"));
+  /* MODULO(A, P) = A - FLOOR (A / P) * P */
+  switch (type->code ())
+    {
+    case TYPE_CODE_INT:
+      {
+	LONGEST a = value_as_long (arg1);
+	LONGEST p = value_as_long (arg2);
+	LONGEST result = a - (a / p) * p;
+	if (result != 0 && (a < 0) != (p < 0))
+	  result += p;
+	return value_from_longest (value_type (arg1), result);
+      }
+    case TYPE_CODE_FLT:
+      {
+	double a
+	  = target_float_to_host_double (value_contents (arg1),
+					 value_type (arg1));
+	double p
+	  = target_float_to_host_double (value_contents (arg2),
+					 value_type (arg2));
+	double result = fmod (a, p);
+	if (result != 0 && (a < 0.0) != (p < 0.0))
+	  result += p;
+	return value_from_host_double (type, result);
+      }
+    }
+  error (_("MODULO of type %s not supported"), TYPE_SAFE_NAME (type));
+}
+
 /* Special expression evaluation cases for Fortran.  */
 
 static struct value *
@@ -846,42 +887,9 @@ evaluate_subexp_f (struct type *expect_type, struct expression *exp,
       return eval_op_f_floor (expect_type, exp, noside, arg1);
 
     case BINOP_FORTRAN_MODULO:
-      {
-	arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-	arg2 = evaluate_subexp (value_type (arg1), exp, pos, noside);
-	if (noside == EVAL_SKIP)
-	  return eval_skip_value (exp);
-	type = value_type (arg1);
-	if (type->code () != value_type (arg2)->code ())
-	  error (_("non-matching types for parameters to MODULO ()"));
-	/* MODULO(A, P) = A - FLOOR (A / P) * P */
-	switch (type->code ())
-	  {
-	  case TYPE_CODE_INT:
-	    {
-	      LONGEST a = value_as_long (arg1);
-	      LONGEST p = value_as_long (arg2);
-	      LONGEST result = a - (a / p) * p;
-	      if (result != 0 && (a < 0) != (p < 0))
-		result += p;
-	      return value_from_longest (value_type (arg1), result);
-	    }
-	  case TYPE_CODE_FLT:
-	    {
-	      double a
-		= target_float_to_host_double (value_contents (arg1),
-					       value_type (arg1));
-	      double p
-		= target_float_to_host_double (value_contents (arg2),
-					       value_type (arg2));
-	      double result = fmod (a, p);
-	      if (result != 0 && (a < 0.0) != (p < 0.0))
-		result += p;
-	      return value_from_host_double (type, result);
-	    }
-	  }
-	error (_("MODULO of type %s not supported"), TYPE_SAFE_NAME (type));
-      }
+      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
+      arg2 = evaluate_subexp (value_type (arg1), exp, pos, noside);
+      return eval_op_f_modulo (expect_type, exp, noside, arg1, arg2);
 
     case BINOP_FORTRAN_CMPLX:
       arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 042/203] Split out eval_op_f_cmplx
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (40 preceding siblings ...)
  2021-01-01 21:44 ` [PATCH 041/203] Split out eval_op_f_modulo Tom Tromey
@ 2021-01-01 21:44 ` Tom Tromey
  2021-01-01 21:44 ` [PATCH 043/203] Split out eval_op_f_kind Tom Tromey
                   ` (161 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:44 UTC (permalink / raw)
  To: gdb-patches

This splits BINOP_FORTRAN_CMPLX into a new function for future use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* f-lang.c (eval_op_f_cmplx): New function.
	(evaluate_subexp_f): Use it.
---
 gdb/ChangeLog |  5 +++++
 gdb/f-lang.c  | 18 ++++++++++++++----
 2 files changed, 19 insertions(+), 4 deletions(-)

diff --git a/gdb/f-lang.c b/gdb/f-lang.c
index b127f6edf05..949812cc15a 100644
--- a/gdb/f-lang.c
+++ b/gdb/f-lang.c
@@ -848,6 +848,19 @@ eval_op_f_modulo (struct type *expect_type, struct expression *exp,
   error (_("MODULO of type %s not supported"), TYPE_SAFE_NAME (type));
 }
 
+/* A helper function for BINOP_FORTRAN_CMPLX.  */
+
+static struct value *
+eval_op_f_cmplx (struct type *expect_type, struct expression *exp,
+		 enum noside noside,
+		 struct value *arg1, struct value *arg2)
+{
+  if (noside == EVAL_SKIP)
+    return eval_skip_value (exp);
+  struct type *type = builtin_f_type(exp->gdbarch)->builtin_complex_s16;
+  return value_literal_complex (arg1, arg2, type);
+}
+
 /* Special expression evaluation cases for Fortran.  */
 
 static struct value *
@@ -894,10 +907,7 @@ evaluate_subexp_f (struct type *expect_type, struct expression *exp,
     case BINOP_FORTRAN_CMPLX:
       arg1 = evaluate_subexp (nullptr, exp, pos, noside);
       arg2 = evaluate_subexp (value_type (arg1), exp, pos, noside);
-      if (noside == EVAL_SKIP)
-	return eval_skip_value (exp);
-      type = builtin_f_type(exp->gdbarch)->builtin_complex_s16;
-      return value_literal_complex (arg1, arg2, type);
+      return eval_op_f_cmplx (expect_type, exp, noside, arg1, arg2);
 
     case UNOP_FORTRAN_KIND:
       arg1 = evaluate_subexp (NULL, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 043/203] Split out eval_op_f_kind
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (41 preceding siblings ...)
  2021-01-01 21:44 ` [PATCH 042/203] Split out eval_op_f_cmplx Tom Tromey
@ 2021-01-01 21:44 ` Tom Tromey
  2021-01-01 21:44 ` [PATCH 044/203] Change parameters to rust_range Tom Tromey
                   ` (160 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:44 UTC (permalink / raw)
  To: gdb-patches

This splits UNOP_FORTRAN_KIND into a new function for future use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* f-lang.c (eval_op_f_kind): New function.
	(evaluate_subexp_f): Use it.
---
 gdb/ChangeLog |  5 +++++
 gdb/f-lang.c  | 43 ++++++++++++++++++++++++++-----------------
 2 files changed, 31 insertions(+), 17 deletions(-)

diff --git a/gdb/f-lang.c b/gdb/f-lang.c
index 949812cc15a..d0932389726 100644
--- a/gdb/f-lang.c
+++ b/gdb/f-lang.c
@@ -861,6 +861,31 @@ eval_op_f_cmplx (struct type *expect_type, struct expression *exp,
   return value_literal_complex (arg1, arg2, type);
 }
 
+/* A helper function for UNOP_FORTRAN_KIND.  */
+
+static struct value *
+eval_op_f_kind (struct type *expect_type, struct expression *exp,
+		enum noside noside,
+		struct value *arg1)
+{
+  struct type *type = value_type (arg1);
+
+  switch (type->code ())
+    {
+    case TYPE_CODE_STRUCT:
+    case TYPE_CODE_UNION:
+    case TYPE_CODE_MODULE:
+    case TYPE_CODE_FUNC:
+      error (_("argument to kind must be an intrinsic type"));
+    }
+
+  if (!TYPE_TARGET_TYPE (type))
+    return value_from_longest (builtin_type (exp->gdbarch)->builtin_int,
+			       TYPE_LENGTH (type));
+  return value_from_longest (builtin_type (exp->gdbarch)->builtin_int,
+			     TYPE_LENGTH (TYPE_TARGET_TYPE (type)));
+}
+
 /* Special expression evaluation cases for Fortran.  */
 
 static struct value *
@@ -911,23 +936,7 @@ evaluate_subexp_f (struct type *expect_type, struct expression *exp,
 
     case UNOP_FORTRAN_KIND:
       arg1 = evaluate_subexp (NULL, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
-      type = value_type (arg1);
-
-      switch (type->code ())
-	{
-	  case TYPE_CODE_STRUCT:
-	  case TYPE_CODE_UNION:
-	  case TYPE_CODE_MODULE:
-	  case TYPE_CODE_FUNC:
-	    error (_("argument to kind must be an intrinsic type"));
-	}
-
-      if (!TYPE_TARGET_TYPE (type))
-	return value_from_longest (builtin_type (exp->gdbarch)->builtin_int,
-				   TYPE_LENGTH (type));
-      return value_from_longest (builtin_type (exp->gdbarch)->builtin_int,
-				 TYPE_LENGTH (TYPE_TARGET_TYPE (type)));
-
+      return eval_op_f_kind (expect_type, exp, noside, arg1);
 
     case OP_F77_UNDETERMINED_ARGLIST:
       /* Remember that in F77, functions, substring ops and array subscript
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 044/203] Change parameters to rust_range
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (42 preceding siblings ...)
  2021-01-01 21:44 ` [PATCH 043/203] Split out eval_op_f_kind Tom Tromey
@ 2021-01-01 21:44 ` Tom Tromey
  2021-01-01 21:44 ` [PATCH 045/203] Change parameters to rust_subscript Tom Tromey
                   ` (159 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:44 UTC (permalink / raw)
  To: gdb-patches

This changes the parameters to rust_range, making it more suitable for
reuse by the (coming) new expression code.  In particular, rust_range
no longer evaluates its subexpressions.  Instead, they are passed in.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* rust-lang.c (rust_range): Change parameters.
	(rust_evaluate_subexp): Update.
---
 gdb/ChangeLog   |  5 +++++
 gdb/rust-lang.c | 27 ++++++++++++++++-----------
 2 files changed, 21 insertions(+), 11 deletions(-)

diff --git a/gdb/rust-lang.c b/gdb/rust-lang.c
index e9827ff15f7..c460d03172e 100644
--- a/gdb/rust-lang.c
+++ b/gdb/rust-lang.c
@@ -1041,9 +1041,10 @@ rust_evaluate_funcall (struct expression *exp, int *pos, enum noside noside)
 /* A helper for rust_evaluate_subexp that handles OP_RANGE.  */
 
 static struct value *
-rust_range (struct expression *exp, int *pos, enum noside noside)
+rust_range (struct type *expect_type, struct expression *exp,
+	    enum noside noside, enum range_flag kind,
+	    struct value *low, struct value *high)
 {
-  struct value *low = NULL, *high = NULL;
   struct value *addrval, *result;
   CORE_ADDR addr;
   struct type *range_type;
@@ -1051,14 +1052,6 @@ rust_range (struct expression *exp, int *pos, enum noside noside)
   struct type *temp_type;
   const char *name;
 
-  auto kind
-    = (enum range_flag) longest_to_int (exp->elts[*pos + 1].longconst);
-  *pos += 3;
-
-  if (!(kind & RANGE_LOW_BOUND_DEFAULT))
-    low = evaluate_subexp (nullptr, exp, pos, noside);
-  if (!(kind & RANGE_HIGH_BOUND_DEFAULT))
-    high = evaluate_subexp (nullptr, exp, pos, noside);
   bool inclusive = !(kind & RANGE_HIGH_BOUND_EXCLUSIVE);
 
   if (noside == EVAL_SKIP)
@@ -1614,7 +1607,19 @@ tuple structs, and tuple-like enum variants"));
       break;
 
     case OP_RANGE:
-      result = rust_range (exp, pos, noside);
+      {
+	struct value *low = NULL, *high = NULL;
+	auto kind
+	  = (enum range_flag) longest_to_int (exp->elts[*pos + 1].longconst);
+	*pos += 3;
+
+	if (!(kind & RANGE_LOW_BOUND_DEFAULT))
+	  low = evaluate_subexp (nullptr, exp, pos, noside);
+	if (!(kind & RANGE_HIGH_BOUND_DEFAULT))
+	  high = evaluate_subexp (nullptr, exp, pos, noside);
+
+	result = rust_range (expect_type, exp, noside, kind, low, high);
+      }
       break;
 
     case UNOP_ADDR:
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 045/203] Change parameters to rust_subscript
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (43 preceding siblings ...)
  2021-01-01 21:44 ` [PATCH 044/203] Change parameters to rust_range Tom Tromey
@ 2021-01-01 21:44 ` Tom Tromey
  2021-01-01 21:44 ` [PATCH 046/203] Split out eval_op_rust_ind Tom Tromey
                   ` (158 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:44 UTC (permalink / raw)
  To: gdb-patches

This changes the parameters to rust_subscript, making it more suitable
for reuse by the (coming) new expression code.  In particular,
rust_subscript no longer evaluates its subexpressions.  Instead, they
are passed in.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* rust-lang.c (rust_subscript): Change parameters.
	(rust_evaluate_subexp): Update.
---
 gdb/ChangeLog   |  5 +++++
 gdb/rust-lang.c | 24 +++++++++++++++---------
 2 files changed, 20 insertions(+), 9 deletions(-)

diff --git a/gdb/rust-lang.c b/gdb/rust-lang.c
index c460d03172e..a635c8b8449 100644
--- a/gdb/rust-lang.c
+++ b/gdb/rust-lang.c
@@ -1168,10 +1168,11 @@ rust_compute_range (struct type *type, struct value *range,
 /* A helper for rust_evaluate_subexp that handles BINOP_SUBSCRIPT.  */
 
 static struct value *
-rust_subscript (struct expression *exp, int *pos, enum noside noside,
-		int for_addr)
+rust_subscript (struct type *expect_type, struct expression *exp,
+		enum noside noside, bool for_addr,
+		struct value *lhs, struct value *rhs)
 {
-  struct value *lhs, *rhs, *result;
+  struct value *result;
   struct type *rhstype;
   LONGEST low, high_bound;
   /* Initialized to appease the compiler.  */
@@ -1179,10 +1180,6 @@ rust_subscript (struct expression *exp, int *pos, enum noside noside,
   LONGEST high = 0;
   int want_slice = 0;
 
-  ++*pos;
-  lhs = evaluate_subexp (nullptr, exp, pos, noside);
-  rhs = evaluate_subexp (nullptr, exp, pos, noside);
-
   if (noside == EVAL_SKIP)
     return lhs;
 
@@ -1374,7 +1371,12 @@ rust_evaluate_subexp (struct type *expect_type, struct expression *exp,
       break;
 
     case BINOP_SUBSCRIPT:
-      result = rust_subscript (exp, pos, noside, 0);
+      {
+	++*pos;
+	struct value *lhs = evaluate_subexp (nullptr, exp, pos, noside);
+	struct value *rhs = evaluate_subexp (nullptr, exp, pos, noside);
+	result = rust_subscript (expect_type, exp, noside, false, lhs, rhs);
+      }
       break;
 
     case OP_FUNCALL:
@@ -1628,7 +1630,11 @@ tuple structs, and tuple-like enum variants"));
       if (exp->elts[*pos + 1].opcode == BINOP_SUBSCRIPT)
 	{
 	  ++*pos;
-	  result = rust_subscript (exp, pos, noside, 1);
+	  ++*pos;
+	  struct value *lhs = evaluate_subexp (nullptr, exp, pos, noside);
+	  struct value *rhs = evaluate_subexp (nullptr, exp, pos, noside);
+
+	  result = rust_subscript (expect_type, exp, noside, true, lhs, rhs);
 	  break;
 	}
       /* Fall through.  */
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 046/203] Split out eval_op_rust_ind
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (44 preceding siblings ...)
  2021-01-01 21:44 ` [PATCH 045/203] Change parameters to rust_subscript Tom Tromey
@ 2021-01-01 21:44 ` Tom Tromey
  2021-01-01 21:44 ` [PATCH 047/203] Split out eval_op_rust_complement Tom Tromey
                   ` (157 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:44 UTC (permalink / raw)
  To: gdb-patches

This splits UNOP_IND into a new function for future use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* rust-lang.c (eval_op_rust_ind): New function.
	(rust_evaluate_subexp): Use it.
---
 gdb/ChangeLog   |  5 +++++
 gdb/rust-lang.c | 22 ++++++++++++++++------
 2 files changed, 21 insertions(+), 6 deletions(-)

diff --git a/gdb/rust-lang.c b/gdb/rust-lang.c
index a635c8b8449..16a8bd18d23 100644
--- a/gdb/rust-lang.c
+++ b/gdb/rust-lang.c
@@ -1322,6 +1322,21 @@ rust_subscript (struct type *expect_type, struct expression *exp,
   return result;
 }
 
+/* A helper function for UNOP_IND.  */
+
+static struct value *
+eval_op_rust_ind (struct type *expect_type, struct expression *exp,
+		  enum noside noside,
+		  struct value *value)
+{
+  gdb_assert (noside == EVAL_NORMAL);
+  struct value *trait_ptr = rust_get_trait_object_pointer (value);
+  if (trait_ptr != NULL)
+    value = trait_ptr;
+
+  return value_ind (value);
+}
+
 /* evaluate_exp implementation for Rust.  */
 
 static struct value *
@@ -1341,12 +1356,7 @@ rust_evaluate_subexp (struct type *expect_type, struct expression *exp,
 	    ++*pos;
 	    struct value *value = evaluate_subexp (expect_type, exp, pos,
 						   noside);
-
-	    struct value *trait_ptr = rust_get_trait_object_pointer (value);
-	    if (trait_ptr != NULL)
-	      value = trait_ptr;
-
-	    result = value_ind (value);
+	    result = eval_op_rust_ind (expect_type, exp, noside, value);
 	  }
       }
       break;
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 047/203] Split out eval_op_rust_complement
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (45 preceding siblings ...)
  2021-01-01 21:44 ` [PATCH 046/203] Split out eval_op_rust_ind Tom Tromey
@ 2021-01-01 21:44 ` Tom Tromey
  2021-01-01 21:44 ` [PATCH 048/203] Split out eval_op_rust_array Tom Tromey
                   ` (156 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:44 UTC (permalink / raw)
  To: gdb-patches

This splits UNOP_COMPLEMENT into a new function for future use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* rust-lang.c (eval_op_rust_complement): New function.
	(rust_evaluate_subexp): Use it.
---
 gdb/ChangeLog   |  5 +++++
 gdb/rust-lang.c | 28 ++++++++++++++++++----------
 2 files changed, 23 insertions(+), 10 deletions(-)

diff --git a/gdb/rust-lang.c b/gdb/rust-lang.c
index 16a8bd18d23..5e293663828 100644
--- a/gdb/rust-lang.c
+++ b/gdb/rust-lang.c
@@ -1337,6 +1337,23 @@ eval_op_rust_ind (struct type *expect_type, struct expression *exp,
   return value_ind (value);
 }
 
+/* A helper function for UNOP_COMPLEMENT.  */
+
+static struct value *
+eval_op_rust_complement (struct type *expect_type, struct expression *exp,
+			 enum noside noside,
+			 struct value *value)
+{
+  if (noside == EVAL_SKIP)
+    {
+      /* Preserving the type is enough.  */
+      return value;
+    }
+  if (value_type (value)->code () == TYPE_CODE_BOOL)
+    return value_from_longest (value_type (value), value_logical_not (value));
+  return value_complement (value);
+}
+
 /* evaluate_exp implementation for Rust.  */
 
 static struct value *
@@ -1367,16 +1384,7 @@ rust_evaluate_subexp (struct type *expect_type, struct expression *exp,
 
 	++*pos;
 	value = evaluate_subexp (nullptr, exp, pos, noside);
-	if (noside == EVAL_SKIP)
-	  {
-	    /* Preserving the type is enough.  */
-	    return value;
-	  }
-	if (value_type (value)->code () == TYPE_CODE_BOOL)
-	  result = value_from_longest (value_type (value),
-				       value_logical_not (value));
-	else
-	  result = value_complement (value);
+	result = eval_op_rust_complement (expect_type, exp, noside, value);
       }
       break;
 
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 048/203] Split out eval_op_rust_array
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (46 preceding siblings ...)
  2021-01-01 21:44 ` [PATCH 047/203] Split out eval_op_rust_complement Tom Tromey
@ 2021-01-01 21:44 ` Tom Tromey
  2021-01-01 21:44 ` [PATCH 049/203] Split out eval_op_rust_struct_anon Tom Tromey
                   ` (155 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:44 UTC (permalink / raw)
  To: gdb-patches

This splits OP_ARRAY into a new function for future use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* rust-lang.c (eval_op_rust_array): New function.
	(rust_evaluate_subexp): Use it.
---
 gdb/ChangeLog   |  5 +++++
 gdb/rust-lang.c | 49 +++++++++++++++++++++++++++++--------------------
 2 files changed, 34 insertions(+), 20 deletions(-)

diff --git a/gdb/rust-lang.c b/gdb/rust-lang.c
index 5e293663828..ba57b6d0572 100644
--- a/gdb/rust-lang.c
+++ b/gdb/rust-lang.c
@@ -1354,6 +1354,34 @@ eval_op_rust_complement (struct type *expect_type, struct expression *exp,
   return value_complement (value);
 }
 
+/* A helper function for OP_ARRAY.  */
+
+static struct value *
+eval_op_rust_array (struct type *expect_type, struct expression *exp,
+		    enum noside noside,
+		    struct value *elt, struct value *ncopies)
+{
+  int copies = value_as_long (ncopies);
+  if (copies < 0)
+    error (_("Array with negative number of elements"));
+
+  if (noside == EVAL_NORMAL)
+    {
+      int i;
+      std::vector<struct value *> eltvec (copies);
+
+      for (i = 0; i < copies; ++i)
+	eltvec[i] = elt;
+      return value_array (0, copies - 1, eltvec.data ());
+    }
+  else
+    {
+      struct type *arraytype
+	= lookup_array_range_type (value_type (elt), 0, copies - 1);
+      return allocate_value (arraytype);
+    }
+}
+
 /* evaluate_exp implementation for Rust.  */
 
 static struct value *
@@ -1472,31 +1500,12 @@ rust_evaluate_subexp (struct type *expect_type, struct expression *exp,
     case OP_RUST_ARRAY:
       {
 	(*pos)++;
-	int copies;
 	struct value *elt;
 	struct value *ncopies;
 
 	elt = rust_evaluate_subexp (NULL, exp, pos, noside);
 	ncopies = rust_evaluate_subexp (NULL, exp, pos, noside);
-	copies = value_as_long (ncopies);
-	if (copies < 0)
-	  error (_("Array with negative number of elements"));
-
-	if (noside == EVAL_NORMAL)
-	  {
-	    int i;
-	    std::vector<struct value *> eltvec (copies);
-
-	    for (i = 0; i < copies; ++i)
-	      eltvec[i] = elt;
-	    result = value_array (0, copies - 1, eltvec.data ());
-	  }
-	else
-	  {
-	    struct type *arraytype
-	      = lookup_array_range_type (value_type (elt), 0, copies - 1);
-	    result = allocate_value (arraytype);
-	  }
+	return eval_op_rust_array (expect_type, exp, noside, elt, ncopies);
       }
       break;
 
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 049/203] Split out eval_op_rust_struct_anon
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (47 preceding siblings ...)
  2021-01-01 21:44 ` [PATCH 048/203] Split out eval_op_rust_array Tom Tromey
@ 2021-01-01 21:44 ` Tom Tromey
  2021-01-01 21:44 ` [PATCH 050/203] Split out eval_op_rust_structop Tom Tromey
                   ` (154 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:44 UTC (permalink / raw)
  To: gdb-patches

This splits STRUCTOP_ANONYMOUS into a new function for future use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* rust-lang.c (eval_op_rust_struct_anon): New function.
	(rust_evaluate_subexp): Use it.
---
 gdb/ChangeLog   |   5 ++
 gdb/rust-lang.c | 130 ++++++++++++++++++++++++++----------------------
 2 files changed, 75 insertions(+), 60 deletions(-)

diff --git a/gdb/rust-lang.c b/gdb/rust-lang.c
index ba57b6d0572..a01e869a201 100644
--- a/gdb/rust-lang.c
+++ b/gdb/rust-lang.c
@@ -1382,6 +1382,73 @@ eval_op_rust_array (struct type *expect_type, struct expression *exp,
     }
 }
 
+/* A helper function for STRUCTOP_ANONYMOUS.  */
+
+static struct value *
+eval_op_rust_struct_anon (struct type *expect_type, struct expression *exp,
+			  enum noside noside,
+			  int field_number, struct value *lhs)
+{
+  struct type *type = value_type (lhs);
+
+  if (type->code () == TYPE_CODE_STRUCT)
+    {
+      struct type *outer_type = NULL;
+
+      if (rust_enum_p (type))
+	{
+	  gdb::array_view<const gdb_byte> view (value_contents (lhs),
+						TYPE_LENGTH (type));
+	  type = resolve_dynamic_type (type, view, value_address (lhs));
+
+	  if (rust_empty_enum_p (type))
+	    error (_("Cannot access field %d of empty enum %s"),
+		   field_number, type->name ());
+
+	  int fieldno = rust_enum_variant (type);
+	  lhs = value_primitive_field (lhs, 0, fieldno, type);
+	  outer_type = type;
+	  type = value_type (lhs);
+	}
+
+      /* Tuples and tuple structs */
+      int nfields = type->num_fields ();
+
+      if (field_number >= nfields || field_number < 0)
+	{
+	  if (outer_type != NULL)
+	    error(_("Cannot access field %d of variant %s::%s, "
+		    "there are only %d fields"),
+		  field_number, outer_type->name (),
+		  rust_last_path_segment (type->name ()),
+		  nfields);
+	  else
+	    error(_("Cannot access field %d of %s, "
+		    "there are only %d fields"),
+		  field_number, type->name (), nfields);
+	}
+
+      /* Tuples are tuple structs too.  */
+      if (!rust_tuple_struct_type_p (type))
+	{
+	  if (outer_type != NULL)
+	    error(_("Variant %s::%s is not a tuple variant"),
+		  outer_type->name (),
+		  rust_last_path_segment (type->name ()));
+	  else
+	    error(_("Attempting to access anonymous field %d "
+		    "of %s, which is not a tuple, tuple struct, or "
+		    "tuple-like variant"),
+		  field_number, type->name ());
+	}
+
+      return value_primitive_field (lhs, 0, field_number, type);
+    }
+  else
+    error(_("Anonymous field access is only allowed on tuples, \
+tuple structs, and tuple-like enum variants"));
+}
+
 /* evaluate_exp implementation for Rust.  */
 
 static struct value *
@@ -1513,72 +1580,15 @@ rust_evaluate_subexp (struct type *expect_type, struct expression *exp,
       {
 	/* Anonymous field access, i.e. foo.1.  */
 	struct value *lhs;
-	int pc, field_number, nfields;
-	struct type *type;
+	int pc, field_number;
 
 	pc = (*pos)++;
 	field_number = longest_to_int (exp->elts[pc + 1].longconst);
 	(*pos) += 2;
 	lhs = evaluate_subexp (nullptr, exp, pos, noside);
 
-	type = value_type (lhs);
-
-	if (type->code () == TYPE_CODE_STRUCT)
-	  {
-	    struct type *outer_type = NULL;
-
-	    if (rust_enum_p (type))
-	      {
-		gdb::array_view<const gdb_byte> view (value_contents (lhs),
-						      TYPE_LENGTH (type));
-		type = resolve_dynamic_type (type, view, value_address (lhs));
-
-		if (rust_empty_enum_p (type))
-		  error (_("Cannot access field %d of empty enum %s"),
-			 field_number, type->name ());
-
-		int fieldno = rust_enum_variant (type);
-		lhs = value_primitive_field (lhs, 0, fieldno, type);
-		outer_type = type;
-		type = value_type (lhs);
-	      }
-
-	    /* Tuples and tuple structs */
-	    nfields = type->num_fields ();
-
-	    if (field_number >= nfields || field_number < 0)
-	      {
-		if (outer_type != NULL)
-		  error(_("Cannot access field %d of variant %s::%s, "
-			  "there are only %d fields"),
-			field_number, outer_type->name (),
-			rust_last_path_segment (type->name ()),
-			nfields);
-		else
-		  error(_("Cannot access field %d of %s, "
-			  "there are only %d fields"),
-			field_number, type->name (), nfields);
-	      }
-
-	    /* Tuples are tuple structs too.  */
-	    if (!rust_tuple_struct_type_p (type))
-	      {
-		if (outer_type != NULL)
-		  error(_("Variant %s::%s is not a tuple variant"),
-			outer_type->name (),
-			rust_last_path_segment (type->name ()));
-		else
-		  error(_("Attempting to access anonymous field %d "
-			  "of %s, which is not a tuple, tuple struct, or "
-			  "tuple-like variant"),
-		      field_number, type->name ());
-	      }
-
-	    result = value_primitive_field (lhs, 0, field_number, type);
-	  }
-	else
-	  error(_("Anonymous field access is only allowed on tuples, \
-tuple structs, and tuple-like enum variants"));
+	return eval_op_rust_struct_anon (expect_type, exp, noside,
+					 field_number, lhs);
       }
       break;
 
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 050/203] Split out eval_op_rust_structop
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (48 preceding siblings ...)
  2021-01-01 21:44 ` [PATCH 049/203] Split out eval_op_rust_struct_anon Tom Tromey
@ 2021-01-01 21:44 ` Tom Tromey
  2021-01-01 21:44 ` [PATCH 051/203] Split helper functions Tom Tromey
                   ` (153 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:44 UTC (permalink / raw)
  To: gdb-patches

This splits STRUCTOP_STRUCT into a new function for future use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* rust-lang.c (eval_op_rust_structop): New function.
	(rust_evaluate_subexp): Use it.
---
 gdb/ChangeLog   |  5 +++
 gdb/rust-lang.c | 90 ++++++++++++++++++++++++++++---------------------
 2 files changed, 56 insertions(+), 39 deletions(-)

diff --git a/gdb/rust-lang.c b/gdb/rust-lang.c
index a01e869a201..a7c62610a1d 100644
--- a/gdb/rust-lang.c
+++ b/gdb/rust-lang.c
@@ -1449,6 +1449,55 @@ eval_op_rust_struct_anon (struct type *expect_type, struct expression *exp,
 tuple structs, and tuple-like enum variants"));
 }
 
+/* A helper function for STRUCTOP_STRUCT.  */
+
+static struct value *
+eval_op_rust_structop (struct type *expect_type, struct expression *exp,
+		       enum noside noside,
+		       struct value *lhs, const char *field_name)
+{
+  struct value *result;
+  struct type *type = value_type (lhs);
+  if (type->code () == TYPE_CODE_STRUCT && rust_enum_p (type))
+    {
+      gdb::array_view<const gdb_byte> view (value_contents (lhs),
+					    TYPE_LENGTH (type));
+      type = resolve_dynamic_type (type, view, value_address (lhs));
+
+      if (rust_empty_enum_p (type))
+	error (_("Cannot access field %s of empty enum %s"),
+	       field_name, type->name ());
+
+      int fieldno = rust_enum_variant (type);
+      lhs = value_primitive_field (lhs, 0, fieldno, type);
+
+      struct type *outer_type = type;
+      type = value_type (lhs);
+      if (rust_tuple_type_p (type) || rust_tuple_struct_type_p (type))
+	error (_("Attempting to access named field %s of tuple "
+		 "variant %s::%s, which has only anonymous fields"),
+	       field_name, outer_type->name (),
+	       rust_last_path_segment (type->name ()));
+
+      try
+	{
+	  result = value_struct_elt (&lhs, NULL, field_name,
+				     NULL, "structure");
+	}
+      catch (const gdb_exception_error &except)
+	{
+	  error (_("Could not find field %s of struct variant %s::%s"),
+		 field_name, outer_type->name (),
+		 rust_last_path_segment (type->name ()));
+	}
+    }
+  else
+    result = value_struct_elt (&lhs, NULL, field_name, NULL, "structure");
+  if (noside == EVAL_AVOID_SIDE_EFFECTS)
+    result = value_zero (value_type (result), VALUE_LVAL (result));
+  return result;
+}
+
 /* evaluate_exp implementation for Rust.  */
 
 static struct value *
@@ -1595,7 +1644,6 @@ rust_evaluate_subexp (struct type *expect_type, struct expression *exp,
     case STRUCTOP_STRUCT:
       {
 	struct value *lhs;
-	struct type *type;
 	int tem, pc;
 
 	pc = (*pos)++;
@@ -1604,44 +1652,8 @@ rust_evaluate_subexp (struct type *expect_type, struct expression *exp,
 	lhs = evaluate_subexp (nullptr, exp, pos, noside);
 
 	const char *field_name = &exp->elts[pc + 2].string;
-	type = value_type (lhs);
-	if (type->code () == TYPE_CODE_STRUCT && rust_enum_p (type))
-	  {
-	    gdb::array_view<const gdb_byte> view (value_contents (lhs),
-						  TYPE_LENGTH (type));
-	    type = resolve_dynamic_type (type, view, value_address (lhs));
-
-	    if (rust_empty_enum_p (type))
-	      error (_("Cannot access field %s of empty enum %s"),
-		     field_name, type->name ());
-
-	    int fieldno = rust_enum_variant (type);
-	    lhs = value_primitive_field (lhs, 0, fieldno, type);
-
-	    struct type *outer_type = type;
-	    type = value_type (lhs);
-	    if (rust_tuple_type_p (type) || rust_tuple_struct_type_p (type))
-		error (_("Attempting to access named field %s of tuple "
-			 "variant %s::%s, which has only anonymous fields"),
-		       field_name, outer_type->name (),
-		       rust_last_path_segment (type->name ()));
-
-	    try
-	      {
-		result = value_struct_elt (&lhs, NULL, field_name,
-					   NULL, "structure");
-	      }
-	    catch (const gdb_exception_error &except)
-	      {
-		error (_("Could not find field %s of struct variant %s::%s"),
-		       field_name, outer_type->name (),
-		       rust_last_path_segment (type->name ()));
-	      }
-	  }
-	else
-	  result = value_struct_elt (&lhs, NULL, field_name, NULL, "structure");
-	if (noside == EVAL_AVOID_SIDE_EFFECTS)
-	  result = value_zero (value_type (result), VALUE_LVAL (result));
+	return eval_op_rust_structop (expect_type, exp, noside, lhs,
+				      field_name);
       }
       break;
 
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 051/203] Split helper functions
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (49 preceding siblings ...)
  2021-01-01 21:44 ` [PATCH 050/203] Split out eval_op_rust_structop Tom Tromey
@ 2021-01-01 21:44 ` Tom Tromey
  2021-01-01 21:44 ` [PATCH 052/203] Split out eval_op_m2_high Tom Tromey
                   ` (152 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:44 UTC (permalink / raw)
  To: gdb-patches

This splits a couple of address-of and sizeof functions, so that the
body can be reused by the (coming) new expression code.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* eval.c (evaluate_subexp_for_address_base): New function.
	(evaluate_subexp_for_address): Use it.
	(evaluate_subexp_for_sizeof_base): New function.
	(evaluate_subexp_for_sizeof): Use it.
---
 gdb/ChangeLog |  7 ++++++
 gdb/eval.c    | 65 +++++++++++++++++++++++++++++++++------------------
 2 files changed, 49 insertions(+), 23 deletions(-)

diff --git a/gdb/eval.c b/gdb/eval.c
index 2907362f709..c27d80ba823 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -3056,6 +3056,29 @@ evaluate_subexp_standard (struct type *expect_type,
   gdb_assert_not_reached ("missed return?");
 }
 \f
+/* Helper for evaluate_subexp_for_address.  */
+
+static value *
+evaluate_subexp_for_address_base (struct expression *exp, enum noside noside,
+				  value *x)
+{
+  if (noside == EVAL_AVOID_SIDE_EFFECTS)
+    {
+      struct type *type = check_typedef (value_type (x));
+
+      if (TYPE_IS_REFERENCE (type))
+	return value_zero (lookup_pointer_type (TYPE_TARGET_TYPE (type)),
+			   not_lval);
+      else if (VALUE_LVAL (x) == lval_memory || value_must_coerce_to_target (x))
+	return value_zero (lookup_pointer_type (value_type (x)),
+			   not_lval);
+      else
+	error (_("Attempt to take address of "
+		 "value not located in memory."));
+    }
+  return value_addr (x);
+}
+
 /* Evaluate a subexpression of EXP, at index *POS,
    and return the address of that subexpression.
    Advance *POS over the subexpression.
@@ -3163,21 +3186,7 @@ evaluate_subexp_for_address (struct expression *exp, int *pos,
     default_case:
       x = evaluate_subexp (nullptr, exp, pos, noside);
     default_case_after_eval:
-      if (noside == EVAL_AVOID_SIDE_EFFECTS)
-	{
-	  struct type *type = check_typedef (value_type (x));
-
-	  if (TYPE_IS_REFERENCE (type))
-	    return value_zero (lookup_pointer_type (TYPE_TARGET_TYPE (type)),
-			       not_lval);
-	  else if (VALUE_LVAL (x) == lval_memory || value_must_coerce_to_target (x))
-	    return value_zero (lookup_pointer_type (value_type (x)),
-			       not_lval);
-	  else
-	    error (_("Attempt to take address of "
-		     "value not located in memory."));
-	}
-      return value_addr (x);
+      return evaluate_subexp_for_address_base (exp, noside, x);
     }
 }
 
@@ -3226,6 +3235,23 @@ evaluate_subexp_with_coercion (struct expression *exp,
     }
 }
 
+/* Helper function for evaluating the size of a type.  */
+
+static value *
+evaluate_subexp_for_sizeof_base (struct expression *exp, struct type *type)
+{
+  /* FIXME: This should be size_t.  */
+  struct type *size_type = builtin_type (exp->gdbarch)->builtin_int;
+  /* $5.3.3/2 of the C++ Standard (n3290 draft) says of sizeof:
+     "When applied to a reference or a reference type, the result is
+     the size of the referenced type."  */
+  type = check_typedef (type);
+  if (exp->language_defn->la_language == language_cplus
+      && (TYPE_IS_REFERENCE (type)))
+    type = check_typedef (TYPE_TARGET_TYPE (type));
+  return value_from_longest (size_type, (LONGEST) TYPE_LENGTH (type));
+}
+
 /* Evaluate a subexpression of EXP, at index *POS,
    and return a value for the size of that subexpression.
    Advance *POS over the subexpression.  If NOSIDE is EVAL_NORMAL
@@ -3349,14 +3375,7 @@ evaluate_subexp_for_sizeof (struct expression *exp, int *pos,
       break;
     }
 
-  /* $5.3.3/2 of the C++ Standard (n3290 draft) says of sizeof:
-     "When applied to a reference or a reference type, the result is
-     the size of the referenced type."  */
-  type = check_typedef (type);
-  if (exp->language_defn->la_language == language_cplus
-      && (TYPE_IS_REFERENCE (type)))
-    type = check_typedef (TYPE_TARGET_TYPE (type));
-  return value_from_longest (size_type, (LONGEST) TYPE_LENGTH (type));
+  return evaluate_subexp_for_sizeof_base (exp, type);
 }
 
 /* Evaluate a subexpression of EXP, at index *POS, and return a value
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 052/203] Split out eval_op_m2_high
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (50 preceding siblings ...)
  2021-01-01 21:44 ` [PATCH 051/203] Split helper functions Tom Tromey
@ 2021-01-01 21:44 ` Tom Tromey
  2021-01-04 12:05   ` Andrew Burgess
  2021-01-01 21:44 ` [PATCH 053/203] Split out eval_op_m2_subscript Tom Tromey
                   ` (151 subsequent siblings)
  203 siblings, 1 reply; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:44 UTC (permalink / raw)
  To: gdb-patches

This splits UNOP_HIGH into a new function for future use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* m2-lang.c (eval_op_m2_high): New function.
	(evaluate_subexp_modula2): Use it.
---
 gdb/ChangeLog |  5 +++++
 gdb/m2-lang.c | 55 ++++++++++++++++++++++++++++++---------------------
 2 files changed, 37 insertions(+), 23 deletions(-)

diff --git a/gdb/m2-lang.c b/gdb/m2-lang.c
index fb49ba470d6..982bc264a3b 100644
--- a/gdb/m2-lang.c
+++ b/gdb/m2-lang.c
@@ -29,6 +29,37 @@
 #include "valprint.h"
 #include "gdbarch.h"
 
+/* A helper function for UNOP_HIGH.  */
+
+static struct value *
+eval_op_m2_high (struct type *expect_type, struct expression *exp,
+		 enum noside noside,
+		 struct value *arg1)
+{
+  if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS)
+    return arg1;
+  else
+    {
+      arg1 = coerce_ref (arg1);
+      struct type *type = check_typedef (value_type (arg1));
+
+      if (m2_is_unbounded_array (type))
+	{
+	  struct value *temp = arg1;
+
+	  type = type->field (1).type ();
+	  /* i18n: Do not translate the "_m2_high" part!  */
+	  arg1 = value_struct_elt (&temp, NULL, "_m2_high", NULL,
+				   _("unbounded structure "
+				     "missing _m2_high field"));
+	  
+	  if (value_type (arg1) != type)
+	    arg1 = value_cast (type, arg1);
+	}
+    }
+  return arg1;
+}
+
 static struct value *
 evaluate_subexp_modula2 (struct type *expect_type, struct expression *exp,
 			 int *pos, enum noside noside)
@@ -43,29 +74,7 @@ evaluate_subexp_modula2 (struct type *expect_type, struct expression *exp,
     case UNOP_HIGH:
       (*pos)++;
       arg1 = evaluate_subexp_with_coercion (exp, pos, noside);
-
-      if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS)
-	return arg1;
-      else
-	{
-	  arg1 = coerce_ref (arg1);
-	  type = check_typedef (value_type (arg1));
-
-	  if (m2_is_unbounded_array (type))
-	    {
-	      struct value *temp = arg1;
-
-	      type = type->field (1).type ();
-	      /* i18n: Do not translate the "_m2_high" part!  */
-	      arg1 = value_struct_elt (&temp, NULL, "_m2_high", NULL,
-				       _("unbounded structure "
-					 "missing _m2_high field"));
-	  
-	      if (value_type (arg1) != type)
-		arg1 = value_cast (type, arg1);
-	    }
-	}
-      return arg1;
+      return eval_op_m2_high (expect_type, exp, noside, arg1);
 
     case BINOP_SUBSCRIPT:
       (*pos)++;
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 053/203] Split out eval_op_m2_subscript
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (51 preceding siblings ...)
  2021-01-01 21:44 ` [PATCH 052/203] Split out eval_op_m2_high Tom Tromey
@ 2021-01-01 21:44 ` Tom Tromey
  2021-01-01 21:44 ` [PATCH 054/203] Split out eval_binop_assign_modify Tom Tromey
                   ` (150 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:44 UTC (permalink / raw)
  To: gdb-patches

This splits BINOP_SUBSCRIPT into a new function for future use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* m2-lang.c (eval_op_m2_subscript): New function.
	(evaluate_subexp_modula2): Use it.
---
 gdb/ChangeLog |  5 +++
 gdb/m2-lang.c | 99 ++++++++++++++++++++++++++-------------------------
 2 files changed, 56 insertions(+), 48 deletions(-)

diff --git a/gdb/m2-lang.c b/gdb/m2-lang.c
index 982bc264a3b..f5e80eee9c6 100644
--- a/gdb/m2-lang.c
+++ b/gdb/m2-lang.c
@@ -60,6 +60,56 @@ eval_op_m2_high (struct type *expect_type, struct expression *exp,
   return arg1;
 }
 
+/* A helper function for BINOP_SUBSCRIPT.  */
+
+static struct value *
+eval_op_m2_subscript (struct type *expect_type, struct expression *exp,
+		      enum noside noside,
+		      struct value *arg1, struct value *arg2)
+{
+  if (noside == EVAL_SKIP)
+    return eval_skip_value (exp);
+  /* If the user attempts to subscript something that is not an
+     array or pointer type (like a plain int variable for example),
+     then report this as an error.  */
+
+  arg1 = coerce_ref (arg1);
+  struct type *type = check_typedef (value_type (arg1));
+
+  if (m2_is_unbounded_array (type))
+    {
+      struct value *temp = arg1;
+      type = type->field (0).type ();
+      if (type == NULL || (type->code () != TYPE_CODE_PTR))
+	error (_("internal error: unbounded "
+		 "array structure is unknown"));
+      /* i18n: Do not translate the "_m2_contents" part!  */
+      arg1 = value_struct_elt (&temp, NULL, "_m2_contents", NULL,
+			       _("unbounded structure "
+				 "missing _m2_contents field"));
+	  
+      if (value_type (arg1) != type)
+	arg1 = value_cast (type, arg1);
+
+      check_typedef (value_type (arg1));
+      return value_ind (value_ptradd (arg1, value_as_long (arg2)));
+    }
+  else
+    if (type->code () != TYPE_CODE_ARRAY)
+      {
+	if (type->name ())
+	  error (_("cannot subscript something of type `%s'"),
+		 type->name ());
+	else
+	  error (_("cannot subscript requested type"));
+      }
+
+  if (noside == EVAL_AVOID_SIDE_EFFECTS)
+    return value_zero (TYPE_TARGET_TYPE (type), VALUE_LVAL (arg1));
+  else
+    return value_subscript (arg1, value_as_long (arg2));
+}
+
 static struct value *
 evaluate_subexp_modula2 (struct type *expect_type, struct expression *exp,
 			 int *pos, enum noside noside)
@@ -67,7 +117,6 @@ evaluate_subexp_modula2 (struct type *expect_type, struct expression *exp,
   enum exp_opcode op = exp->elts[*pos].opcode;
   struct value *arg1;
   struct value *arg2;
-  struct type *type;
 
   switch (op)
     {
@@ -80,57 +129,11 @@ evaluate_subexp_modula2 (struct type *expect_type, struct expression *exp,
       (*pos)++;
       arg1 = evaluate_subexp_with_coercion (exp, pos, noside);
       arg2 = evaluate_subexp_with_coercion (exp, pos, noside);
-      if (noside == EVAL_SKIP)
-	goto nosideret;
-      /* If the user attempts to subscript something that is not an
-	 array or pointer type (like a plain int variable for example),
-	 then report this as an error.  */
-
-      arg1 = coerce_ref (arg1);
-      type = check_typedef (value_type (arg1));
-
-      if (m2_is_unbounded_array (type))
-	{
-	  struct value *temp = arg1;
-	  type = type->field (0).type ();
-	  if (type == NULL || (type->code () != TYPE_CODE_PTR))
-	    {
-	      warning (_("internal error: unbounded "
-			 "array structure is unknown"));
-	      return evaluate_subexp_standard (expect_type, exp, pos, noside);
-	    }
-	  /* i18n: Do not translate the "_m2_contents" part!  */
-	  arg1 = value_struct_elt (&temp, NULL, "_m2_contents", NULL,
-				   _("unbounded structure "
-				     "missing _m2_contents field"));
-	  
-	  if (value_type (arg1) != type)
-	    arg1 = value_cast (type, arg1);
-
-	  check_typedef (value_type (arg1));
-	  return value_ind (value_ptradd (arg1, value_as_long (arg2)));
-	}
-      else
-	if (type->code () != TYPE_CODE_ARRAY)
-	  {
-	    if (type->name ())
-	      error (_("cannot subscript something of type `%s'"),
-		     type->name ());
-	    else
-	      error (_("cannot subscript requested type"));
-	  }
-
-      if (noside == EVAL_AVOID_SIDE_EFFECTS)
-	return value_zero (TYPE_TARGET_TYPE (type), VALUE_LVAL (arg1));
-      else
-	return value_subscript (arg1, value_as_long (arg2));
+      return eval_op_m2_subscript (expect_type, exp, noside, arg1, arg2);
 
     default:
       return evaluate_subexp_standard (expect_type, exp, pos, noside);
     }
-
- nosideret:
-  return value_from_longest (builtin_type (exp->gdbarch)->builtin_int, 1);
 }
 \f
 
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 054/203] Split out eval_binop_assign_modify
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (52 preceding siblings ...)
  2021-01-01 21:44 ` [PATCH 053/203] Split out eval_op_m2_subscript Tom Tromey
@ 2021-01-01 21:44 ` Tom Tromey
  2021-01-01 21:44 ` [PATCH 055/203] Split out eval_op_objc_msgcall Tom Tromey
                   ` (149 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:44 UTC (permalink / raw)
  To: gdb-patches

This splits BINOP_ASSIGN_MODIFY into a new function for future use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* eval.c (eval_binop_assign_modify): New function.
	(evaluate_subexp_standard): Use it.
---
 gdb/ChangeLog |  5 ++++
 gdb/eval.c    | 65 ++++++++++++++++++++++++++++++---------------------
 2 files changed, 43 insertions(+), 27 deletions(-)

diff --git a/gdb/eval.c b/gdb/eval.c
index c27d80ba823..b0d2a217ee5 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -2028,6 +2028,42 @@ eval_op_type (struct type *expect_type, struct expression *exp,
     error (_("Attempt to use a type name as an expression"));
 }
 
+/* A helper function for BINOP_ASSIGN_MODIFY.  */
+
+static struct value *
+eval_binop_assign_modify (struct type *expect_type, struct expression *exp,
+			  enum noside noside, enum exp_opcode op,
+			  struct value *arg1, struct value *arg2)
+{
+  if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS)
+    return arg1;
+  if (binop_user_defined_p (op, arg1, arg2))
+    return value_x_binop (arg1, arg2, BINOP_ASSIGN_MODIFY, op, noside);
+  else if (op == BINOP_ADD && ptrmath_type_p (exp->language_defn,
+					      value_type (arg1))
+	   && is_integral_type (value_type (arg2)))
+    arg2 = value_ptradd (arg1, value_as_long (arg2));
+  else if (op == BINOP_SUB && ptrmath_type_p (exp->language_defn,
+					      value_type (arg1))
+	   && is_integral_type (value_type (arg2)))
+    arg2 = value_ptradd (arg1, - value_as_long (arg2));
+  else
+    {
+      struct value *tmp = arg1;
+
+      /* For shift and integer exponentiation operations,
+	 only promote the first argument.  */
+      if ((op == BINOP_LSH || op == BINOP_RSH || op == BINOP_EXP)
+	  && is_integral_type (value_type (arg2)))
+	unop_promote (exp->language_defn, exp->gdbarch, &tmp);
+      else
+	binop_promote (exp->language_defn, exp->gdbarch, &tmp, &arg2);
+
+      arg2 = value_binop (tmp, arg2, op);
+    }
+  return value_assign (arg1, arg2);
+}
+
 struct value *
 evaluate_subexp_standard (struct type *expect_type,
 			  struct expression *exp, int *pos,
@@ -2681,34 +2717,9 @@ evaluate_subexp_standard (struct type *expect_type,
       (*pos) += 2;
       arg1 = evaluate_subexp (nullptr, exp, pos, noside);
       arg2 = evaluate_subexp (value_type (arg1), exp, pos, noside);
-      if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS)
-	return arg1;
       op = exp->elts[pc + 1].opcode;
-      if (binop_user_defined_p (op, arg1, arg2))
-	return value_x_binop (arg1, arg2, BINOP_ASSIGN_MODIFY, op, noside);
-      else if (op == BINOP_ADD && ptrmath_type_p (exp->language_defn,
-						  value_type (arg1))
-	       && is_integral_type (value_type (arg2)))
-	arg2 = value_ptradd (arg1, value_as_long (arg2));
-      else if (op == BINOP_SUB && ptrmath_type_p (exp->language_defn,
-						  value_type (arg1))
-	       && is_integral_type (value_type (arg2)))
-	arg2 = value_ptradd (arg1, - value_as_long (arg2));
-      else
-	{
-	  struct value *tmp = arg1;
-
-	  /* For shift and integer exponentiation operations,
-	     only promote the first argument.  */
-	  if ((op == BINOP_LSH || op == BINOP_RSH || op == BINOP_EXP)
-	      && is_integral_type (value_type (arg2)))
-	    unop_promote (exp->language_defn, exp->gdbarch, &tmp);
-	  else
-	    binop_promote (exp->language_defn, exp->gdbarch, &tmp, &arg2);
-
-	  arg2 = value_binop (tmp, arg2, op);
-	}
-      return value_assign (arg1, arg2);
+      return eval_binop_assign_modify (expect_type, exp, noside, op,
+				       arg1, arg2);
 
     case BINOP_ADD:
       arg1 = evaluate_subexp_with_coercion (exp, pos, noside);
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 055/203] Split out eval_op_objc_msgcall
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (53 preceding siblings ...)
  2021-01-01 21:44 ` [PATCH 054/203] Split out eval_binop_assign_modify Tom Tromey
@ 2021-01-01 21:44 ` Tom Tromey
  2021-01-01 21:44 ` [PATCH 056/203] Split out eval_opencl_assign Tom Tromey
                   ` (148 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:44 UTC (permalink / raw)
  To: gdb-patches

This splits OP_OBJC_MSGCALL into a new function for future use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* eval.c (eval_op_objc_msgcall): New function.
	(evaluate_subexp_standard): Use it.
---
 gdb/ChangeLog |   5 +
 gdb/eval.c    | 530 ++++++++++++++++++++++++++------------------------
 2 files changed, 286 insertions(+), 249 deletions(-)

diff --git a/gdb/eval.c b/gdb/eval.c
index b0d2a217ee5..8af14fc723b 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -2064,6 +2064,277 @@ eval_binop_assign_modify (struct type *expect_type, struct expression *exp,
   return value_assign (arg1, arg2);
 }
 
+/* Note that ARGS needs 2 empty slots up front and must end with a
+   null pointer.  */
+static struct value *
+eval_op_objc_msgcall (struct type *expect_type, struct expression *exp,
+		      enum noside noside, CORE_ADDR selector,
+		      value *target, gdb::array_view<value *> args)
+{
+  CORE_ADDR responds_selector = 0;
+  CORE_ADDR method_selector = 0;
+
+  int struct_return = 0;
+
+  struct value *msg_send = NULL;
+  struct value *msg_send_stret = NULL;
+  int gnu_runtime = 0;
+
+  struct value *method = NULL;
+  struct value *called_method = NULL;
+
+  struct type *selector_type = NULL;
+  struct type *long_type;
+  struct type *type;
+
+  struct value *ret = NULL;
+  CORE_ADDR addr = 0;
+
+  value *argvec[5];
+
+  long_type = builtin_type (exp->gdbarch)->builtin_long;
+  selector_type = builtin_type (exp->gdbarch)->builtin_data_ptr;
+
+  if (value_as_long (target) == 0)
+    return value_from_longest (long_type, 0);
+
+  if (lookup_minimal_symbol ("objc_msg_lookup", 0, 0).minsym)
+    gnu_runtime = 1;
+
+  /* Find the method dispatch (Apple runtime) or method lookup
+     (GNU runtime) function for Objective-C.  These will be used
+     to lookup the symbol information for the method.  If we
+     can't find any symbol information, then we'll use these to
+     call the method, otherwise we can call the method
+     directly.  The msg_send_stret function is used in the special
+     case of a method that returns a structure (Apple runtime
+     only).  */
+  if (gnu_runtime)
+    {
+      type = selector_type;
+
+      type = lookup_function_type (type);
+      type = lookup_pointer_type (type);
+      type = lookup_function_type (type);
+      type = lookup_pointer_type (type);
+
+      msg_send = find_function_in_inferior ("objc_msg_lookup", NULL);
+      msg_send_stret
+	= find_function_in_inferior ("objc_msg_lookup", NULL);
+
+      msg_send = value_from_pointer (type, value_as_address (msg_send));
+      msg_send_stret = value_from_pointer (type,
+					   value_as_address (msg_send_stret));
+    }
+  else
+    {
+      msg_send = find_function_in_inferior ("objc_msgSend", NULL);
+      /* Special dispatcher for methods returning structs.  */
+      msg_send_stret
+	= find_function_in_inferior ("objc_msgSend_stret", NULL);
+    }
+
+  /* Verify the target object responds to this method.  The
+     standard top-level 'Object' class uses a different name for
+     the verification method than the non-standard, but more
+     often used, 'NSObject' class.  Make sure we check for both.  */
+
+  responds_selector
+    = lookup_child_selector (exp->gdbarch, "respondsToSelector:");
+  if (responds_selector == 0)
+    responds_selector
+      = lookup_child_selector (exp->gdbarch, "respondsTo:");
+
+  if (responds_selector == 0)
+    error (_("no 'respondsTo:' or 'respondsToSelector:' method"));
+
+  method_selector
+    = lookup_child_selector (exp->gdbarch, "methodForSelector:");
+  if (method_selector == 0)
+    method_selector
+      = lookup_child_selector (exp->gdbarch, "methodFor:");
+
+  if (method_selector == 0)
+    error (_("no 'methodFor:' or 'methodForSelector:' method"));
+
+  /* Call the verification method, to make sure that the target
+     class implements the desired method.  */
+
+  argvec[0] = msg_send;
+  argvec[1] = target;
+  argvec[2] = value_from_longest (long_type, responds_selector);
+  argvec[3] = value_from_longest (long_type, selector);
+  argvec[4] = 0;
+
+  ret = call_function_by_hand (argvec[0], NULL, {argvec + 1, 3});
+  if (gnu_runtime)
+    {
+      /* Function objc_msg_lookup returns a pointer.  */
+      argvec[0] = ret;
+      ret = call_function_by_hand (argvec[0], NULL, {argvec + 1, 3});
+    }
+  if (value_as_long (ret) == 0)
+    error (_("Target does not respond to this message selector."));
+
+  /* Call "methodForSelector:" method, to get the address of a
+     function method that implements this selector for this
+     class.  If we can find a symbol at that address, then we
+     know the return type, parameter types etc.  (that's a good
+     thing).  */
+
+  argvec[0] = msg_send;
+  argvec[1] = target;
+  argvec[2] = value_from_longest (long_type, method_selector);
+  argvec[3] = value_from_longest (long_type, selector);
+  argvec[4] = 0;
+
+  ret = call_function_by_hand (argvec[0], NULL, {argvec + 1, 3});
+  if (gnu_runtime)
+    {
+      argvec[0] = ret;
+      ret = call_function_by_hand (argvec[0], NULL, {argvec + 1, 3});
+    }
+
+  /* ret should now be the selector.  */
+
+  addr = value_as_long (ret);
+  if (addr)
+    {
+      struct symbol *sym = NULL;
+
+      /* The address might point to a function descriptor;
+	 resolve it to the actual code address instead.  */
+      addr = gdbarch_convert_from_func_ptr_addr (exp->gdbarch, addr,
+						 current_top_target ());
+
+      /* Is it a high_level symbol?  */
+      sym = find_pc_function (addr);
+      if (sym != NULL)
+	method = value_of_variable (sym, 0);
+    }
+
+  /* If we found a method with symbol information, check to see
+     if it returns a struct.  Otherwise assume it doesn't.  */
+
+  if (method)
+    {
+      CORE_ADDR funaddr;
+      struct type *val_type;
+
+      funaddr = find_function_addr (method, &val_type);
+
+      block_for_pc (funaddr);
+
+      val_type = check_typedef (val_type);
+
+      if ((val_type == NULL)
+	  || (val_type->code () == TYPE_CODE_ERROR))
+	{
+	  if (expect_type != NULL)
+	    val_type = expect_type;
+	}
+
+      struct_return = using_struct_return (exp->gdbarch, method,
+					   val_type);
+    }
+  else if (expect_type != NULL)
+    {
+      struct_return = using_struct_return (exp->gdbarch, NULL,
+					   check_typedef (expect_type));
+    }
+
+  /* Found a function symbol.  Now we will substitute its
+     value in place of the message dispatcher (obj_msgSend),
+     so that we call the method directly instead of thru
+     the dispatcher.  The main reason for doing this is that
+     we can now evaluate the return value and parameter values
+     according to their known data types, in case we need to
+     do things like promotion, dereferencing, special handling
+     of structs and doubles, etc.
+
+     We want to use the type signature of 'method', but still
+     jump to objc_msgSend() or objc_msgSend_stret() to better
+     mimic the behavior of the runtime.  */
+
+  if (method)
+    {
+      if (value_type (method)->code () != TYPE_CODE_FUNC)
+	error (_("method address has symbol information "
+		 "with non-function type; skipping"));
+
+      /* Create a function pointer of the appropriate type, and
+	 replace its value with the value of msg_send or
+	 msg_send_stret.  We must use a pointer here, as
+	 msg_send and msg_send_stret are of pointer type, and
+	 the representation may be different on systems that use
+	 function descriptors.  */
+      if (struct_return)
+	called_method
+	  = value_from_pointer (lookup_pointer_type (value_type (method)),
+				value_as_address (msg_send_stret));
+      else
+	called_method
+	  = value_from_pointer (lookup_pointer_type (value_type (method)),
+				value_as_address (msg_send));
+    }
+  else
+    {
+      if (struct_return)
+	called_method = msg_send_stret;
+      else
+	called_method = msg_send;
+    }
+
+  if (noside == EVAL_SKIP)
+    return eval_skip_value (exp);
+
+  if (noside == EVAL_AVOID_SIDE_EFFECTS)
+    {
+      /* If the return type doesn't look like a function type,
+	 call an error.  This can happen if somebody tries to
+	 turn a variable into a function call.  This is here
+	 because people often want to call, eg, strcmp, which
+	 gdb doesn't know is a function.  If gdb isn't asked for
+	 it's opinion (ie. through "whatis"), it won't offer
+	 it.  */
+
+      struct type *callee_type = value_type (called_method);
+
+      if (callee_type && callee_type->code () == TYPE_CODE_PTR)
+	callee_type = TYPE_TARGET_TYPE (callee_type);
+      callee_type = TYPE_TARGET_TYPE (callee_type);
+
+      if (callee_type)
+	{
+	  if ((callee_type->code () == TYPE_CODE_ERROR) && expect_type)
+	    return allocate_value (expect_type);
+	  else
+	    return allocate_value (callee_type);
+	}
+      else
+	error (_("Expression of type other than "
+		 "\"method returning ...\" used as a method"));
+    }
+
+  /* Now depending on whether we found a symbol for the method,
+     we will either call the runtime dispatcher or the method
+     directly.  */
+
+  args[0] = target;
+  args[1] = value_from_longest (long_type, selector);
+
+  if (gnu_runtime && (method != NULL))
+    {
+      /* Function objc_msg_lookup returns a pointer.  */
+      struct type *tem_type = value_type (called_method);
+      tem_type = lookup_pointer_type (lookup_function_type (tem_type));
+      deprecated_set_value_type (called_method, tem_type);
+      called_method = call_function_by_hand (called_method, NULL, args);
+    }
+
+  return call_function_by_hand (called_method, NULL, args);
+}
+
 struct value *
 evaluate_subexp_standard (struct type *expect_type,
 			  struct expression *exp, int *pos,
@@ -2351,36 +2622,20 @@ evaluate_subexp_standard (struct type *expect_type,
 
     case OP_OBJC_MSGCALL:
       {				/* Objective C message (method) call.  */
-
-	CORE_ADDR responds_selector = 0;
-	CORE_ADDR method_selector = 0;
-
 	CORE_ADDR selector = 0;
 
-	int struct_return = 0;
 	enum noside sub_no_side = EVAL_NORMAL;
 
-	struct value *msg_send = NULL;
-	struct value *msg_send_stret = NULL;
-	int gnu_runtime = 0;
-
 	struct value *target = NULL;
-	struct value *method = NULL;
-	struct value *called_method = NULL; 
 
 	struct type *selector_type = NULL;
-	struct type *long_type;
-
-	struct value *ret = NULL;
-	CORE_ADDR addr = 0;
 
 	selector = exp->elts[pc + 1].longconst;
 	nargs = exp->elts[pc + 2].longconst;
-	argvec = XALLOCAVEC (struct value *, nargs + 5);
+	argvec = XALLOCAVEC (struct value *, nargs + 3);
 
 	(*pos) += 3;
 
-	long_type = builtin_type (exp->gdbarch)->builtin_long;
 	selector_type = builtin_type (exp->gdbarch)->builtin_data_ptr;
 
 	if (noside == EVAL_AVOID_SIDE_EFFECTS)
@@ -2391,249 +2646,26 @@ evaluate_subexp_standard (struct type *expect_type,
 	target = evaluate_subexp (selector_type, exp, pos, sub_no_side);
 
 	if (value_as_long (target) == 0)
- 	  return value_from_longest (long_type, 0);
-	
-	if (lookup_minimal_symbol ("objc_msg_lookup", 0, 0).minsym)
-	  gnu_runtime = 1;
-	
-	/* Find the method dispatch (Apple runtime) or method lookup
-	   (GNU runtime) function for Objective-C.  These will be used
-	   to lookup the symbol information for the method.  If we
-	   can't find any symbol information, then we'll use these to
-	   call the method, otherwise we can call the method
-	   directly.  The msg_send_stret function is used in the special
-	   case of a method that returns a structure (Apple runtime 
-	   only).  */
-	if (gnu_runtime)
-	  {
-	    type = selector_type;
-
-	    type = lookup_function_type (type);
-	    type = lookup_pointer_type (type);
-	    type = lookup_function_type (type);
-	    type = lookup_pointer_type (type);
-
-	    msg_send = find_function_in_inferior ("objc_msg_lookup", NULL);
-	    msg_send_stret
-	      = find_function_in_inferior ("objc_msg_lookup", NULL);
-
-	    msg_send = value_from_pointer (type, value_as_address (msg_send));
-	    msg_send_stret = value_from_pointer (type, 
-					value_as_address (msg_send_stret));
-	  }
+	  sub_no_side = EVAL_SKIP;
 	else
-	  {
-	    msg_send = find_function_in_inferior ("objc_msgSend", NULL);
-	    /* Special dispatcher for methods returning structs.  */
-	    msg_send_stret
-	      = find_function_in_inferior ("objc_msgSend_stret", NULL);
-	  }
-
-	/* Verify the target object responds to this method.  The
-	   standard top-level 'Object' class uses a different name for
-	   the verification method than the non-standard, but more
-	   often used, 'NSObject' class.  Make sure we check for both.  */
-
-	responds_selector
-	  = lookup_child_selector (exp->gdbarch, "respondsToSelector:");
-	if (responds_selector == 0)
-	  responds_selector
-	    = lookup_child_selector (exp->gdbarch, "respondsTo:");
-	
-	if (responds_selector == 0)
-	  error (_("no 'respondsTo:' or 'respondsToSelector:' method"));
-	
-	method_selector
-	  = lookup_child_selector (exp->gdbarch, "methodForSelector:");
-	if (method_selector == 0)
-	  method_selector
-	    = lookup_child_selector (exp->gdbarch, "methodFor:");
-	
-	if (method_selector == 0)
-	  error (_("no 'methodFor:' or 'methodForSelector:' method"));
-
-	/* Call the verification method, to make sure that the target
-	 class implements the desired method.  */
-
-	argvec[0] = msg_send;
-	argvec[1] = target;
-	argvec[2] = value_from_longest (long_type, responds_selector);
-	argvec[3] = value_from_longest (long_type, selector);
-	argvec[4] = 0;
-
-	ret = call_function_by_hand (argvec[0], NULL, {argvec + 1, 3});
-	if (gnu_runtime)
-	  {
-	    /* Function objc_msg_lookup returns a pointer.  */
-	    argvec[0] = ret;
-	    ret = call_function_by_hand (argvec[0], NULL, {argvec + 1, 3});
-	  }
-	if (value_as_long (ret) == 0)
-	  error (_("Target does not respond to this message selector."));
-
-	/* Call "methodForSelector:" method, to get the address of a
-	   function method that implements this selector for this
-	   class.  If we can find a symbol at that address, then we
-	   know the return type, parameter types etc.  (that's a good
-	   thing).  */
-
-	argvec[0] = msg_send;
-	argvec[1] = target;
-	argvec[2] = value_from_longest (long_type, method_selector);
-	argvec[3] = value_from_longest (long_type, selector);
-	argvec[4] = 0;
-
-	ret = call_function_by_hand (argvec[0], NULL, {argvec + 1, 3});
-	if (gnu_runtime)
-	  {
-	    argvec[0] = ret;
-	    ret = call_function_by_hand (argvec[0], NULL, {argvec + 1, 3});
-	  }
-
-	/* ret should now be the selector.  */
-
-	addr = value_as_long (ret);
-	if (addr)
-	  {
-	    struct symbol *sym = NULL;
-
-	    /* The address might point to a function descriptor;
-	       resolve it to the actual code address instead.  */
-	    addr = gdbarch_convert_from_func_ptr_addr (exp->gdbarch, addr,
-						       current_top_target ());
-
-	    /* Is it a high_level symbol?  */
-	    sym = find_pc_function (addr);
-	    if (sym != NULL) 
-	      method = value_of_variable (sym, 0);
-	  }
-
-	/* If we found a method with symbol information, check to see
-	   if it returns a struct.  Otherwise assume it doesn't.  */
-
-	if (method)
-	  {
-	    CORE_ADDR funaddr;
-	    struct type *val_type;
-
-	    funaddr = find_function_addr (method, &val_type);
-
-	    block_for_pc (funaddr);
-
-	    val_type = check_typedef (val_type);
-
-	    if ((val_type == NULL)
-		|| (val_type->code () == TYPE_CODE_ERROR))
-	      {
-		if (expect_type != NULL)
-		  val_type = expect_type;
-	      }
-
-	    struct_return = using_struct_return (exp->gdbarch, method,
-						 val_type);
-	  }
-	else if (expect_type != NULL)
-	  {
-	    struct_return = using_struct_return (exp->gdbarch, NULL,
-						 check_typedef (expect_type));
-	  }
-
-	/* Found a function symbol.  Now we will substitute its
-	   value in place of the message dispatcher (obj_msgSend),
-	   so that we call the method directly instead of thru
-	   the dispatcher.  The main reason for doing this is that
-	   we can now evaluate the return value and parameter values
-	   according to their known data types, in case we need to
-	   do things like promotion, dereferencing, special handling
-	   of structs and doubles, etc.
-	  
-	   We want to use the type signature of 'method', but still
-	   jump to objc_msgSend() or objc_msgSend_stret() to better
-	   mimic the behavior of the runtime.  */
-	
-	if (method)
-	  {
-	    if (value_type (method)->code () != TYPE_CODE_FUNC)
-	      error (_("method address has symbol information "
-		       "with non-function type; skipping"));
-
-	    /* Create a function pointer of the appropriate type, and
-	       replace its value with the value of msg_send or
-	       msg_send_stret.  We must use a pointer here, as
-	       msg_send and msg_send_stret are of pointer type, and
-	       the representation may be different on systems that use
-	       function descriptors.  */
-	    if (struct_return)
-	      called_method
-		= value_from_pointer (lookup_pointer_type (value_type (method)),
-				      value_as_address (msg_send_stret));
-	    else
-	      called_method
-		= value_from_pointer (lookup_pointer_type (value_type (method)),
-				      value_as_address (msg_send));
-	  }
-	else
-	  {
-	    if (struct_return)
-	      called_method = msg_send_stret;
-	    else
-	      called_method = msg_send;
-	  }
-
-	if (noside == EVAL_SKIP)
-	  return eval_skip_value (exp);
-
-	if (noside == EVAL_AVOID_SIDE_EFFECTS)
-	  {
-	    /* If the return type doesn't look like a function type,
-	       call an error.  This can happen if somebody tries to
-	       turn a variable into a function call.  This is here
-	       because people often want to call, eg, strcmp, which
-	       gdb doesn't know is a function.  If gdb isn't asked for
-	       it's opinion (ie. through "whatis"), it won't offer
-	       it.  */
-
-	    struct type *callee_type = value_type (called_method);
-
-	    if (callee_type && callee_type->code () == TYPE_CODE_PTR)
-	      callee_type = TYPE_TARGET_TYPE (callee_type);
-	    callee_type = TYPE_TARGET_TYPE (callee_type);
-
-	    if (callee_type)
-	    {
-	      if ((callee_type->code () == TYPE_CODE_ERROR) && expect_type)
-		return allocate_value (expect_type);
-	      else
-		return allocate_value (callee_type);
-	    }
-	    else
-	      error (_("Expression of type other than "
-		       "\"method returning ...\" used as a method"));
-	  }
+	  sub_no_side = noside;
 
 	/* Now depending on whether we found a symbol for the method,
 	   we will either call the runtime dispatcher or the method
 	   directly.  */
 
-	argvec[0] = called_method;
-	argvec[1] = target;
-	argvec[2] = value_from_longest (long_type, selector);
+	argvec[0] = nullptr;
+	argvec[1] = nullptr;
 	/* User-supplied arguments.  */
 	for (tem = 0; tem < nargs; tem++)
-	  argvec[tem + 3] = evaluate_subexp_with_coercion (exp, pos, noside);
+	  argvec[tem + 2] = evaluate_subexp_with_coercion (exp, pos,
+							   sub_no_side);
 	argvec[tem + 3] = 0;
 
-	auto call_args = gdb::make_array_view (argvec + 1, nargs + 2);
-
-	if (gnu_runtime && (method != NULL))
-	  {
-	    /* Function objc_msg_lookup returns a pointer.  */
-	    deprecated_set_value_type (argvec[0],
-				       lookup_pointer_type (lookup_function_type (value_type (argvec[0]))));
-	    argvec[0] = call_function_by_hand (argvec[0], NULL, call_args);
-	  }
+	auto call_args = gdb::make_array_view (argvec, nargs + 3);
 
-	return call_function_by_hand (argvec[0], NULL, call_args);
+	return eval_op_objc_msgcall (expect_type, exp, noside, selector,
+				     target, call_args);
       }
       break;
 
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 056/203] Split out eval_opencl_assign
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (54 preceding siblings ...)
  2021-01-01 21:44 ` [PATCH 055/203] Split out eval_op_objc_msgcall Tom Tromey
@ 2021-01-01 21:44 ` Tom Tromey
  2021-01-01 21:44 ` [PATCH 057/203] Split out eval_ternop_in_range Tom Tromey
                   ` (147 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:44 UTC (permalink / raw)
  To: gdb-patches

This splits BINOP_ASSIGN into a new function for future use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* opencl-lang.c (eval_opencl_assign): New function.
	(evaluate_subexp_opencl): Use it.
---
 gdb/ChangeLog     |  5 +++++
 gdb/opencl-lang.c | 27 +++++++++++++++++++--------
 2 files changed, 24 insertions(+), 8 deletions(-)

diff --git a/gdb/opencl-lang.c b/gdb/opencl-lang.c
index 183d67897f0..b45e47eb506 100644
--- a/gdb/opencl-lang.c
+++ b/gdb/opencl-lang.c
@@ -670,6 +670,24 @@ opencl_relop (struct expression *exp, struct value *arg1, struct value *arg2,
   return val;
 }
 
+/* A helper function for BINOP_ASSIGN.  */
+
+static struct value *
+eval_opencl_assign (struct type *expect_type, struct expression *exp,
+		    enum noside noside,
+		    struct value *arg1, struct value *arg2)
+{
+  if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS)
+    return arg1;
+
+  struct type *type1 = value_type (arg1);
+  if (deprecated_value_modifiable (arg1)
+      && VALUE_LVAL (arg1) != lval_internalvar)
+    arg2 = opencl_value_cast (type1, arg2);
+
+  return value_assign (arg1, arg2);
+}
+
 /* Expression evaluator for the OpenCL.  Most operations are delegated to
    evaluate_subexp_standard; see that function for a description of the
    arguments.  */
@@ -693,14 +711,7 @@ evaluate_subexp_opencl (struct type *expect_type, struct expression *exp,
       type1 = value_type (arg1);
       arg2 = evaluate_subexp (type1, exp, pos, noside);
 
-      if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS)
-	return arg1;
-
-      if (deprecated_value_modifiable (arg1)
-	  && VALUE_LVAL (arg1) != lval_internalvar)
-	arg2 = opencl_value_cast (type1, arg2);
-
-      return value_assign (arg1, arg2);
+      return eval_opencl_assign (expect_type, exp, noside, arg1, arg2);
 
     case UNOP_CAST:
       type1 = exp->elts[*pos + 1].type;
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 057/203] Split out eval_ternop_in_range
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (55 preceding siblings ...)
  2021-01-01 21:44 ` [PATCH 056/203] Split out eval_opencl_assign Tom Tromey
@ 2021-01-01 21:44 ` Tom Tromey
  2021-01-01 21:44 ` [PATCH 058/203] Split out ada_unop_neg Tom Tromey
                   ` (146 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:44 UTC (permalink / raw)
  To: gdb-patches

This splits TERNOP_IN_RANGE into a new function for future use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* ada-lang.c (eval_ternop_in_range): New function.
	(ada_evaluate_subexp): Use it.
---
 gdb/ChangeLog  |  5 +++++
 gdb/ada-lang.c | 34 ++++++++++++++++++++++------------
 2 files changed, 27 insertions(+), 12 deletions(-)

diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 8b2086109b9..4cf6335ceb5 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -10085,6 +10085,27 @@ ada_evaluate_subexp_for_cast (expression *exp, int *pos,
   return ada_value_cast (to_type, val);
 }
 
+/* A helper function for TERNOP_IN_RANGE.  */
+
+static value *
+eval_ternop_in_range (struct type *expect_type, struct expression *exp,
+		      enum noside noside,
+		      value *arg1, value *arg2, value *arg3)
+{
+  if (noside == EVAL_SKIP)
+    return eval_skip_value (exp);
+
+  binop_promote (exp->language_defn, exp->gdbarch, &arg1, &arg2);
+  binop_promote (exp->language_defn, exp->gdbarch, &arg1, &arg3);
+  struct type *type = language_bool_type (exp->language_defn, exp->gdbarch);
+  return
+    value_from_longest (type,
+			(value_less (arg1, arg3)
+			 || value_equal (arg1, arg3))
+			&& (value_less (arg2, arg1)
+			    || value_equal (arg2, arg1)));
+}
+
 /* Implement the evaluate_exp routine in the exp_descriptor structure
    for the Ada language.  */
 
@@ -10703,18 +10724,7 @@ ada_evaluate_subexp (struct type *expect_type, struct expression *exp,
       arg2 = evaluate_subexp (nullptr, exp, pos, noside);
       arg3 = evaluate_subexp (nullptr, exp, pos, noside);
 
-      if (noside == EVAL_SKIP)
-	goto nosideret;
-
-      binop_promote (exp->language_defn, exp->gdbarch, &arg1, &arg2);
-      binop_promote (exp->language_defn, exp->gdbarch, &arg1, &arg3);
-      type = language_bool_type (exp->language_defn, exp->gdbarch);
-      return
-	value_from_longest (type,
-			    (value_less (arg1, arg3)
-			     || value_equal (arg1, arg3))
-			    && (value_less (arg2, arg1)
-				|| value_equal (arg2, arg1)));
+      return eval_ternop_in_range (expect_type, exp, noside, arg1, arg2, arg3);
 
     case OP_ATR_FIRST:
     case OP_ATR_LAST:
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 058/203] Split out ada_unop_neg
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (56 preceding siblings ...)
  2021-01-01 21:44 ` [PATCH 057/203] Split out eval_ternop_in_range Tom Tromey
@ 2021-01-01 21:44 ` Tom Tromey
  2021-01-01 21:44 ` [PATCH 059/203] Split out ada_unop_in_range Tom Tromey
                   ` (145 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:44 UTC (permalink / raw)
  To: gdb-patches

This splits UNOP_NEG into a new function for future use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* ada-lang.c (ada_unop_neg): New function.
	(ada_evaluate_subexp): Use it.
---
 gdb/ChangeLog  |  5 +++++
 gdb/ada-lang.c | 29 ++++++++++++++++++++---------
 2 files changed, 25 insertions(+), 9 deletions(-)

diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 4cf6335ceb5..b071c3d3f65 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -10106,6 +10106,25 @@ eval_ternop_in_range (struct type *expect_type, struct expression *exp,
 			    || value_equal (arg2, arg1)));
 }
 
+/* A helper function for UNOP_NEG.  */
+
+static value *
+ada_unop_neg (struct type *expect_type,
+	      struct expression *exp,
+	      enum noside noside, enum exp_opcode op,
+	      struct value *arg1)
+{
+  if (noside == EVAL_SKIP)
+    return eval_skip_value (exp);
+  else if (ada_is_gnat_encoded_fixed_point_type (value_type (arg1)))
+    return value_cast (value_type (arg1), value_neg (arg1));
+  else
+    {
+      unop_promote (exp->language_defn, exp->gdbarch, &arg1);
+      return value_neg (arg1);
+    }
+}
+
 /* Implement the evaluate_exp routine in the exp_descriptor structure
    for the Ada language.  */
 
@@ -10300,15 +10319,7 @@ ada_evaluate_subexp (struct type *expect_type, struct expression *exp,
 
     case UNOP_NEG:
       arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      if (noside == EVAL_SKIP)
-	goto nosideret;
-      else if (ada_is_gnat_encoded_fixed_point_type (value_type (arg1)))
-	return value_cast (value_type (arg1), value_neg (arg1));
-      else
-	{
-	  unop_promote (exp->language_defn, exp->gdbarch, &arg1);
-	  return value_neg (arg1);
-	}
+      return ada_unop_neg (expect_type, exp, noside, op, arg1);
 
     case BINOP_LOGICAL_AND:
     case BINOP_LOGICAL_OR:
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 059/203] Split out ada_unop_in_range
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (57 preceding siblings ...)
  2021-01-01 21:44 ` [PATCH 058/203] Split out ada_unop_neg Tom Tromey
@ 2021-01-01 21:44 ` Tom Tromey
  2021-01-01 21:45 ` [PATCH 060/203] Split out ada_atr_tag Tom Tromey
                   ` (144 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:44 UTC (permalink / raw)
  To: gdb-patches

This splits UNOP_IN_RANGE into a new function for future use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* ada-lang.c (ada_unop_in_range): New function.
	(ada_evaluate_subexp): Use it.
---
 gdb/ChangeLog  |  5 ++++
 gdb/ada-lang.c | 65 +++++++++++++++++++++++++++++---------------------
 2 files changed, 43 insertions(+), 27 deletions(-)

diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index b071c3d3f65..22ea6346088 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -10125,6 +10125,43 @@ ada_unop_neg (struct type *expect_type,
     }
 }
 
+/* A helper function for UNOP_IN_RANGE.  */
+
+static value *
+ada_unop_in_range (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside, enum exp_opcode op,
+		   struct value *arg1, struct type *type)
+{
+  if (noside == EVAL_SKIP)
+    return eval_skip_value (exp);
+
+  struct value *arg2, *arg3;
+  switch (type->code ())
+    {
+    default:
+      lim_warning (_("Membership test incompletely implemented; "
+		     "always returns true"));
+      type = language_bool_type (exp->language_defn, exp->gdbarch);
+      return value_from_longest (type, (LONGEST) 1);
+
+    case TYPE_CODE_RANGE:
+      arg2 = value_from_longest (type,
+				 type->bounds ()->low.const_val ());
+      arg3 = value_from_longest (type,
+				 type->bounds ()->high.const_val ());
+      binop_promote (exp->language_defn, exp->gdbarch, &arg1, &arg2);
+      binop_promote (exp->language_defn, exp->gdbarch, &arg1, &arg3);
+      type = language_bool_type (exp->language_defn, exp->gdbarch);
+      return
+	value_from_longest (type,
+			    (value_less (arg1, arg3)
+			     || value_equal (arg1, arg3))
+			    && (value_less (arg2, arg1)
+				|| value_equal (arg2, arg1)));
+    }
+}
+
 /* Implement the evaluate_exp routine in the exp_descriptor structure
    for the Ada language.  */
 
@@ -10669,33 +10706,7 @@ ada_evaluate_subexp (struct type *expect_type, struct expression *exp,
       (*pos) += 2;
       arg1 = evaluate_subexp (nullptr, exp, pos, noside);
       type = check_typedef (exp->elts[pc + 1].type);
-
-      if (noside == EVAL_SKIP)
-	goto nosideret;
-
-      switch (type->code ())
-	{
-	default:
-	  lim_warning (_("Membership test incompletely implemented; "
-			 "always returns true"));
-	  type = language_bool_type (exp->language_defn, exp->gdbarch);
-	  return value_from_longest (type, (LONGEST) 1);
-
-	case TYPE_CODE_RANGE:
-	  arg2 = value_from_longest (type,
-				     type->bounds ()->low.const_val ());
-	  arg3 = value_from_longest (type,
-				     type->bounds ()->high.const_val ());
-	  binop_promote (exp->language_defn, exp->gdbarch, &arg1, &arg2);
-	  binop_promote (exp->language_defn, exp->gdbarch, &arg1, &arg3);
-	  type = language_bool_type (exp->language_defn, exp->gdbarch);
-	  return
-	    value_from_longest (type,
-				(value_less (arg1, arg3)
-				 || value_equal (arg1, arg3))
-				&& (value_less (arg2, arg1)
-				    || value_equal (arg2, arg1)));
-	}
+      return ada_unop_in_range (expect_type, exp, noside, op, arg1, type);
 
     case BINOP_IN_BOUNDS:
       (*pos) += 2;
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 060/203] Split out ada_atr_tag
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (58 preceding siblings ...)
  2021-01-01 21:44 ` [PATCH 059/203] Split out ada_unop_in_range Tom Tromey
@ 2021-01-01 21:45 ` Tom Tromey
  2021-01-01 21:45 ` [PATCH 061/203] Split out ada_atr_size Tom Tromey
                   ` (143 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:45 UTC (permalink / raw)
  To: gdb-patches

This splits OP_ATR_TAG into a new function for future use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* ada-lang.c (ada_atr_tag): New function.
	(ada_evaluate_subexp): Use it.
---
 gdb/ChangeLog  |  5 +++++
 gdb/ada-lang.c | 20 +++++++++++++++-----
 2 files changed, 20 insertions(+), 5 deletions(-)

diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 22ea6346088..88d1198acf6 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -10162,6 +10162,20 @@ ada_unop_in_range (struct type *expect_type,
     }
 }
 
+/* A helper function for OP_ATR_TAG.  */
+
+static value *
+ada_atr_tag (struct type *expect_type,
+	     struct expression *exp,
+	     enum noside noside, enum exp_opcode op,
+	     struct value *arg1)
+{
+  if (noside == EVAL_AVOID_SIDE_EFFECTS)
+    return value_zero (ada_tag_type (arg1), not_lval);
+
+  return ada_value_tag (arg1);
+}
+
 /* Implement the evaluate_exp routine in the exp_descriptor structure
    for the Ada language.  */
 
@@ -10896,11 +10910,7 @@ ada_evaluate_subexp (struct type *expect_type, struct expression *exp,
       arg1 = evaluate_subexp (nullptr, exp, pos, noside);
       if (noside == EVAL_SKIP)
 	goto nosideret;
-
-      if (noside == EVAL_AVOID_SIDE_EFFECTS)
-	return value_zero (ada_tag_type (arg1), not_lval);
-
-      return ada_value_tag (arg1);
+      return ada_atr_tag (expect_type, exp, noside, op, arg1);
 
     case OP_ATR_MIN:
     case OP_ATR_MAX:
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 061/203] Split out ada_atr_size
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (59 preceding siblings ...)
  2021-01-01 21:45 ` [PATCH 060/203] Split out ada_atr_tag Tom Tromey
@ 2021-01-01 21:45 ` Tom Tromey
  2021-01-01 21:45 ` [PATCH 062/203] Split out ada_abs Tom Tromey
                   ` (142 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:45 UTC (permalink / raw)
  To: gdb-patches

This splits OP_ATR_SIZE into a new function for future use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* ada-lang.c (ada_atr_size): New function.
	(ada_evaluate_subexp): Use it.
---
 gdb/ChangeLog  |  5 +++++
 gdb/ada-lang.c | 41 ++++++++++++++++++++++++++---------------
 2 files changed, 31 insertions(+), 15 deletions(-)

diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 88d1198acf6..203648ade02 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -10176,6 +10176,31 @@ ada_atr_tag (struct type *expect_type,
   return ada_value_tag (arg1);
 }
 
+/* A helper function for OP_ATR_SIZE.  */
+
+static value *
+ada_atr_size (struct type *expect_type,
+	      struct expression *exp,
+	      enum noside noside, enum exp_opcode op,
+	      struct value *arg1)
+{
+  struct type *type = value_type (arg1);
+
+  /* If the argument is a reference, then dereference its type, since
+     the user is really asking for the size of the actual object,
+     not the size of the pointer.  */
+  if (type->code () == TYPE_CODE_REF)
+    type = TYPE_TARGET_TYPE (type);
+
+  if (noside == EVAL_SKIP)
+    return eval_skip_value (exp);
+  else if (noside == EVAL_AVOID_SIDE_EFFECTS)
+    return value_zero (builtin_type (exp->gdbarch)->builtin_int, not_lval);
+  else
+    return value_from_longest (builtin_type (exp->gdbarch)->builtin_int,
+			       TARGET_CHAR_BIT * TYPE_LENGTH (type));
+}
+
 /* Implement the evaluate_exp routine in the exp_descriptor structure
    for the Ada language.  */
 
@@ -10957,21 +10982,7 @@ ada_evaluate_subexp (struct type *expect_type, struct expression *exp,
 
     case OP_ATR_SIZE:
       arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      type = value_type (arg1);
-
-      /* If the argument is a reference, then dereference its type, since
-	 the user is really asking for the size of the actual object,
-	 not the size of the pointer.  */
-      if (type->code () == TYPE_CODE_REF)
-	type = TYPE_TARGET_TYPE (type);
-
-      if (noside == EVAL_SKIP)
-	goto nosideret;
-      else if (noside == EVAL_AVOID_SIDE_EFFECTS)
-	return value_zero (builtin_type (exp->gdbarch)->builtin_int, not_lval);
-      else
-	return value_from_longest (builtin_type (exp->gdbarch)->builtin_int,
-				   TARGET_CHAR_BIT * TYPE_LENGTH (type));
+      return ada_atr_size (expect_type, exp, noside, op, arg1);
 
     case OP_ATR_VAL:
       evaluate_subexp (nullptr, exp, pos, EVAL_SKIP);
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 062/203] Split out ada_abs
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (60 preceding siblings ...)
  2021-01-01 21:45 ` [PATCH 061/203] Split out ada_atr_size Tom Tromey
@ 2021-01-01 21:45 ` Tom Tromey
  2021-01-01 21:45 ` [PATCH 063/203] Split out ada_mult_binop Tom Tromey
                   ` (141 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:45 UTC (permalink / raw)
  To: gdb-patches

This splits UNOP_ABS into a new function for future use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* ada-lang.c (ada_abs): New function.
	(ada_evaluate_subexp): Use it.
---
 gdb/ChangeLog  |  5 +++++
 gdb/ada-lang.c | 21 ++++++++++++++++-----
 2 files changed, 21 insertions(+), 5 deletions(-)

diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 203648ade02..a1468b81e05 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -10201,6 +10201,21 @@ ada_atr_size (struct type *expect_type,
 			       TARGET_CHAR_BIT * TYPE_LENGTH (type));
 }
 
+/* A helper function for UNOP_ABS.  */
+
+static value *
+ada_abs (struct type *expect_type,
+	 struct expression *exp,
+	 enum noside noside, enum exp_opcode op,
+	 struct value *arg1)
+{
+  unop_promote (exp->language_defn, exp->gdbarch, &arg1);
+  if (value_less (arg1, value_zero (value_type (arg1), not_lval)))
+    return value_neg (arg1);
+  else
+    return arg1;
+}
+
 /* Implement the evaluate_exp routine in the exp_descriptor structure
    for the Ada language.  */
 
@@ -11025,11 +11040,7 @@ ada_evaluate_subexp (struct type *expect_type, struct expression *exp,
       arg1 = evaluate_subexp (nullptr, exp, pos, noside);
       if (noside == EVAL_SKIP)
 	goto nosideret;
-      unop_promote (exp->language_defn, exp->gdbarch, &arg1);
-      if (value_less (arg1, value_zero (value_type (arg1), not_lval)))
-	return value_neg (arg1);
-      else
-	return arg1;
+      return ada_abs (expect_type, exp, noside, op, arg1);
 
     case UNOP_IND:
       preeval_pos = *pos;
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 063/203] Split out ada_mult_binop
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (61 preceding siblings ...)
  2021-01-01 21:45 ` [PATCH 062/203] Split out ada_abs Tom Tromey
@ 2021-01-01 21:45 ` Tom Tromey
  2021-01-01 21:45 ` [PATCH 064/203] Split out ada_equal_binop Tom Tromey
                   ` (140 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:45 UTC (permalink / raw)
  To: gdb-patches

This splits BINOP_MUL into a new function for future use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* ada-lang.c (ada_mult_binop): New function.
	(ada_evaluate_subexp): Use it.
---
 gdb/ChangeLog  |  5 +++++
 gdb/ada-lang.c | 42 +++++++++++++++++++++++++++---------------
 2 files changed, 32 insertions(+), 15 deletions(-)

diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index a1468b81e05..f096157881a 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -10216,6 +10216,31 @@ ada_abs (struct type *expect_type,
     return arg1;
 }
 
+/* A helper function for BINOP_MUL.  */
+
+static value *
+ada_mult_binop (struct type *expect_type,
+		struct expression *exp,
+		enum noside noside, enum exp_opcode op,
+		struct value *arg1, struct value *arg2)
+{
+  if (noside == EVAL_AVOID_SIDE_EFFECTS)
+    {
+      binop_promote (exp->language_defn, exp->gdbarch, &arg1, &arg2);
+      return value_zero (value_type (arg1), not_lval);
+    }
+  else
+    {
+      struct type *type = builtin_type (exp->gdbarch)->builtin_double;
+      if (ada_is_gnat_encoded_fixed_point_type (value_type (arg1)))
+	arg1 = cast_from_gnat_encoded_fixed_point_type (type, arg1);
+      if (ada_is_gnat_encoded_fixed_point_type (value_type (arg2)))
+	arg2 = cast_from_gnat_encoded_fixed_point_type (type, arg2);
+      binop_promote (exp->language_defn, exp->gdbarch, &arg1, &arg2);
+      return ada_value_binop (arg1, arg2, op);
+    }
+}
+
 /* Implement the evaluate_exp routine in the exp_descriptor structure
    for the Ada language.  */
 
@@ -10374,21 +10399,8 @@ ada_evaluate_subexp (struct type *expect_type, struct expression *exp,
       arg2 = evaluate_subexp (nullptr, exp, pos, noside);
       if (noside == EVAL_SKIP)
 	goto nosideret;
-      else if (noside == EVAL_AVOID_SIDE_EFFECTS)
-	{
-	  binop_promote (exp->language_defn, exp->gdbarch, &arg1, &arg2);
-	  return value_zero (value_type (arg1), not_lval);
-	}
-      else
-	{
-	  type = builtin_type (exp->gdbarch)->builtin_double;
-	  if (ada_is_gnat_encoded_fixed_point_type (value_type (arg1)))
-	    arg1 = cast_from_gnat_encoded_fixed_point_type (type, arg1);
-	  if (ada_is_gnat_encoded_fixed_point_type (value_type (arg2)))
-	    arg2 = cast_from_gnat_encoded_fixed_point_type (type, arg2);
-	  binop_promote (exp->language_defn, exp->gdbarch, &arg1, &arg2);
-	  return ada_value_binop (arg1, arg2, op);
-	}
+      return ada_mult_binop (expect_type, exp, noside, op,
+			     arg1, arg2);
 
     case BINOP_EQUAL:
     case BINOP_NOTEQUAL:
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 064/203] Split out ada_equal_binop
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (62 preceding siblings ...)
  2021-01-01 21:45 ` [PATCH 063/203] Split out ada_mult_binop Tom Tromey
@ 2021-01-01 21:45 ` Tom Tromey
  2021-01-01 21:45 ` [PATCH 065/203] Split out ada_ternop_slice Tom Tromey
                   ` (139 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:45 UTC (permalink / raw)
  To: gdb-patches

This splits BINOP_EQUAL and BINOP_NOTEQUAL into a new function for
future use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* ada-lang.c (ada_equal_binop): New function.
	(ada_evaluate_subexp): Use it.
---
 gdb/ChangeLog  |  5 +++++
 gdb/ada-lang.c | 34 +++++++++++++++++++++++-----------
 2 files changed, 28 insertions(+), 11 deletions(-)

diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index f096157881a..47ff8b0e0f5 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -10241,6 +10241,28 @@ ada_mult_binop (struct type *expect_type,
     }
 }
 
+/* A helper function for BINOP_EQUAL and BINOP_NOTEQUAL.  */
+
+static value *
+ada_equal_binop (struct type *expect_type,
+		 struct expression *exp,
+		 enum noside noside, enum exp_opcode op,
+		 struct value *arg1, struct value *arg2)
+{
+  int tem;
+  if (noside == EVAL_AVOID_SIDE_EFFECTS)
+    tem = 0;
+  else
+    {
+      binop_promote (exp->language_defn, exp->gdbarch, &arg1, &arg2);
+      tem = ada_value_equal (arg1, arg2);
+    }
+  if (op == BINOP_NOTEQUAL)
+    tem = !tem;
+  struct type *type = language_bool_type (exp->language_defn, exp->gdbarch);
+  return value_from_longest (type, (LONGEST) tem);
+}
+
 /* Implement the evaluate_exp routine in the exp_descriptor structure
    for the Ada language.  */
 
@@ -10408,17 +10430,7 @@ ada_evaluate_subexp (struct type *expect_type, struct expression *exp,
       arg2 = evaluate_subexp (value_type (arg1), exp, pos, noside);
       if (noside == EVAL_SKIP)
 	goto nosideret;
-      if (noside == EVAL_AVOID_SIDE_EFFECTS)
-	tem = 0;
-      else
-	{
-	  binop_promote (exp->language_defn, exp->gdbarch, &arg1, &arg2);
-	  tem = ada_value_equal (arg1, arg2);
-	}
-      if (op == BINOP_NOTEQUAL)
-	tem = !tem;
-      type = language_bool_type (exp->language_defn, exp->gdbarch);
-      return value_from_longest (type, (LONGEST) tem);
+      return ada_equal_binop (expect_type, exp, noside, op, arg1, arg2);
 
     case UNOP_NEG:
       arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 065/203] Split out ada_ternop_slice
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (63 preceding siblings ...)
  2021-01-01 21:45 ` [PATCH 064/203] Split out ada_equal_binop Tom Tromey
@ 2021-01-01 21:45 ` Tom Tromey
  2021-01-01 21:45 ` [PATCH 066/203] Split out ada_binop_in_bounds Tom Tromey
                   ` (138 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:45 UTC (permalink / raw)
  To: gdb-patches

This splits TERNOP_SLICE into a new function for future use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* ada-lang.c (ada_ternop_slice): New function.
	(ada_evaluate_subexp): Use it.
---
 gdb/ChangeLog  |   5 ++
 gdb/ada-lang.c | 153 +++++++++++++++++++++++++++----------------------
 2 files changed, 88 insertions(+), 70 deletions(-)

diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 47ff8b0e0f5..dd909d2f41e 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -10263,6 +10263,87 @@ ada_equal_binop (struct type *expect_type,
   return value_from_longest (type, (LONGEST) tem);
 }
 
+/* A helper function for TERNOP_SLICE.  */
+
+static value *
+ada_ternop_slice (struct expression *exp,
+		  enum noside noside,
+		  struct value *array, struct value *low_bound_val,
+		  struct value *high_bound_val)
+{
+  LONGEST low_bound;
+  LONGEST high_bound;
+
+  low_bound_val = coerce_ref (low_bound_val);
+  high_bound_val = coerce_ref (high_bound_val);
+  low_bound = value_as_long (low_bound_val);
+  high_bound = value_as_long (high_bound_val);
+
+  /* If this is a reference to an aligner type, then remove all
+     the aligners.  */
+  if (value_type (array)->code () == TYPE_CODE_REF
+      && ada_is_aligner_type (TYPE_TARGET_TYPE (value_type (array))))
+    TYPE_TARGET_TYPE (value_type (array)) =
+      ada_aligned_type (TYPE_TARGET_TYPE (value_type (array)));
+
+  if (ada_is_any_packed_array_type (value_type (array)))
+    error (_("cannot slice a packed array"));
+
+  /* If this is a reference to an array or an array lvalue,
+     convert to a pointer.  */
+  if (value_type (array)->code () == TYPE_CODE_REF
+      || (value_type (array)->code () == TYPE_CODE_ARRAY
+	  && VALUE_LVAL (array) == lval_memory))
+    array = value_addr (array);
+
+  if (noside == EVAL_AVOID_SIDE_EFFECTS
+      && ada_is_array_descriptor_type (ada_check_typedef
+				       (value_type (array))))
+    return empty_array (ada_type_of_array (array, 0), low_bound,
+			high_bound);
+
+  array = ada_coerce_to_simple_array_ptr (array);
+
+  /* If we have more than one level of pointer indirection,
+     dereference the value until we get only one level.  */
+  while (value_type (array)->code () == TYPE_CODE_PTR
+	 && (TYPE_TARGET_TYPE (value_type (array))->code ()
+	     == TYPE_CODE_PTR))
+    array = value_ind (array);
+
+  /* Make sure we really do have an array type before going further,
+     to avoid a SEGV when trying to get the index type or the target
+     type later down the road if the debug info generated by
+     the compiler is incorrect or incomplete.  */
+  if (!ada_is_simple_array_type (value_type (array)))
+    error (_("cannot take slice of non-array"));
+
+  if (ada_check_typedef (value_type (array))->code ()
+      == TYPE_CODE_PTR)
+    {
+      struct type *type0 = ada_check_typedef (value_type (array));
+
+      if (high_bound < low_bound || noside == EVAL_AVOID_SIDE_EFFECTS)
+	return empty_array (TYPE_TARGET_TYPE (type0), low_bound, high_bound);
+      else
+	{
+	  struct type *arr_type0 =
+	    to_fixed_array_type (TYPE_TARGET_TYPE (type0), NULL, 1);
+
+	  return ada_value_slice_from_ptr (array, arr_type0,
+					   longest_to_int (low_bound),
+					   longest_to_int (high_bound));
+	}
+    }
+  else if (noside == EVAL_AVOID_SIDE_EFFECTS)
+    return array;
+  else if (high_bound < low_bound)
+    return empty_array (value_type (array), low_bound, high_bound);
+  else
+    return ada_value_slice (array, longest_to_int (low_bound),
+			    longest_to_int (high_bound));
+}
+
 /* Implement the evaluate_exp routine in the exp_descriptor structure
    for the Ada language.  */
 
@@ -10704,80 +10785,12 @@ ada_evaluate_subexp (struct type *expect_type, struct expression *exp,
 	  = evaluate_subexp (nullptr, exp, pos, noside);
 	struct value *high_bound_val
 	  = evaluate_subexp (nullptr, exp, pos, noside);
-	LONGEST low_bound;
-	LONGEST high_bound;
-
-	low_bound_val = coerce_ref (low_bound_val);
-	high_bound_val = coerce_ref (high_bound_val);
-	low_bound = value_as_long (low_bound_val);
-	high_bound = value_as_long (high_bound_val);
 
 	if (noside == EVAL_SKIP)
 	  goto nosideret;
 
-	/* If this is a reference to an aligner type, then remove all
-	   the aligners.  */
-	if (value_type (array)->code () == TYPE_CODE_REF
-	    && ada_is_aligner_type (TYPE_TARGET_TYPE (value_type (array))))
-	  TYPE_TARGET_TYPE (value_type (array)) =
-	    ada_aligned_type (TYPE_TARGET_TYPE (value_type (array)));
-
-	if (ada_is_any_packed_array_type (value_type (array)))
-	  error (_("cannot slice a packed array"));
-
-	/* If this is a reference to an array or an array lvalue,
-	   convert to a pointer.  */
-	if (value_type (array)->code () == TYPE_CODE_REF
-	    || (value_type (array)->code () == TYPE_CODE_ARRAY
-		&& VALUE_LVAL (array) == lval_memory))
-	  array = value_addr (array);
-
-	if (noside == EVAL_AVOID_SIDE_EFFECTS
-	    && ada_is_array_descriptor_type (ada_check_typedef
-					     (value_type (array))))
-	  return empty_array (ada_type_of_array (array, 0), low_bound,
-			      high_bound);
-
-	array = ada_coerce_to_simple_array_ptr (array);
-
-	/* If we have more than one level of pointer indirection,
-	   dereference the value until we get only one level.  */
-	while (value_type (array)->code () == TYPE_CODE_PTR
-	       && (TYPE_TARGET_TYPE (value_type (array))->code ()
-		     == TYPE_CODE_PTR))
-	  array = value_ind (array);
-
-	/* Make sure we really do have an array type before going further,
-	   to avoid a SEGV when trying to get the index type or the target
-	   type later down the road if the debug info generated by
-	   the compiler is incorrect or incomplete.  */
-	if (!ada_is_simple_array_type (value_type (array)))
-	  error (_("cannot take slice of non-array"));
-
-	if (ada_check_typedef (value_type (array))->code ()
-	    == TYPE_CODE_PTR)
-	  {
-	    struct type *type0 = ada_check_typedef (value_type (array));
-
-	    if (high_bound < low_bound || noside == EVAL_AVOID_SIDE_EFFECTS)
-	      return empty_array (TYPE_TARGET_TYPE (type0), low_bound, high_bound);
-	    else
-	      {
-		struct type *arr_type0 =
-		  to_fixed_array_type (TYPE_TARGET_TYPE (type0), NULL, 1);
-
-		return ada_value_slice_from_ptr (array, arr_type0,
-						 longest_to_int (low_bound),
-						 longest_to_int (high_bound));
-	      }
-	  }
-	else if (noside == EVAL_AVOID_SIDE_EFFECTS)
-	  return array;
-	else if (high_bound < low_bound)
-	  return empty_array (value_type (array), low_bound, high_bound);
-	else
-	  return ada_value_slice (array, longest_to_int (low_bound),
-				  longest_to_int (high_bound));
+	return ada_ternop_slice (exp, noside, array, low_bound_val,
+				 high_bound_val);
       }
 
     case UNOP_IN_RANGE:
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 066/203] Split out ada_binop_in_bounds
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (64 preceding siblings ...)
  2021-01-01 21:45 ` [PATCH 065/203] Split out ada_ternop_slice Tom Tromey
@ 2021-01-01 21:45 ` Tom Tromey
  2021-01-01 21:45 ` [PATCH 067/203] Split out ada_unop_atr Tom Tromey
                   ` (137 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:45 UTC (permalink / raw)
  To: gdb-patches

This splits BINOP_IN_BOUNDS into a new function for future use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* ada-lang.c (ada_binop_in_bounds): New function.
	(ada_evaluate_subexp): Use it.
---
 gdb/ChangeLog  |  5 +++++
 gdb/ada-lang.c | 53 +++++++++++++++++++++++++++++---------------------
 2 files changed, 36 insertions(+), 22 deletions(-)

diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index dd909d2f41e..bc5fc618161 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -10344,6 +10344,36 @@ ada_ternop_slice (struct expression *exp,
 			    longest_to_int (high_bound));
 }
 
+/* A helper function for BINOP_IN_BOUNDS.  */
+
+static value *
+ada_binop_in_bounds (struct expression *exp, enum noside noside,
+		     struct value *arg1, struct value *arg2, int n)
+{
+  if (noside == EVAL_AVOID_SIDE_EFFECTS)
+    {
+      struct type *type = language_bool_type (exp->language_defn,
+					      exp->gdbarch);
+      return value_zero (type, not_lval);
+    }
+
+  struct type *type = ada_index_type (value_type (arg2), n, "range");
+  if (!type)
+    type = value_type (arg1);
+
+  value *arg3 = value_from_longest (type, ada_array_bound (arg2, n, 1));
+  arg2 = value_from_longest (type, ada_array_bound (arg2, n, 0));
+
+  binop_promote (exp->language_defn, exp->gdbarch, &arg1, &arg2);
+  binop_promote (exp->language_defn, exp->gdbarch, &arg1, &arg3);
+  type = language_bool_type (exp->language_defn, exp->gdbarch);
+  return value_from_longest (type,
+			     (value_less (arg1, arg3)
+			      || value_equal (arg1, arg3))
+			     && (value_less (arg2, arg1)
+				 || value_equal (arg2, arg1)));
+}
+
 /* Implement the evaluate_exp routine in the exp_descriptor structure
    for the Ada language.  */
 
@@ -10807,30 +10837,9 @@ ada_evaluate_subexp (struct type *expect_type, struct expression *exp,
       if (noside == EVAL_SKIP)
 	goto nosideret;
 
-      if (noside == EVAL_AVOID_SIDE_EFFECTS)
-	{
-	  type = language_bool_type (exp->language_defn, exp->gdbarch);
-	  return value_zero (type, not_lval);
-	}
-
       tem = longest_to_int (exp->elts[pc + 1].longconst);
 
-      type = ada_index_type (value_type (arg2), tem, "range");
-      if (!type)
-	type = value_type (arg1);
-
-      arg3 = value_from_longest (type, ada_array_bound (arg2, tem, 1));
-      arg2 = value_from_longest (type, ada_array_bound (arg2, tem, 0));
-
-      binop_promote (exp->language_defn, exp->gdbarch, &arg1, &arg2);
-      binop_promote (exp->language_defn, exp->gdbarch, &arg1, &arg3);
-      type = language_bool_type (exp->language_defn, exp->gdbarch);
-      return
-	value_from_longest (type,
-			    (value_less (arg1, arg3)
-			     || value_equal (arg1, arg3))
-			    && (value_less (arg2, arg1)
-				|| value_equal (arg2, arg1)));
+      return ada_binop_in_bounds (exp, noside, arg1, arg2, tem);
 
     case TERNOP_IN_RANGE:
       arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 067/203] Split out ada_unop_atr
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (65 preceding siblings ...)
  2021-01-01 21:45 ` [PATCH 066/203] Split out ada_binop_in_bounds Tom Tromey
@ 2021-01-01 21:45 ` Tom Tromey
  2021-01-01 21:45 ` [PATCH 068/203] Split out ada_binop_minmax Tom Tromey
                   ` (136 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:45 UTC (permalink / raw)
  To: gdb-patches

This splits some Ada attribute operations into a new function for
future use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* ada-lang.c (ada_unop_atr): New function.
	(ada_evaluate_subexp): Use it.
---
 gdb/ChangeLog  |   5 +
 gdb/ada-lang.c | 244 ++++++++++++++++++++++++++-----------------------
 2 files changed, 133 insertions(+), 116 deletions(-)

diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index bc5fc618161..06347b0a28c 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -10374,6 +10374,133 @@ ada_binop_in_bounds (struct expression *exp, enum noside noside,
 				 || value_equal (arg2, arg1)));
 }
 
+/* A helper function for some attribute operations.  */
+
+static value *
+ada_unop_atr (struct expression *exp, enum noside noside, enum exp_opcode op,
+	      struct value *arg1, struct type *type_arg, int tem)
+{
+  if (noside == EVAL_AVOID_SIDE_EFFECTS)
+    {
+      if (type_arg == NULL)
+	type_arg = value_type (arg1);
+
+      if (ada_is_constrained_packed_array_type (type_arg))
+	type_arg = decode_constrained_packed_array_type (type_arg);
+
+      if (!discrete_type_p (type_arg))
+	{
+	  switch (op)
+	    {
+	    default:          /* Should never happen.  */
+	      error (_("unexpected attribute encountered"));
+	    case OP_ATR_FIRST:
+	    case OP_ATR_LAST:
+	      type_arg = ada_index_type (type_arg, tem,
+					 ada_attribute_name (op));
+	      break;
+	    case OP_ATR_LENGTH:
+	      type_arg = builtin_type (exp->gdbarch)->builtin_int;
+	      break;
+	    }
+	}
+
+      return value_zero (type_arg, not_lval);
+    }
+  else if (type_arg == NULL)
+    {
+      arg1 = ada_coerce_ref (arg1);
+
+      if (ada_is_constrained_packed_array_type (value_type (arg1)))
+	arg1 = ada_coerce_to_simple_array (arg1);
+
+      struct type *type;
+      if (op == OP_ATR_LENGTH)
+	type = builtin_type (exp->gdbarch)->builtin_int;
+      else
+	{
+	  type = ada_index_type (value_type (arg1), tem,
+				 ada_attribute_name (op));
+	  if (type == NULL)
+	    type = builtin_type (exp->gdbarch)->builtin_int;
+	}
+
+      switch (op)
+	{
+	default:          /* Should never happen.  */
+	  error (_("unexpected attribute encountered"));
+	case OP_ATR_FIRST:
+	  return value_from_longest
+	    (type, ada_array_bound (arg1, tem, 0));
+	case OP_ATR_LAST:
+	  return value_from_longest
+	    (type, ada_array_bound (arg1, tem, 1));
+	case OP_ATR_LENGTH:
+	  return value_from_longest
+	    (type, ada_array_length (arg1, tem));
+	}
+    }
+  else if (discrete_type_p (type_arg))
+    {
+      struct type *range_type;
+      const char *name = ada_type_name (type_arg);
+
+      range_type = NULL;
+      if (name != NULL && type_arg->code () != TYPE_CODE_ENUM)
+	range_type = to_fixed_range_type (type_arg, NULL);
+      if (range_type == NULL)
+	range_type = type_arg;
+      switch (op)
+	{
+	default:
+	  error (_("unexpected attribute encountered"));
+	case OP_ATR_FIRST:
+	  return value_from_longest 
+	    (range_type, ada_discrete_type_low_bound (range_type));
+	case OP_ATR_LAST:
+	  return value_from_longest
+	    (range_type, ada_discrete_type_high_bound (range_type));
+	case OP_ATR_LENGTH:
+	  error (_("the 'length attribute applies only to array types"));
+	}
+    }
+  else if (type_arg->code () == TYPE_CODE_FLT)
+    error (_("unimplemented type attribute"));
+  else
+    {
+      LONGEST low, high;
+
+      if (ada_is_constrained_packed_array_type (type_arg))
+	type_arg = decode_constrained_packed_array_type (type_arg);
+
+      struct type *type;
+      if (op == OP_ATR_LENGTH)
+	type = builtin_type (exp->gdbarch)->builtin_int;
+      else
+	{
+	  type = ada_index_type (type_arg, tem, ada_attribute_name (op));
+	  if (type == NULL)
+	    type = builtin_type (exp->gdbarch)->builtin_int;
+	}
+
+      switch (op)
+	{
+	default:
+	  error (_("unexpected attribute encountered"));
+	case OP_ATR_FIRST:
+	  low = ada_array_bound_from_type (type_arg, tem, 0);
+	  return value_from_longest (type, low);
+	case OP_ATR_LAST:
+	  high = ada_array_bound_from_type (type_arg, tem, 1);
+	  return value_from_longest (type, high);
+	case OP_ATR_LENGTH:
+	  low = ada_array_bound_from_type (type_arg, tem, 0);
+	  high = ada_array_bound_from_type (type_arg, tem, 1);
+	  return value_from_longest (type, high - low + 1);
+	}
+    }
+}
+
 /* Implement the evaluate_exp routine in the exp_descriptor structure
    for the Ada language.  */
 
@@ -10873,123 +11000,8 @@ ada_evaluate_subexp (struct type *expect_type, struct expression *exp,
 
 	if (noside == EVAL_SKIP)
 	  goto nosideret;
-	else if (noside == EVAL_AVOID_SIDE_EFFECTS)
-	  {
-	    if (type_arg == NULL)
-	      type_arg = value_type (arg1);
-
-	    if (ada_is_constrained_packed_array_type (type_arg))
-	      type_arg = decode_constrained_packed_array_type (type_arg);
 
-	    if (!discrete_type_p (type_arg))
-	      {
-		switch (op)
-		  {
-		  default:          /* Should never happen.  */
-		    error (_("unexpected attribute encountered"));
-		  case OP_ATR_FIRST:
-		  case OP_ATR_LAST:
-		    type_arg = ada_index_type (type_arg, tem,
-					       ada_attribute_name (op));
-		    break;
-		  case OP_ATR_LENGTH:
-		    type_arg = builtin_type (exp->gdbarch)->builtin_int;
-		    break;
-		  }
-	      }
-
-	    return value_zero (type_arg, not_lval);
-	  }
-	else if (type_arg == NULL)
-	  {
-	    arg1 = ada_coerce_ref (arg1);
-
-	    if (ada_is_constrained_packed_array_type (value_type (arg1)))
-	      arg1 = ada_coerce_to_simple_array (arg1);
-
-	    if (op == OP_ATR_LENGTH)
-	      type = builtin_type (exp->gdbarch)->builtin_int;
-	    else
-	      {
-		type = ada_index_type (value_type (arg1), tem,
-				       ada_attribute_name (op));
-		if (type == NULL)
-		  type = builtin_type (exp->gdbarch)->builtin_int;
-	      }
-
-	    switch (op)
-	      {
-	      default:          /* Should never happen.  */
-		error (_("unexpected attribute encountered"));
-	      case OP_ATR_FIRST:
-		return value_from_longest
-			(type, ada_array_bound (arg1, tem, 0));
-	      case OP_ATR_LAST:
-		return value_from_longest
-			(type, ada_array_bound (arg1, tem, 1));
-	      case OP_ATR_LENGTH:
-		return value_from_longest
-			(type, ada_array_length (arg1, tem));
-	      }
-	  }
-	else if (discrete_type_p (type_arg))
-	  {
-	    struct type *range_type;
-	    const char *name = ada_type_name (type_arg);
-
-	    range_type = NULL;
-	    if (name != NULL && type_arg->code () != TYPE_CODE_ENUM)
-	      range_type = to_fixed_range_type (type_arg, NULL);
-	    if (range_type == NULL)
-	      range_type = type_arg;
-	    switch (op)
-	      {
-	      default:
-		error (_("unexpected attribute encountered"));
-	      case OP_ATR_FIRST:
-		return value_from_longest 
-		  (range_type, ada_discrete_type_low_bound (range_type));
-	      case OP_ATR_LAST:
-		return value_from_longest
-		  (range_type, ada_discrete_type_high_bound (range_type));
-	      case OP_ATR_LENGTH:
-		error (_("the 'length attribute applies only to array types"));
-	      }
-	  }
-	else if (type_arg->code () == TYPE_CODE_FLT)
-	  error (_("unimplemented type attribute"));
-	else
-	  {
-	    LONGEST low, high;
-
-	    if (ada_is_constrained_packed_array_type (type_arg))
-	      type_arg = decode_constrained_packed_array_type (type_arg);
-
-	    if (op == OP_ATR_LENGTH)
-	      type = builtin_type (exp->gdbarch)->builtin_int;
-	    else
-	      {
-		type = ada_index_type (type_arg, tem, ada_attribute_name (op));
-		if (type == NULL)
-		  type = builtin_type (exp->gdbarch)->builtin_int;
-	      }
-
-	    switch (op)
-	      {
-	      default:
-		error (_("unexpected attribute encountered"));
-	      case OP_ATR_FIRST:
-		low = ada_array_bound_from_type (type_arg, tem, 0);
-		return value_from_longest (type, low);
-	      case OP_ATR_LAST:
-		high = ada_array_bound_from_type (type_arg, tem, 1);
-		return value_from_longest (type, high);
-	      case OP_ATR_LENGTH:
-		low = ada_array_bound_from_type (type_arg, tem, 0);
-		high = ada_array_bound_from_type (type_arg, tem, 1);
-		return value_from_longest (type, high - low + 1);
-	      }
-	  }
+	return ada_unop_atr (exp, noside, op, arg1, type_arg, tem);
       }
 
     case OP_ATR_TAG:
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 068/203] Split out ada_binop_minmax
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (66 preceding siblings ...)
  2021-01-01 21:45 ` [PATCH 067/203] Split out ada_unop_atr Tom Tromey
@ 2021-01-01 21:45 ` Tom Tromey
  2021-01-01 21:45 ` [PATCH 069/203] Change value_val_atr to ada_val_atr Tom Tromey
                   ` (135 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:45 UTC (permalink / raw)
  To: gdb-patches

This splits OP_ATR_MIN and OP_ATR_MAX into a new function for future
use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* ada-lang.c (ada_binop_minmax): New function.
	(ada_evaluate_subexp): Use it.
---
 gdb/ChangeLog  |  5 +++++
 gdb/ada-lang.c | 27 +++++++++++++++++++--------
 2 files changed, 24 insertions(+), 8 deletions(-)

diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 06347b0a28c..a3164ccd709 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -10501,6 +10501,24 @@ ada_unop_atr (struct expression *exp, enum noside noside, enum exp_opcode op,
     }
 }
 
+/* A helper function for OP_ATR_MIN and OP_ATR_MAX.  */
+
+static struct value *
+ada_binop_minmax (struct type *expect_type,
+		  struct expression *exp,
+		  enum noside noside, enum exp_opcode op,
+		  struct value *arg1, struct value *arg2)
+{
+  if (noside == EVAL_AVOID_SIDE_EFFECTS)
+    return value_zero (value_type (arg1), not_lval);
+  else
+    {
+      binop_promote (exp->language_defn, exp->gdbarch, &arg1, &arg2);
+      return value_binop (arg1, arg2,
+			  op == OP_ATR_MIN ? BINOP_MIN : BINOP_MAX);
+    }
+}
+
 /* Implement the evaluate_exp routine in the exp_descriptor structure
    for the Ada language.  */
 
@@ -11017,14 +11035,7 @@ ada_evaluate_subexp (struct type *expect_type, struct expression *exp,
       arg2 = evaluate_subexp (nullptr, exp, pos, noside);
       if (noside == EVAL_SKIP)
 	goto nosideret;
-      else if (noside == EVAL_AVOID_SIDE_EFFECTS)
-	return value_zero (value_type (arg1), not_lval);
-      else
-	{
-	  binop_promote (exp->language_defn, exp->gdbarch, &arg1, &arg2);
-	  return value_binop (arg1, arg2,
-			      op == OP_ATR_MIN ? BINOP_MIN : BINOP_MAX);
-	}
+      return ada_binop_minmax (expect_type, exp, noside, op, arg1, arg2);
 
     case OP_ATR_MODULUS:
       {
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 069/203] Change value_val_atr to ada_val_atr
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (67 preceding siblings ...)
  2021-01-01 21:45 ` [PATCH 068/203] Split out ada_binop_minmax Tom Tromey
@ 2021-01-01 21:45 ` Tom Tromey
  2021-01-01 21:45 ` [PATCH 070/203] Split out ada_binop_exp Tom Tromey
                   ` (134 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:45 UTC (permalink / raw)
  To: gdb-patches

This renames value_val_atr to ada_val_atr, changing its parameters to
more closely mirror other expression helpers.  The
EVAL_AVOID_SIDE_EFFECTS case is moved into this function as well.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* ada-lang.c (ada_val_atr): Rename from value_val_atr.  Change
	parameters.
	(ada_evaluate_subexp): Use it.
---
 gdb/ChangeLog  |  6 ++++++
 gdb/ada-lang.c | 12 +++++-------
 2 files changed, 11 insertions(+), 7 deletions(-)

diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index a3164ccd709..04d203d84cd 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -194,8 +194,6 @@ static struct value *value_pos_atr (struct type *, struct value *);
 
 static struct value *val_atr (struct type *, LONGEST);
 
-static struct value *value_val_atr (struct type *, struct value *);
-
 static struct symbol *standard_lookup (const char *, const struct block *,
 				       domain_enum);
 
@@ -8953,8 +8951,11 @@ val_atr (struct type *type, LONGEST val)
 }
 
 static struct value *
-value_val_atr (struct type *type, struct value *arg)
+ada_val_atr (enum noside noside, struct type *type, struct value *arg)
 {
+  if (noside == EVAL_AVOID_SIDE_EFFECTS)
+    return value_zero (type, not_lval);
+
   if (!discrete_type_p (type))
     error (_("'VAL only defined on discrete types"));
   if (!integer_type_p (value_type (arg)))
@@ -11074,10 +11075,7 @@ ada_evaluate_subexp (struct type *expect_type, struct expression *exp,
       type = exp->elts[pc + 2].type;
       if (noside == EVAL_SKIP)
 	goto nosideret;
-      else if (noside == EVAL_AVOID_SIDE_EFFECTS)
-	return value_zero (type, not_lval);
-      else
-	return value_val_atr (type, arg1);
+      return ada_val_atr (noside, type, arg1);
 
     case BINOP_EXP:
       arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 070/203] Split out ada_binop_exp
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (68 preceding siblings ...)
  2021-01-01 21:45 ` [PATCH 069/203] Change value_val_atr to ada_val_atr Tom Tromey
@ 2021-01-01 21:45 ` Tom Tromey
  2021-01-01 21:45 ` [PATCH 071/203] Split out eval_multi_subscript Tom Tromey
                   ` (133 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:45 UTC (permalink / raw)
  To: gdb-patches

This splits BINOP_EXP into a new function for future use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* ada-lang.c (ada_binop_exp): New function.
	(ada_evaluate_subexp): Use it.
---
 gdb/ChangeLog  |  5 +++++
 gdb/ada-lang.c | 37 ++++++++++++++++++++++++-------------
 2 files changed, 29 insertions(+), 13 deletions(-)

diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 04d203d84cd..e46c2bdbbe5 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -10520,6 +10520,29 @@ ada_binop_minmax (struct type *expect_type,
     }
 }
 
+/* A helper function for BINOP_EXP.  */
+
+static struct value *
+ada_binop_exp (struct type *expect_type,
+	       struct expression *exp,
+	       enum noside noside, enum exp_opcode op,
+	       struct value *arg1, struct value *arg2)
+{
+  if (noside == EVAL_AVOID_SIDE_EFFECTS)
+    return value_zero (value_type (arg1), not_lval);
+  else
+    {
+      /* For integer exponentiation operations,
+	 only promote the first argument.  */
+      if (is_integral_type (value_type (arg2)))
+	unop_promote (exp->language_defn, exp->gdbarch, &arg1);
+      else
+	binop_promote (exp->language_defn, exp->gdbarch, &arg1, &arg2);
+
+      return value_binop (arg1, arg2, op);
+    }
+}
+
 /* Implement the evaluate_exp routine in the exp_descriptor structure
    for the Ada language.  */
 
@@ -11082,19 +11105,7 @@ ada_evaluate_subexp (struct type *expect_type, struct expression *exp,
       arg2 = evaluate_subexp (nullptr, exp, pos, noside);
       if (noside == EVAL_SKIP)
 	goto nosideret;
-      else if (noside == EVAL_AVOID_SIDE_EFFECTS)
-	return value_zero (value_type (arg1), not_lval);
-      else
-	{
-	  /* For integer exponentiation operations,
-	     only promote the first argument.  */
-	  if (is_integral_type (value_type (arg2)))
-	    unop_promote (exp->language_defn, exp->gdbarch, &arg1);
-	  else
-	    binop_promote (exp->language_defn, exp->gdbarch, &arg1, &arg2);
-
-	  return value_binop (arg1, arg2, op);
-	}
+      return ada_binop_exp (expect_type, exp, noside, op, arg1, arg2);
 
     case UNOP_PLUS:
       arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 071/203] Split out eval_multi_subscript
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (69 preceding siblings ...)
  2021-01-01 21:45 ` [PATCH 070/203] Split out ada_binop_exp Tom Tromey
@ 2021-01-01 21:45 ` Tom Tromey
  2021-01-01 21:45 ` [PATCH 072/203] Split gen_expr_binop_rest Tom Tromey
                   ` (132 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:45 UTC (permalink / raw)
  To: gdb-patches

This splits MULTI_SUBSCRIPT into a new function for future use.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* eval.c (eval_multi_subscript): New function.
	(evaluate_subexp_standard): Use it.
---
 gdb/ChangeLog |  5 ++++
 gdb/eval.c    | 75 ++++++++++++++++++++++++++++-----------------------
 2 files changed, 47 insertions(+), 33 deletions(-)

diff --git a/gdb/eval.c b/gdb/eval.c
index 8af14fc723b..421cfb8e393 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -2335,6 +2335,46 @@ eval_op_objc_msgcall (struct type *expect_type, struct expression *exp,
   return call_function_by_hand (called_method, NULL, args);
 }
 
+/* Helper function for MULTI_SUBSCRIPT.  */
+
+static struct value *
+eval_multi_subscript (struct type *expect_type, struct expression *exp,
+		      enum noside noside, value *arg1,
+		      gdb::array_view<value *> args)
+{
+  if (noside == EVAL_SKIP)
+    return arg1;
+  for (value *arg2 : args)
+    {
+      if (binop_user_defined_p (MULTI_SUBSCRIPT, arg1, arg2))
+	{
+	  arg1 = value_x_binop (arg1, arg2, MULTI_SUBSCRIPT, OP_NULL, noside);
+	}
+      else
+	{
+	  arg1 = coerce_ref (arg1);
+	  struct type *type = check_typedef (value_type (arg1));
+
+	  switch (type->code ())
+	    {
+	    case TYPE_CODE_PTR:
+	    case TYPE_CODE_ARRAY:
+	    case TYPE_CODE_STRING:
+	      arg1 = value_subscript (arg1, value_as_long (arg2));
+	      break;
+
+	    default:
+	      if (type->name ())
+		error (_("cannot subscript something of type `%s'"),
+		       type->name ());
+	      else
+		error (_("cannot subscript requested type"));
+	    }
+	}
+    }
+  return (arg1);
+}
+
 struct value *
 evaluate_subexp_standard (struct type *expect_type,
 			  struct expression *exp, int *pos,
@@ -2790,39 +2830,8 @@ evaluate_subexp_standard (struct type *expect_type,
       argvec = XALLOCAVEC (struct value *, nargs);
       for (ix = 0; ix < nargs; ++ix)
 	argvec[ix] = evaluate_subexp_with_coercion (exp, pos, noside);
-      if (noside == EVAL_SKIP)
-	return arg1;
-      for (ix = 0; ix < nargs; ++ix)
-	{
-	  arg2 = argvec[ix];
-
-	  if (binop_user_defined_p (op, arg1, arg2))
-	    {
-	      arg1 = value_x_binop (arg1, arg2, op, OP_NULL, noside);
-	    }
-	  else
-	    {
-	      arg1 = coerce_ref (arg1);
-	      type = check_typedef (value_type (arg1));
-
-	      switch (type->code ())
-		{
-		case TYPE_CODE_PTR:
-		case TYPE_CODE_ARRAY:
-		case TYPE_CODE_STRING:
-		  arg1 = value_subscript (arg1, value_as_long (arg2));
-		  break;
-
-		default:
-		  if (type->name ())
-		    error (_("cannot subscript something of type `%s'"),
-			   type->name ());
-		  else
-		    error (_("cannot subscript requested type"));
-		}
-	    }
-	}
-      return (arg1);
+      return eval_multi_subscript (expect_type, exp, noside, arg1,
+				   gdb::make_array_view (argvec, nargs));
 
     case BINOP_LOGICAL_AND:
       arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 072/203] Split gen_expr_binop_rest
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (70 preceding siblings ...)
  2021-01-01 21:45 ` [PATCH 071/203] Split out eval_multi_subscript Tom Tromey
@ 2021-01-01 21:45 ` Tom Tromey
  2021-01-01 21:45 ` [PATCH 073/203] Introduce class operation Tom Tromey
                   ` (131 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:45 UTC (permalink / raw)
  To: gdb-patches

This splits gen_expr_binop_rest into two overloads.  One overload
retains the "pc" parameter, while the other does not, and furthermore
does not call gen_expr on the left-hand-side.  This split is useful
for subsequent patches in the new expression evaluation approach.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* ax-gdb.c (gen_expr_binop_rest): Remove "pc" parameter.
	(gen_expr_binop_rest): New overload.
---
 gdb/ChangeLog |  5 +++++
 gdb/ax-gdb.c  | 16 ++++++++++++++--
 2 files changed, 19 insertions(+), 2 deletions(-)

diff --git a/gdb/ax-gdb.c b/gdb/ax-gdb.c
index fa777281c1e..e18e968b852 100644
--- a/gdb/ax-gdb.c
+++ b/gdb/ax-gdb.c
@@ -2276,13 +2276,12 @@ gen_expr (struct expression *exp, union exp_element **pc,
 
 static void
 gen_expr_binop_rest (struct expression *exp,
-		     enum exp_opcode op, union exp_element **pc,
+		     enum exp_opcode op,
 		     struct agent_expr *ax, struct axs_value *value,
 		     struct axs_value *value1, struct axs_value *value2)
 {
   struct type *int_type = builtin_type (ax->gdbarch)->builtin_int;
 
-  gen_expr (exp, pc, ax, value2);
   gen_usual_unary (ax, value2);
   gen_usual_arithmetic (ax, value1, value2);
   switch (op)
@@ -2420,6 +2419,19 @@ gen_expr_binop_rest (struct expression *exp,
 		      _("gen_expr: op case sets don't match"));
     }
 }
+
+/* Variant of gen_expr_binop_rest that first generates the
+   right-hand-side.  */
+
+static void
+gen_expr_binop_rest (struct expression *exp,
+		     enum exp_opcode op, union exp_element **pc,
+		     struct agent_expr *ax, struct axs_value *value,
+		     struct axs_value *value1, struct axs_value *value2)
+{
+  gen_expr (exp, pc, ax, value2);
+  gen_expr_binop_rest (exp, op, ax, value, value1, value2);
+}
 \f
 
 /* Given a single variable and a scope, generate bytecodes to trace
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 073/203] Introduce class operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (71 preceding siblings ...)
  2021-01-01 21:45 ` [PATCH 072/203] Split gen_expr_binop_rest Tom Tromey
@ 2021-01-01 21:45 ` Tom Tromey
  2021-01-03  7:09   ` Joel Brobecker
  2021-01-01 21:45 ` [PATCH 074/203] Implement dumping Tom Tromey
                   ` (130 subsequent siblings)
  203 siblings, 1 reply; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:45 UTC (permalink / raw)
  To: gdb-patches

This patch introduces class operation, the new base class for all
expression operations.

In the new approach, an operation is simply a class that presents a
certain interface.  Operations own their operands, and management is
done via unique_ptr.

The operation interface is largely ad hoc, based on the evolution of
expression handling in GDB.  Parts (for example,
evaluate_with_coercion) are probably redundant; however I took this
approach to try to avoid mixing different kinds of refactorings.

In some specific situations, rather than add a generic method across
the entire operation class hierarchy, I chose instead to use
dynamic_cast and specialized methods on certain concrete subclasses.
This will appear in some subsequent patches.

One goal of this work is to avoid the kinds of easy-to-make errors
that affected the old implementation.  To this end, some helper
subclasses are also added here.  These helpers automate the
implementation of the 'dump', 'uses_objfile', and 'constant_p'
methods.  Nearly every concrete operation that is subsequently added
will use these facilities.  (Note that the 'dump' implementation is
only outlined here, the body appears in the next patch.)

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* expression.h (expr::operation): New class.
	(expr::make_operation): New function.
	(expr::operation_up): New typedef.
	* expop.h: New file.
	* eval.c (operation::evaluate_for_cast)
	(operation::evaluate_for_address, operation::evaluate_for_sizeof):
	New methods.
	* ax-gdb.c (operation::generate_ax): New method.
---
 gdb/ChangeLog    |  11 ++
 gdb/ax-gdb.c     |  26 ++++
 gdb/eval.c       |  36 ++++++
 gdb/expop.h      | 313 +++++++++++++++++++++++++++++++++++++++++++++++
 gdb/expression.h |  99 +++++++++++++++
 5 files changed, 485 insertions(+)
 create mode 100644 gdb/expop.h

diff --git a/gdb/ax-gdb.c b/gdb/ax-gdb.c
index e18e968b852..728b21dfd6a 100644
--- a/gdb/ax-gdb.c
+++ b/gdb/ax-gdb.c
@@ -2270,6 +2270,32 @@ gen_expr (struct expression *exp, union exp_element **pc,
     }
 }
 
+namespace expr
+{
+
+void
+operation::generate_ax (struct expression *exp,
+			struct agent_expr *ax,
+			struct axs_value *value,
+			struct type *cast_type)
+{
+  if (constant_p ())
+    {
+      struct value *v = evaluate (nullptr, exp, EVAL_AVOID_SIDE_EFFECTS);
+      ax_const_l (ax, value_as_long (v));
+      value->kind = axs_rvalue;
+      value->type = check_typedef (value_type (v));
+    }
+  else
+    {
+      do_generate_ax (exp, ax, value, cast_type);
+      if (cast_type != nullptr)
+	gen_cast (ax, value, cast_type);
+    }
+}
+
+}
+
 /* This handles the middle-to-right-side of code generation for binary
    expressions, which is shared between regular binary operations and
    assign-modify (+= and friends) expressions.  */
diff --git a/gdb/eval.c b/gdb/eval.c
index 421cfb8e393..970e7d7c0bc 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -40,6 +40,7 @@
 #include "objfiles.h"
 #include "typeprint.h"
 #include <ctype.h>
+#include "expop.h"
 
 /* Prototypes for local functions.  */
 
@@ -3242,6 +3243,29 @@ evaluate_subexp_for_address (struct expression *exp, int *pos,
     }
 }
 
+namespace expr
+{
+
+value *
+operation::evaluate_for_cast (struct type *expect_type,
+			      struct expression *exp,
+			      enum noside noside)
+{
+  value *val = evaluate (expect_type, exp, noside);
+  if (noside == EVAL_SKIP)
+    return eval_skip_value (exp);
+  return value_cast (expect_type, val);
+}
+
+value *
+operation::evaluate_for_address (struct expression *exp, enum noside noside)
+{
+  value *val = evaluate (nullptr, exp, noside);
+  return evaluate_subexp_for_address_base (exp, noside, val);
+}
+
+}
+
 /* Evaluate like `evaluate_subexp' except coercing arrays to pointers.
    When used in contexts where arrays will be coerced anyway, this is
    equivalent to `evaluate_subexp' but much faster because it avoids
@@ -3430,6 +3454,18 @@ evaluate_subexp_for_sizeof (struct expression *exp, int *pos,
   return evaluate_subexp_for_sizeof_base (exp, type);
 }
 
+namespace expr
+{
+
+value *
+operation::evaluate_for_sizeof (struct expression *exp, enum noside noside)
+{
+  value *val = evaluate (nullptr, exp, EVAL_AVOID_SIDE_EFFECTS);
+  return evaluate_subexp_for_sizeof_base (exp, value_type (val));
+}
+
+}
+
 /* Evaluate a subexpression of EXP, at index *POS, and return a value
    for that subexpression cast to TO_TYPE.  Advance *POS over the
    subexpression.  */
diff --git a/gdb/expop.h b/gdb/expop.h
new file mode 100644
index 00000000000..1ce57a10d9a
--- /dev/null
+++ b/gdb/expop.h
@@ -0,0 +1,313 @@
+/* Definitions for expressions in GDB
+
+   Copyright (C) 2020 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 EXPOP_H
+#define EXPOP_H
+
+#include "block.h"
+#include "c-lang.h"
+#include "cp-abi.h"
+#include "expression.h"
+#include "objfiles.h"
+#include "gdbsupport/traits.h"
+#include "gdbsupport/enum-flags.h"
+
+struct agent_expr;
+struct axs_value;
+
+namespace expr
+{
+
+/* The check_objfile overloads are used to check whether a particular
+   component of some operation references an objfile.  The passed-in
+   objfile will never be a debug objfile.  */
+
+/* See if EXP_OBJFILE matches OBJFILE.  */
+static inline bool
+check_objfile (struct objfile *exp_objfile, struct objfile *objfile)
+{
+  if (exp_objfile->separate_debug_objfile_backlink)
+    exp_objfile = exp_objfile->separate_debug_objfile_backlink;
+  return exp_objfile == objfile;
+}
+
+static inline bool 
+check_objfile (struct type *type, struct objfile *objfile)
+{
+  struct objfile *ty_objfile = TYPE_OBJFILE (type);
+  if (ty_objfile != nullptr)
+    return check_objfile (ty_objfile, objfile);
+  return false;
+}
+
+static inline bool 
+check_objfile (struct symbol *sym, struct objfile *objfile)
+{
+  return check_objfile (symbol_objfile (sym), objfile);
+}
+
+static inline bool 
+check_objfile (const struct block *block, struct objfile *objfile)
+{
+  return check_objfile (block_objfile (block), objfile);
+}
+
+static inline bool
+check_objfile (minimal_symbol *minsym, struct objfile *objfile)
+{
+  /* This may seem strange but minsyms are only used with an objfile
+     as well.  */
+  return false;
+}
+
+static inline bool
+check_objfile (internalvar *ivar, struct objfile *objfile)
+{
+  return false;
+}
+
+static inline bool
+check_objfile (const std::string &str, struct objfile *objfile)
+{
+  return false;
+}
+
+static inline bool 
+check_objfile (const operation_up &op, struct objfile *objfile)
+{
+  return op->uses_objfile (objfile);
+}
+
+static inline bool
+check_objfile (enum exp_opcode val, struct objfile *objfile)
+{
+  return false;
+}
+
+static inline bool
+check_objfile (ULONGEST val, struct objfile *objfile)
+{
+  return false;
+}
+
+template<typename T>
+static inline bool
+check_objfile (enum_flags<T> val, struct objfile *objfile)
+{
+  return false;
+}
+
+template<typename T>
+static inline bool 
+check_objfile (const std::vector<T> &collection, struct objfile *objfile)
+{
+  for (const auto &item : collection)
+    {
+      if (check_objfile (item, objfile))
+	return true;
+    }
+  return false;
+}
+
+template<typename S, typename T>
+static inline bool 
+check_objfile (const std::pair<S, T> &item, struct objfile *objfile)
+{
+  return (check_objfile (item.first, objfile)
+	  || check_objfile (item.second, objfile));
+}
+
+/* Base class for most concrete operations.  This class holds data,
+   specified via template parameters, and supplies generic
+   implementations of the 'dump' and 'uses_objfile' methods.  */
+template<typename... Arg>
+class tuple_holding_operation : public operation
+{
+public:
+
+  explicit tuple_holding_operation (Arg... args)
+    : m_storage (std::forward<Arg> (args)...)
+  {
+  }
+
+  DISABLE_COPY_AND_ASSIGN (tuple_holding_operation);
+
+  bool uses_objfile (struct objfile *objfile) const override
+  {
+    return do_check_objfile<0, Arg...> (objfile, m_storage);
+  }
+
+  void dump (struct ui_file *stream, int depth) const override
+  {
+    do_dump<0, Arg...> (stream, depth, m_storage);
+  }
+
+protected:
+
+  /* Storage for the data.  */
+  std::tuple<Arg...> m_storage;
+
+private:
+
+  /* do_dump does the work of dumping the data.  */
+  template<int I, typename... T>
+  typename std::enable_if<I == sizeof... (T), void>::type
+  do_dump (struct ui_file *stream, int depth, const std::tuple<T...> &value)
+    const
+  {
+  }
+
+  template<int I, typename... T>
+  typename std::enable_if<I < sizeof... (T), void>::type
+  do_dump (struct ui_file *stream, int depth, const std::tuple<T...> &value)
+    const
+  {
+    do_dump<I + 1, T...> (stream, depth, value);
+  }
+
+  /* do_check_objfile does the work of checking whether this object
+     refers to OBJFILE.  */
+  template<int I, typename... T>
+  typename std::enable_if<I == sizeof... (T), bool>::type
+  do_check_objfile (struct objfile *objfile, const std::tuple<T...> &value)
+    const
+  {
+    return false;
+  }
+
+  template<int I, typename... T>
+  typename std::enable_if<I < sizeof... (T), bool>::type
+  do_check_objfile (struct objfile *objfile, const std::tuple<T...> &value)
+    const
+  {
+    if (check_objfile (std::get<I> (value), objfile))
+      return true;
+    return do_check_objfile<I + 1, T...> (objfile, value);
+  }
+};
+
+/* The check_constant overloads are used to decide whether a given
+   concrete operation is a constant.  This is done by checking the
+   operands.  */
+
+static inline bool
+check_constant (const operation_up &item)
+{
+  return item->constant_p ();
+}
+
+static inline bool
+check_constant (struct minimal_symbol *msym)
+{
+  return false;
+}
+
+static inline bool
+check_constant (struct type *type)
+{
+  return true;
+}
+
+static inline bool
+check_constant (const struct block *block)
+{
+  return true;
+}
+
+static inline bool
+check_constant (const std::string &str)
+{
+  return true;
+}
+
+static inline bool
+check_constant (struct objfile *objfile)
+{
+  return true;
+}
+
+static inline bool
+check_constant (ULONGEST cst)
+{
+  return true;
+}
+
+static inline bool
+check_constant (struct symbol *sym)
+{
+  return (SYMBOL_CLASS (sym) == LOC_BLOCK
+	  || SYMBOL_CLASS (sym) == LOC_CONST
+	  || SYMBOL_CLASS (sym) == LOC_CONST_BYTES);
+}
+
+template<typename T>
+static inline bool
+check_constant (const std::vector<T> &collection)
+{
+  for (const auto &item : collection)
+    if (!check_constant (item))
+      return false;
+  return true;
+}
+
+template<typename S, typename T>
+static inline bool
+check_constant (const std::pair<S, T> &item)
+{
+  return check_constant (item.first) && check_constant (item.second);
+}
+
+/* Base class for concrete operations.  This class supplies an
+   implementation of 'constant_p' that works by checking the
+   operands.  */
+template<typename... Arg>
+class maybe_constant_operation
+  : public tuple_holding_operation<Arg...>
+{
+public:
+
+  using tuple_holding_operation<Arg...>::tuple_holding_operation;
+
+  bool constant_p () const override
+  {
+    return do_check_constant<0, Arg...> (this->m_storage);
+  }
+
+private:
+
+  template<int I, typename... T>
+  typename std::enable_if<I == sizeof... (T), bool>::type
+  do_check_constant (const std::tuple<T...> &value) const
+  {
+    return true;
+  }
+
+  template<int I, typename... T>
+  typename std::enable_if<I < sizeof... (T), bool>::type
+  do_check_constant (const std::tuple<T...> &value) const
+  {
+    if (!check_constant (std::get<I> (value)))
+      return false;
+    return do_check_constant<I + 1, T...> (value);
+  }
+};
+
+} /* namespace expr */
+
+#endif /* EXPOP_H */
diff --git a/gdb/expression.h b/gdb/expression.h
index 8c0bcc90f15..08a6424fdd2 100644
--- a/gdb/expression.h
+++ b/gdb/expression.h
@@ -89,6 +89,105 @@ enum noside
 				   does in many situations.  */
   };
 
+struct expression;
+struct agent_expr;
+struct axs_value;
+struct type;
+struct ui_file;
+
+namespace expr
+{
+
+class operation;
+typedef std::unique_ptr<operation> operation_up;
+
+/* Base class for an operation.  An operation is a single component of
+   an expression.  */
+
+class operation
+{
+protected:
+
+  operation () = default;
+  DISABLE_COPY_AND_ASSIGN (operation);
+
+public:
+
+  virtual ~operation () = default;
+
+  /* Evaluate this operation.  */
+  virtual value *evaluate (struct type *expect_type,
+			   struct expression *exp,
+			   enum noside noside) = 0;
+
+  /* Evaluate this operation in a context where C-like coercion is
+     needed.  */
+  virtual value *evaluate_with_coercion (struct expression *exp,
+					 enum noside noside)
+  {
+    return evaluate (nullptr, exp, noside);
+  }
+
+  /* Evaluate this expression in the context of a cast to
+     EXPECT_TYPE.  */
+  virtual value *evaluate_for_cast (struct type *expect_type,
+				    struct expression *exp,
+				    enum noside noside);
+
+  /* Evaluate this expression in the context of a sizeof
+     operation.  */
+  virtual value *evaluate_for_sizeof (struct expression *exp,
+				      enum noside noside);
+
+  /* Evaluate this expression in the context of an address-of
+     operation.  Must return the address.  */
+  virtual value *evaluate_for_address (struct expression *exp,
+				       enum noside noside);
+
+  /* True if this is a constant expression.  */
+  virtual bool constant_p () const
+  { return false; }
+
+  /* Return true if this operation uses OBJFILE (and will become
+     dangling when OBJFILE is unloaded), otherwise return false.
+     OBJFILE must not be a separate debug info file.  */
+  virtual bool uses_objfile (struct objfile *objfile) const
+  { return false; }
+
+  /* Generate agent expression bytecodes for this operation.  */
+  void generate_ax (struct expression *exp, struct agent_expr *ax,
+		    struct axs_value *value,
+		    struct type *cast_type = nullptr);
+
+  /* Return the opcode that is implemented by this operation.  */
+  virtual enum exp_opcode opcode () const = 0;
+
+  /* Print this operation to STREAM.  */
+  virtual void dump (struct ui_file *stream, int depth) const = 0;
+
+protected:
+
+  /* Called by generate_ax to do the work for this particular
+     operation.  */
+  virtual void do_generate_ax (struct expression *exp,
+			       struct agent_expr *ax,
+			       struct axs_value *value,
+			       struct type *cast_type)
+  {
+    error (_("Cannot translate to agent expression"));
+  }
+};
+
+/* A helper function for creating an operation_up, given a type.  */
+template<typename T, typename... Arg>
+operation_up
+make_operation (Arg... args)
+{
+  return operation_up (new T (std::forward<Arg> (args)...));
+}
+
+}
+
 union exp_element
   {
     enum exp_opcode opcode;
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 074/203] Implement dumping
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (72 preceding siblings ...)
  2021-01-01 21:45 ` [PATCH 073/203] Introduce class operation Tom Tromey
@ 2021-01-01 21:45 ` Tom Tromey
  2021-01-01 21:45 ` [PATCH 075/203] Add two agent expression helper functions Tom Tromey
                   ` (129 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:45 UTC (permalink / raw)
  To: gdb-patches

This patch implements the dumping methods for tuple_holding_operation.
A number of overloads are used.  Note that no default case is given.
This approach makes it simple to detect when a new overload is needed
-- compilation will fail.  (There is an example of this in a later
patch in the series.)

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* expprint.c (expr::dump_for_expression): New functions.
	* expop.h (dump_for_expression): New overloads.
	(tuple_holding_operation::dump, tuple_holding_operation::do_dump):
	Update.
---
 gdb/ChangeLog  |   7 +++
 gdb/expop.h    |  55 +++++++++++++++++++++-
 gdb/expprint.c | 124 +++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 185 insertions(+), 1 deletion(-)

diff --git a/gdb/expop.h b/gdb/expop.h
index 1ce57a10d9a..9fea1152cc9 100644
--- a/gdb/expop.h
+++ b/gdb/expop.h
@@ -133,6 +133,57 @@ check_objfile (const std::pair<S, T> &item, struct objfile *objfile)
 	  || check_objfile (item.second, objfile));
 }
 
+static inline void
+dump_for_expression (struct ui_file *stream, int depth,
+		     const operation_up &op)
+{
+  op->dump (stream, depth);
+}
+
+extern void dump_for_expression (struct ui_file *stream, int depth,
+				 enum exp_opcode op);
+extern void dump_for_expression (struct ui_file *stream, int depth,
+				 const std::string &str);
+extern void dump_for_expression (struct ui_file *stream, int depth,
+				 struct type *type);
+extern void dump_for_expression (struct ui_file *stream, int depth,
+				 CORE_ADDR addr);
+extern void dump_for_expression (struct ui_file *stream, int depth,
+				 internalvar *ivar);
+extern void dump_for_expression (struct ui_file *stream, int depth,
+				 symbol *sym);
+extern void dump_for_expression (struct ui_file *stream, int depth,
+				 minimal_symbol *msym);
+extern void dump_for_expression (struct ui_file *stream, int depth,
+				 const block *bl);
+extern void dump_for_expression (struct ui_file *stream, int depth,
+				 type_instance_flags flags);
+extern void dump_for_expression (struct ui_file *stream, int depth,
+				 enum c_string_type_values flags);
+extern void dump_for_expression (struct ui_file *stream, int depth,
+				 enum range_flag flags);
+extern void dump_for_expression (struct ui_file *stream, int depth,
+				 objfile *objf);
+
+template<typename T>
+void
+dump_for_expression (struct ui_file *stream, int depth,
+		     const std::vector<T> &vals)
+{
+  fprintf_filtered (stream, _("%*sVector:\n"), depth, "");
+  for (auto &item : vals)
+    dump_for_expression (stream, depth + 1, item);
+}
+
+template<typename X, typename Y>
+void
+dump_for_expression (struct ui_file *stream, int depth,
+		     const std::pair<X, Y> &vals)
+{
+  dump_for_expression (stream, depth, vals.first);
+  dump_for_expression (stream, depth, vals.second);
+}
+
 /* Base class for most concrete operations.  This class holds data,
    specified via template parameters, and supplies generic
    implementations of the 'dump' and 'uses_objfile' methods.  */
@@ -155,7 +206,8 @@ class tuple_holding_operation : public operation
 
   void dump (struct ui_file *stream, int depth) const override
   {
-    do_dump<0, Arg...> (stream, depth, m_storage);
+    dump_for_expression (stream, depth, opcode ());
+    do_dump<0, Arg...> (stream, depth + 1, m_storage);
   }
 
 protected:
@@ -178,6 +230,7 @@ class tuple_holding_operation : public operation
   do_dump (struct ui_file *stream, int depth, const std::tuple<T...> &value)
     const
   {
+    dump_for_expression (stream, depth, std::get<I> (value));
     do_dump<I + 1, T...> (stream, depth, value);
   }
 
diff --git a/gdb/expprint.c b/gdb/expprint.c
index f75874b77df..3c84a65bfda 100644
--- a/gdb/expprint.c
+++ b/gdb/expprint.c
@@ -30,6 +30,8 @@
 #include "objfiles.h"
 #include "valprint.h"
 #include "cli/cli-style.h"
+#include "c-lang.h"
+#include "expop.h"
 
 #include <ctype.h>
 
@@ -1153,3 +1155,125 @@ dump_prefix_expression (struct expression *exp, struct ui_file *stream)
     elt = dump_subexp (exp, stream, elt);
   fputs_filtered ("\n", stream);
 }
+
+namespace expr
+{
+
+void
+dump_for_expression (struct ui_file *stream, int depth, enum exp_opcode op)
+{
+  fprintf_filtered (stream, _("%*sOperation: %s\n"), depth, "", op_name (op));
+}
+
+void
+dump_for_expression (struct ui_file *stream, int depth, const std::string &str)
+{
+  fprintf_filtered (stream, _("%*sString: %s\n"), depth, "", str.c_str ());
+}
+
+void
+dump_for_expression (struct ui_file *stream, int depth, struct type *type)
+{
+  fprintf_filtered (stream, _("%*sType: "), depth, "");
+  type_print (type, nullptr, stream, 0);
+  fprintf_filtered (stream, "\n");
+}
+
+void
+dump_for_expression (struct ui_file *stream, int depth, CORE_ADDR addr)
+{
+  fprintf_filtered (stream, _("%*sAddress: %s\n"), depth, "",
+		     core_addr_to_string (addr));
+}
+
+void
+dump_for_expression (struct ui_file *stream, int depth, internalvar *ivar)
+{
+  fprintf_filtered (stream, _("%*sInternalvar: $%s\n"), depth, "",
+		     internalvar_name (ivar));
+}
+
+void
+dump_for_expression (struct ui_file *stream, int depth, symbol *sym)
+{
+  fprintf_filtered (stream, _("%*sSymbol: %s\n"), depth, "",
+		     sym->print_name ());
+}
+
+void
+dump_for_expression (struct ui_file *stream, int depth, minimal_symbol *msym)
+{
+  fprintf_filtered (stream, _("%*sMinsym: %s\n"), depth, "",
+		     msym->print_name ());
+}
+
+void
+dump_for_expression (struct ui_file *stream, int depth, const block *bl)
+{
+  fprintf_filtered (stream, _("%*sBlock: %p\n"), depth, "", bl);
+}
+
+void
+dump_for_expression (struct ui_file *stream, int depth,
+		     type_instance_flags flags)
+{
+  fprintf_filtered (stream, _("%*sType flags: "), depth, "");
+  if (flags & TYPE_INSTANCE_FLAG_CONST)
+    fputs_unfiltered ("const ", stream);
+  if (flags & TYPE_INSTANCE_FLAG_VOLATILE)
+    fputs_unfiltered ("volatile", stream);
+  fprintf_filtered (stream, "\n");
+}
+
+void
+dump_for_expression (struct ui_file *stream, int depth,
+		     enum c_string_type_values flags)
+{
+  fprintf_filtered (stream, _("%*sC string flags: "), depth, "");
+  switch (flags & ~C_CHAR)
+    {
+    case C_WIDE_STRING:
+      fputs_unfiltered (_("wide "), stream);
+      break;
+    case C_STRING_16:
+      fputs_unfiltered (_("u16 "), stream);
+      break;
+    case C_STRING_32:
+      fputs_unfiltered (_("u32 "), stream);
+      break;
+    default:
+      fputs_unfiltered (_("ordinary "), stream);
+      break;
+    }
+
+  if ((flags & C_CHAR) != 0)
+    fputs_unfiltered (_("char"), stream);
+  else
+    fputs_unfiltered (_("string"), stream);
+  fputs_unfiltered ("\n", stream);
+}
+
+void
+dump_for_expression (struct ui_file *stream, int depth, objfile *objf)
+{
+  fprintf_filtered (stream, _("%*sObjfile: %s\n"), depth, "",
+		     objfile_name (objf));
+}
+
+void
+dump_for_expression (struct ui_file *stream, int depth,
+		     enum range_flag flags)
+{
+  fprintf_filtered (stream, _("%*sRange:"), depth, "");
+  if ((flags & RANGE_LOW_BOUND_DEFAULT) != 0)
+    fputs_unfiltered (_("low-default "), stream);
+  if ((flags & RANGE_HIGH_BOUND_DEFAULT) != 0)
+    fputs_unfiltered (_("high-default "), stream);
+  if ((flags & RANGE_HIGH_BOUND_EXCLUSIVE) != 0)
+    fputs_unfiltered (_("high-exclusive "), stream);
+  if ((flags & RANGE_HAS_STRIDE) != 0)
+    fputs_unfiltered (_("has-stride"), stream);
+  fprintf_filtered (stream, "\n");
+}
+
+} /* namespace expr */
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 075/203] Add two agent expression helper functions
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (73 preceding siblings ...)
  2021-01-01 21:45 ` [PATCH 074/203] Implement dumping Tom Tromey
@ 2021-01-01 21:45 ` Tom Tromey
  2021-01-01 21:45 ` [PATCH 076/203] Introduce float_const_operation Tom Tromey
                   ` (128 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:45 UTC (permalink / raw)
  To: gdb-patches

This adds a couple of agent expression helper functions that will be
useful when implementing various operations.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* expop.h (gen_expr_binop, gen_expr_structop): Declare.
	* ax-gdb.c (gen_expr_binop): New function.
	(gen_expr_structop): Likewise.
---
 gdb/ChangeLog |  6 ++++++
 gdb/ax-gdb.c  | 45 +++++++++++++++++++++++++++++++++++++++++++++
 gdb/expop.h   | 10 ++++++++++
 3 files changed, 61 insertions(+)

diff --git a/gdb/ax-gdb.c b/gdb/ax-gdb.c
index 728b21dfd6a..1ffa8e49bf1 100644
--- a/gdb/ax-gdb.c
+++ b/gdb/ax-gdb.c
@@ -158,6 +158,12 @@ static void gen_expr_binop_rest (struct expression *exp,
 				 struct axs_value *value,
 				 struct axs_value *value1,
 				 struct axs_value *value2);
+static void gen_expr_binop_rest (struct expression *exp,
+				 enum exp_opcode op,
+				 struct agent_expr *ax,
+				 struct axs_value *value,
+				 struct axs_value *value1,
+				 struct axs_value *value2);
 \f
 
 /* Detecting constant expressions.  */
@@ -2458,6 +2464,45 @@ gen_expr_binop_rest (struct expression *exp,
   gen_expr (exp, pc, ax, value2);
   gen_expr_binop_rest (exp, op, ax, value, value1, value2);
 }
+
+/* A helper function that emits a binop based on two operations.  */
+
+void
+gen_expr_binop (struct expression *exp,
+		enum exp_opcode op,
+		expr::operation *lhs, expr::operation *rhs,
+		struct agent_expr *ax, struct axs_value *value)
+{
+  struct axs_value value1, value2;
+
+  lhs->generate_ax (exp, ax, &value1);
+  gen_usual_unary (ax, &value1);
+  rhs->generate_ax (exp, ax, &value2);
+  gen_expr_binop_rest (exp, op, ax, value, &value1, &value2);
+}
+
+/* A helper function that emits a structop based on an operation and a
+   member name.  */
+
+void
+gen_expr_structop (struct expression *exp,
+		   enum exp_opcode op,
+		   expr::operation *lhs,
+		   const char *name,
+		   struct agent_expr *ax, struct axs_value *value)
+{
+  lhs->generate_ax (exp, ax, value);
+  if (op == STRUCTOP_STRUCT)
+    gen_struct_ref (ax, value, name, ".", "structure or union");
+  else if (op == STRUCTOP_PTR)
+    gen_struct_ref (ax, value, name, "->",
+		    "pointer to a structure or union");
+  else
+    /* If this `if' chain doesn't handle it, then the case list
+       shouldn't mention it, and we shouldn't be here.  */
+    internal_error (__FILE__, __LINE__,
+		    _("gen_expr: unhandled struct case"));
+}
 \f
 
 /* Given a single variable and a scope, generate bytecodes to trace
diff --git a/gdb/expop.h b/gdb/expop.h
index 9fea1152cc9..2e7191cf59c 100644
--- a/gdb/expop.h
+++ b/gdb/expop.h
@@ -31,6 +31,16 @@
 struct agent_expr;
 struct axs_value;
 
+extern void gen_expr_binop (struct expression *exp,
+			    enum exp_opcode op,
+			    expr::operation *lhs, expr::operation *rhs,
+			    struct agent_expr *ax, struct axs_value *value);
+extern void gen_expr_structop (struct expression *exp,
+			       enum exp_opcode op,
+			       expr::operation *lhs,
+			       const char *name,
+			       struct agent_expr *ax, struct axs_value *value);
+
 namespace expr
 {
 
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 076/203] Introduce float_const_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (74 preceding siblings ...)
  2021-01-01 21:45 ` [PATCH 075/203] Add two agent expression helper functions Tom Tromey
@ 2021-01-01 21:45 ` Tom Tromey
  2021-01-01 21:45 ` [PATCH 077/203] Introduce scope_operation Tom Tromey
                   ` (127 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:45 UTC (permalink / raw)
  To: gdb-patches

This adds class float_const_operation, an operation holding a
floating-point constant.  Unlike most other new operations, this one
requires a custom 'dump' method.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* expprint.c (float_const_operation::dump): New method.
	* expop.h (float_data): New typedef.
	(class float_const_operation): New.
---
 gdb/ChangeLog  |  6 ++++++
 gdb/expop.h    | 42 ++++++++++++++++++++++++++++++++++++++++++
 gdb/expprint.c |  8 ++++++++
 3 files changed, 56 insertions(+)

diff --git a/gdb/expop.h b/gdb/expop.h
index 2e7191cf59c..6af6504332e 100644
--- a/gdb/expop.h
+++ b/gdb/expop.h
@@ -371,6 +371,48 @@ class maybe_constant_operation
   }
 };
 
+/* A floating-point constant.  The constant is encoded in the target
+   format.  */
+
+typedef std::array<gdb_byte, 16> float_data;
+
+/* An operation that holds a floating-point constant of a given
+   type.
+
+   This does not need the facilities provided by
+   tuple_holding_operation, so it does not use it.  */
+class float_const_operation
+  : public operation
+{
+public:
+
+  float_const_operation (struct type *type, float_data data)
+    : m_type (type),
+      m_data (data)
+  {
+  }
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override
+  {
+    return value_from_contents (m_type, m_data.data ());
+  }
+
+  enum exp_opcode opcode () const override
+  { return OP_FLOAT; }
+
+  bool constant_p () const override
+  { return true; }
+
+  void dump (struct ui_file *stream, int depth) const override;
+
+private:
+
+  struct type *m_type;
+  float_data m_data;
+};
+
 } /* namespace expr */
 
 #endif /* EXPOP_H */
diff --git a/gdb/expprint.c b/gdb/expprint.c
index 3c84a65bfda..0f4c8602f1c 100644
--- a/gdb/expprint.c
+++ b/gdb/expprint.c
@@ -1276,4 +1276,12 @@ dump_for_expression (struct ui_file *stream, int depth,
   fprintf_filtered (stream, "\n");
 }
 
+void
+float_const_operation::dump (struct ui_file *stream, int depth) const
+{
+  fprintf_filtered (stream, _("%*sFloat: "), depth, "");
+  print_floating (m_data.data (), m_type, stream);
+  fprintf_filtered (stream, "\n");
+}
+
 } /* namespace expr */
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 077/203] Introduce scope_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (75 preceding siblings ...)
  2021-01-01 21:45 ` [PATCH 076/203] Introduce float_const_operation Tom Tromey
@ 2021-01-01 21:45 ` Tom Tromey
  2021-01-01 21:45 ` [PATCH 078/203] Introduce long_const_operation Tom Tromey
                   ` (126 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:45 UTC (permalink / raw)
  To: gdb-patches

This adds class scope_operation, an implementation of OP_SCOPE.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* expop.h (class scope_operation): New.
	* eval.c (eval_op_scope): No longer static.
	(scope_operation::evaluate_for_address): New method.
	* ax-gdb.c (scope_operation::do_generate_ax): New method.
---
 gdb/ChangeLog |  7 +++++++
 gdb/ax-gdb.c  | 14 ++++++++++++++
 gdb/eval.c    | 14 +++++++++++++-
 gdb/expop.h   | 36 ++++++++++++++++++++++++++++++++++++
 4 files changed, 70 insertions(+), 1 deletion(-)

diff --git a/gdb/ax-gdb.c b/gdb/ax-gdb.c
index 1ffa8e49bf1..6d568a71e03 100644
--- a/gdb/ax-gdb.c
+++ b/gdb/ax-gdb.c
@@ -45,6 +45,7 @@
 #include "typeprint.h"
 #include "valprint.h"
 #include "c-lang.h"
+#include "expop.h"
 
 #include "gdbsupport/format.h"
 
@@ -2300,6 +2301,19 @@ operation::generate_ax (struct expression *exp,
     }
 }
 
+void
+scope_operation::do_generate_ax (struct expression *exp,
+				 struct agent_expr *ax,
+				 struct axs_value *value,
+				 struct type *cast_type)
+{
+  struct type *type = std::get<0> (m_storage);
+  const std::string &name = std::get<1> (m_storage);
+  int found = gen_aggregate_elt_ref (ax, value, type, name.c_str ());
+  if (!found)
+    error (_("There is no field named %s"), name.c_str ());
+}
+
 }
 
 /* This handles the middle-to-right-side of code generation for binary
diff --git a/gdb/eval.c b/gdb/eval.c
index 970e7d7c0bc..fe8698342db 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1182,7 +1182,7 @@ is_integral_or_integral_reference (struct type *type)
 
 /* Helper function that implements the body of OP_SCOPE.  */
 
-static struct value *
+struct value *
 eval_op_scope (struct type *expect_type, struct expression *exp,
 	       enum noside noside,
 	       struct type *type, const char *string)
@@ -3264,6 +3264,18 @@ operation::evaluate_for_address (struct expression *exp, enum noside noside)
   return evaluate_subexp_for_address_base (exp, noside, val);
 }
 
+value *
+scope_operation::evaluate_for_address (struct expression *exp,
+				       enum noside noside)
+{
+  value *x = value_aggregate_elt (std::get<0> (m_storage),
+				  std::get<1> (m_storage).c_str (),
+				  NULL, 1, noside);
+  if (x == NULL)
+    error (_("There is no field named %s"), std::get<1> (m_storage).c_str ());
+  return x;
+}
+
 }
 
 /* Evaluate like `evaluate_subexp' except coercing arrays to pointers.
diff --git a/gdb/expop.h b/gdb/expop.h
index 6af6504332e..3fcd25ddcea 100644
--- a/gdb/expop.h
+++ b/gdb/expop.h
@@ -41,6 +41,11 @@ extern void gen_expr_structop (struct expression *exp,
 			       const char *name,
 			       struct agent_expr *ax, struct axs_value *value);
 
+extern struct value *eval_op_scope (struct type *expect_type,
+				    struct expression *exp,
+				    enum noside noside,
+				    struct type *type, const char *string);
+
 namespace expr
 {
 
@@ -413,6 +418,37 @@ class float_const_operation
   float_data m_data;
 };
 
+class scope_operation
+  : public maybe_constant_operation<struct type *, std::string>
+{
+public:
+
+  using maybe_constant_operation::maybe_constant_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override
+  {
+    return eval_op_scope (expect_type, exp, noside,
+			  std::get<0> (m_storage),
+			  std::get<1> (m_storage).c_str ());
+  }
+
+  value *evaluate_for_address (struct expression *exp,
+			       enum noside noside) override;
+
+  enum exp_opcode opcode () const override
+  { return OP_SCOPE; }
+
+protected:
+
+  void do_generate_ax (struct expression *exp,
+		       struct agent_expr *ax,
+		       struct axs_value *value,
+		       struct type *cast_type)
+    override;
+};
+
 } /* namespace expr */
 
 #endif /* EXPOP_H */
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 078/203] Introduce long_const_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (76 preceding siblings ...)
  2021-01-01 21:45 ` [PATCH 077/203] Introduce scope_operation Tom Tromey
@ 2021-01-01 21:45 ` Tom Tromey
  2021-01-01 21:45 ` [PATCH 079/203] Introduce var_msym_value_operation Tom Tromey
                   ` (125 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:45 UTC (permalink / raw)
  To: gdb-patches

This adds class long_const_operation, which holds a scalar constant.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* expop.h (class long_const_operation): New.
	* ax-gdb.c (long_const_operation::do_generate_ax): New method.
---
 gdb/ChangeLog |  5 +++++
 gdb/ax-gdb.c  | 10 ++++++++++
 gdb/expop.h   | 30 ++++++++++++++++++++++++++++++
 3 files changed, 45 insertions(+)

diff --git a/gdb/ax-gdb.c b/gdb/ax-gdb.c
index 6d568a71e03..7640b1ba925 100644
--- a/gdb/ax-gdb.c
+++ b/gdb/ax-gdb.c
@@ -2314,6 +2314,16 @@ scope_operation::do_generate_ax (struct expression *exp,
     error (_("There is no field named %s"), name.c_str ());
 }
 
+void
+long_const_operation::do_generate_ax (struct expression *exp,
+				      struct agent_expr *ax,
+				      struct axs_value *value,
+				      struct type *cast_type)
+{
+  gen_int_literal (ax, value, std::get<1> (m_storage),
+		   std::get<0> (m_storage));
+}
+
 }
 
 /* This handles the middle-to-right-side of code generation for binary
diff --git a/gdb/expop.h b/gdb/expop.h
index 3fcd25ddcea..ede075b44d8 100644
--- a/gdb/expop.h
+++ b/gdb/expop.h
@@ -449,6 +449,36 @@ class scope_operation
     override;
 };
 
+class long_const_operation
+  : public tuple_holding_operation<struct type *, LONGEST>
+{
+public:
+
+  using tuple_holding_operation::tuple_holding_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override
+  {
+    return value_from_longest (std::get<0> (m_storage),
+			       std::get<1> (m_storage));
+  }
+
+  enum exp_opcode opcode () const override
+  { return OP_LONG; }
+
+  bool constant_p () const override
+  { return true; }
+
+protected:
+
+  void do_generate_ax (struct expression *exp,
+		       struct agent_expr *ax,
+		       struct axs_value *value,
+		       struct type *cast_type)
+    override;
+};
+
 } /* namespace expr */
 
 #endif /* EXPOP_H */
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 079/203] Introduce var_msym_value_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (77 preceding siblings ...)
  2021-01-01 21:45 ` [PATCH 078/203] Introduce long_const_operation Tom Tromey
@ 2021-01-01 21:45 ` Tom Tromey
  2021-01-01 21:45 ` [PATCH 080/203] Introduce var_entry_value_operation Tom Tromey
                   ` (124 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:45 UTC (permalink / raw)
  To: gdb-patches

This adds class var_msym_value_operation, which implements
OP_VAR_MSYM_VALUE.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* expop.h (class var_msym_value_operation): New.
	* eval.c (eval_op_var_msym_value): No longer static.
	(var_msym_value_operation::evaluate_for_address)
	(var_msym_value_operation::evaluate_for_sizeof)
	(var_msym_value_operation::evaluate_for_cast): New methods.
	* ax-gdb.c (var_msym_value_operation::do_generate_ax): New
	method.
---
 gdb/ChangeLog | 10 ++++++++
 gdb/ax-gdb.c  | 17 +++++++++++++
 gdb/eval.c    | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 gdb/expop.h   | 43 ++++++++++++++++++++++++++++++++
 4 files changed, 138 insertions(+), 1 deletion(-)

diff --git a/gdb/ax-gdb.c b/gdb/ax-gdb.c
index 7640b1ba925..60281700703 100644
--- a/gdb/ax-gdb.c
+++ b/gdb/ax-gdb.c
@@ -2324,6 +2324,23 @@ long_const_operation::do_generate_ax (struct expression *exp,
 		   std::get<0> (m_storage));
 }
 
+void
+var_msym_value_operation::do_generate_ax (struct expression *exp,
+					  struct agent_expr *ax,
+					  struct axs_value *value,
+					  struct type *cast_type)
+{
+  gen_msym_var_ref (ax, value, std::get<0> (m_storage),
+		    std::get<1> (m_storage));
+
+  if (value->type->code () == TYPE_CODE_ERROR)
+    {
+      if (cast_type == nullptr)
+	error_unknown_type (std::get<0> (m_storage)->linkage_name ());
+      value->type = cast_type;
+    }
+}
+
 }
 
 /* This handles the middle-to-right-side of code generation for binary
diff --git a/gdb/eval.c b/gdb/eval.c
index fe8698342db..38bbb3519ba 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1216,7 +1216,7 @@ eval_op_var_entry_value (struct type *expect_type, struct expression *exp,
   return SYMBOL_COMPUTED_OPS (sym)->read_variable_at_entry (sym, frame);
 }
 
-static struct value *
+struct value *
 eval_op_var_msym_value (struct type *expect_type, struct expression *exp,
 			enum noside noside,
 			minimal_symbol *msymbol, struct objfile *objfile)
@@ -3276,6 +3276,22 @@ scope_operation::evaluate_for_address (struct expression *exp,
   return x;
 }
 
+value *
+var_msym_value_operation::evaluate_for_address (struct expression *exp,
+						enum noside noside)
+{
+  value *val = evaluate_var_msym_value (noside,
+					std::get<1> (m_storage),
+					std::get<0> (m_storage));
+  if (noside == EVAL_AVOID_SIDE_EFFECTS)
+    {
+      struct type *type = lookup_pointer_type (value_type (val));
+      return value_zero (type, not_lval);
+    }
+  else
+    return value_addr (val);
+}
+
 }
 
 /* Evaluate like `evaluate_subexp' except coercing arrays to pointers.
@@ -3476,6 +3492,25 @@ operation::evaluate_for_sizeof (struct expression *exp, enum noside noside)
   return evaluate_subexp_for_sizeof_base (exp, value_type (val));
 }
 
+value *
+var_msym_value_operation::evaluate_for_sizeof (struct expression *exp,
+					       enum noside noside)
+
+{
+  minimal_symbol *msymbol = std::get<0> (m_storage);
+  value *mval = evaluate_var_msym_value (noside,
+					 std::get<1> (m_storage),
+					 msymbol);
+
+  struct type *type = value_type (mval);
+  if (type->code () == TYPE_CODE_ERROR)
+    error_unknown_type (msymbol->print_name ());
+
+  /* FIXME: This should be size_t.  */
+  struct type *size_type = builtin_type (exp->gdbarch)->builtin_int;
+  return value_from_longest (size_type, TYPE_LENGTH (type));
+}
+
 }
 
 /* Evaluate a subexpression of EXP, at index *POS, and return a value
@@ -3533,6 +3568,38 @@ evaluate_subexp_for_cast (expression *exp, int *pos,
   return value_cast (to_type, val);
 }
 
+namespace expr
+{
+
+value *
+var_msym_value_operation::evaluate_for_cast (struct type *to_type,
+					     struct expression *exp,
+					     enum noside noside)
+{
+  if (noside == EVAL_AVOID_SIDE_EFFECTS)
+    return value_zero (to_type, not_lval);
+
+  value *val = evaluate_var_msym_value (noside,
+					std::get<1> (m_storage),
+					std::get<0> (m_storage));
+
+  if (noside == EVAL_SKIP)
+    return eval_skip_value (exp);
+
+  val = value_cast (to_type, val);
+
+  /* Don't allow e.g. '&(int)var_with_no_debug_info'.  */
+  if (VALUE_LVAL (val) == lval_memory)
+    {
+      if (value_lazy (val))
+	value_fetch_lazy (val);
+      VALUE_LVAL (val) = not_lval;
+    }
+  return val;
+}
+
+}
+
 /* Parse a type expression in the string [P..P+LENGTH).  */
 
 struct type *
diff --git a/gdb/expop.h b/gdb/expop.h
index ede075b44d8..caa4d329fef 100644
--- a/gdb/expop.h
+++ b/gdb/expop.h
@@ -45,6 +45,11 @@ extern struct value *eval_op_scope (struct type *expect_type,
 				    struct expression *exp,
 				    enum noside noside,
 				    struct type *type, const char *string);
+extern struct value *eval_op_var_msym_value (struct type *expect_type,
+					     struct expression *exp,
+					     enum noside noside,
+					     minimal_symbol *msymbol,
+					     struct objfile *objfile);
 
 namespace expr
 {
@@ -479,6 +484,44 @@ class long_const_operation
     override;
 };
 
+class var_msym_value_operation
+  : public maybe_constant_operation<minimal_symbol *, struct objfile *>
+{
+public:
+
+  using maybe_constant_operation::maybe_constant_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override
+  {
+    return eval_op_var_msym_value (expect_type, exp, noside,
+				   std::get<0> (m_storage),
+				   std::get<1> (m_storage));
+  }
+
+  value *evaluate_for_sizeof (struct expression *exp, enum noside noside)
+    override;
+
+  value *evaluate_for_address (struct expression *exp, enum noside noside)
+    override;
+
+  value *evaluate_for_cast (struct type *expect_type,
+			    struct expression *exp,
+			    enum noside noside) override;
+
+  enum exp_opcode opcode () const override
+  { return OP_VAR_MSYM_VALUE; }
+
+protected:
+
+  void do_generate_ax (struct expression *exp,
+		       struct agent_expr *ax,
+		       struct axs_value *value,
+		       struct type *cast_type)
+    override;
+};
+
 } /* namespace expr */
 
 #endif /* EXPOP_H */
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 080/203] Introduce var_entry_value_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (78 preceding siblings ...)
  2021-01-01 21:45 ` [PATCH 079/203] Introduce var_msym_value_operation Tom Tromey
@ 2021-01-01 21:45 ` Tom Tromey
  2021-01-01 21:45 ` [PATCH 081/203] Introduce func_static_var_operation Tom Tromey
                   ` (123 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:45 UTC (permalink / raw)
  To: gdb-patches

This adds class var_entry_value_operation, which implements
OP_VAR_ENTRY_VALUE.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* expop.h (class var_entry_value_operation): New.
	* eval.c (eval_op_var_entry_value): No longer static.
---
 gdb/ChangeLog |  5 +++++
 gdb/eval.c    |  2 +-
 gdb/expop.h   | 22 ++++++++++++++++++++++
 3 files changed, 28 insertions(+), 1 deletion(-)

diff --git a/gdb/eval.c b/gdb/eval.c
index 38bbb3519ba..753d505b173 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1198,7 +1198,7 @@ eval_op_scope (struct type *expect_type, struct expression *exp,
 
 /* Helper function that implements the body of OP_VAR_ENTRY_VALUE.  */
 
-static struct value *
+struct value *
 eval_op_var_entry_value (struct type *expect_type, struct expression *exp,
 			 enum noside noside, symbol *sym)
 {
diff --git a/gdb/expop.h b/gdb/expop.h
index caa4d329fef..d9052887739 100644
--- a/gdb/expop.h
+++ b/gdb/expop.h
@@ -50,6 +50,9 @@ extern struct value *eval_op_var_msym_value (struct type *expect_type,
 					     enum noside noside,
 					     minimal_symbol *msymbol,
 					     struct objfile *objfile);
+extern struct value *eval_op_var_entry_value (struct type *expect_type,
+					      struct expression *exp,
+					      enum noside noside, symbol *sym);
 
 namespace expr
 {
@@ -522,6 +525,25 @@ class var_msym_value_operation
     override;
 };
 
+class var_entry_value_operation
+  : public tuple_holding_operation<symbol *>
+{
+public:
+
+  using tuple_holding_operation::tuple_holding_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override
+  {
+    return eval_op_var_entry_value (expect_type, exp, noside,
+				    std::get<0> (m_storage));
+  }
+
+  enum exp_opcode opcode () const override
+  { return OP_VAR_ENTRY_VALUE; }
+};
+
 } /* namespace expr */
 
 #endif /* EXPOP_H */
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 081/203] Introduce func_static_var_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (79 preceding siblings ...)
  2021-01-01 21:45 ` [PATCH 080/203] Introduce var_entry_value_operation Tom Tromey
@ 2021-01-01 21:45 ` Tom Tromey
  2021-01-01 21:45 ` [PATCH 082/203] Introduce last_operation Tom Tromey
                   ` (122 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:45 UTC (permalink / raw)
  To: gdb-patches

This adds class func_static_var_operation, which implements
OP_FUNC_STATIC_VAR.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* expop.h (class func_static_var_operation): New.
	* eval.c (eval_op_func_static_var): No longer static.
---
 gdb/ChangeLog |  5 +++++
 gdb/eval.c    |  2 +-
 gdb/expop.h   | 24 ++++++++++++++++++++++++
 3 files changed, 30 insertions(+), 1 deletion(-)

diff --git a/gdb/eval.c b/gdb/eval.c
index 753d505b173..f28c7ace8be 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1230,7 +1230,7 @@ eval_op_var_msym_value (struct type *expect_type, struct expression *exp,
   return val;
 }
 
-static struct value *
+struct value *
 eval_op_func_static_var (struct type *expect_type, struct expression *exp,
 			 enum noside noside,
 			 value *func, const char *var)
diff --git a/gdb/expop.h b/gdb/expop.h
index d9052887739..49f1f561019 100644
--- a/gdb/expop.h
+++ b/gdb/expop.h
@@ -53,6 +53,10 @@ extern struct value *eval_op_var_msym_value (struct type *expect_type,
 extern struct value *eval_op_var_entry_value (struct type *expect_type,
 					      struct expression *exp,
 					      enum noside noside, symbol *sym);
+extern struct value *eval_op_func_static_var (struct type *expect_type,
+					      struct expression *exp,
+					      enum noside noside,
+					      value *func, const char *var);
 
 namespace expr
 {
@@ -544,6 +548,26 @@ class var_entry_value_operation
   { return OP_VAR_ENTRY_VALUE; }
 };
 
+class func_static_var_operation
+  : public maybe_constant_operation<operation_up, std::string>
+{
+public:
+
+  using maybe_constant_operation::maybe_constant_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override
+  {
+    value *func = std::get<0> (m_storage)->evaluate (nullptr, exp, noside);
+    return eval_op_func_static_var (expect_type, exp, noside, func,
+				    std::get<1> (m_storage).c_str ());
+  }
+
+  enum exp_opcode opcode () const override
+  { return OP_FUNC_STATIC_VAR; }
+};
+
 } /* namespace expr */
 
 #endif /* EXPOP_H */
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 082/203] Introduce last_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (80 preceding siblings ...)
  2021-01-01 21:45 ` [PATCH 081/203] Introduce func_static_var_operation Tom Tromey
@ 2021-01-01 21:45 ` Tom Tromey
  2021-01-01 21:45 ` [PATCH 083/203] Introduce register_operation Tom Tromey
                   ` (121 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:45 UTC (permalink / raw)
  To: gdb-patches

This adds class last_operation, which implements OP_LAST.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* expop.h (class last_operation): New.
---
 gdb/ChangeLog |  4 ++++
 gdb/expop.h   | 18 ++++++++++++++++++
 2 files changed, 22 insertions(+)

diff --git a/gdb/expop.h b/gdb/expop.h
index 49f1f561019..110ad0a29ab 100644
--- a/gdb/expop.h
+++ b/gdb/expop.h
@@ -568,6 +568,24 @@ class func_static_var_operation
   { return OP_FUNC_STATIC_VAR; }
 };
 
+class last_operation
+  : public tuple_holding_operation<int>
+{
+public:
+
+  using tuple_holding_operation::tuple_holding_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override
+  {
+    return access_value_history (std::get<0> (m_storage));
+  }
+
+  enum exp_opcode opcode () const override
+  { return OP_LAST; }
+};
+
 } /* namespace expr */
 
 #endif /* EXPOP_H */
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 083/203] Introduce register_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (81 preceding siblings ...)
  2021-01-01 21:45 ` [PATCH 082/203] Introduce last_operation Tom Tromey
@ 2021-01-01 21:45 ` Tom Tromey
  2021-01-01 21:45 ` [PATCH 084/203] Introduce bool_operation Tom Tromey
                   ` (120 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:45 UTC (permalink / raw)
  To: gdb-patches

This adds class register_operation, which implements OP_REGISTER.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* expop.h (class register_operation): New.
	* eval.c (eval_op_register): No longer static.
	* ax-gdb.c (register_operation::do_generate_ax): New method.
---
 gdb/ChangeLog |  6 ++++++
 gdb/ax-gdb.c  | 24 ++++++++++++++++++++++++
 gdb/eval.c    |  2 +-
 gdb/expop.h   | 30 ++++++++++++++++++++++++++++++
 4 files changed, 61 insertions(+), 1 deletion(-)

diff --git a/gdb/ax-gdb.c b/gdb/ax-gdb.c
index 60281700703..5ffe5a00da1 100644
--- a/gdb/ax-gdb.c
+++ b/gdb/ax-gdb.c
@@ -2341,6 +2341,30 @@ var_msym_value_operation::do_generate_ax (struct expression *exp,
     }
 }
 
+void
+register_operation::do_generate_ax (struct expression *exp,
+				    struct agent_expr *ax,
+				    struct axs_value *value,
+				    struct type *cast_type)
+{
+  const char *name = std::get<0> (m_storage).c_str ();
+  int len = std::get<0> (m_storage).size ();
+  int reg;
+
+  reg = user_reg_map_name_to_regnum (ax->gdbarch, name, len);
+  if (reg == -1)
+    internal_error (__FILE__, __LINE__,
+		    _("Register $%s not available"), name);
+  /* No support for tracing user registers yet.  */
+  if (reg >= gdbarch_num_cooked_regs (ax->gdbarch))
+    error (_("'%s' is a user-register; "
+	     "GDB cannot yet trace user-register contents."),
+	   name);
+  value->kind = axs_lvalue_register;
+  value->u.reg = reg;
+  value->type = register_type (ax->gdbarch, reg);
+}
+
 }
 
 /* This handles the middle-to-right-side of code generation for binary
diff --git a/gdb/eval.c b/gdb/eval.c
index f28c7ace8be..510a7b720cb 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1245,7 +1245,7 @@ eval_op_func_static_var (struct type *expect_type, struct expression *exp,
   return evaluate_var_value (noside, sym.block, sym.symbol);
 }
 
-static struct value *
+struct value *
 eval_op_register (struct type *expect_type, struct expression *exp,
 		  enum noside noside, const char *name)
 {
diff --git a/gdb/expop.h b/gdb/expop.h
index 110ad0a29ab..32b57a0fff7 100644
--- a/gdb/expop.h
+++ b/gdb/expop.h
@@ -57,6 +57,9 @@ extern struct value *eval_op_func_static_var (struct type *expect_type,
 					      struct expression *exp,
 					      enum noside noside,
 					      value *func, const char *var);
+extern struct value *eval_op_register (struct type *expect_type,
+				       struct expression *exp,
+				       enum noside noside, const char *name);
 
 namespace expr
 {
@@ -586,6 +589,33 @@ class last_operation
   { return OP_LAST; }
 };
 
+class register_operation
+  : public tuple_holding_operation<std::string>
+{
+public:
+
+  using tuple_holding_operation::tuple_holding_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override
+  {
+    return eval_op_register (expect_type, exp, noside,
+			     std::get<0> (m_storage).c_str ());
+  }
+
+  enum exp_opcode opcode () const override
+  { return OP_REGISTER; }
+
+protected:
+
+  void do_generate_ax (struct expression *exp,
+		       struct agent_expr *ax,
+		       struct axs_value *value,
+		       struct type *cast_type)
+    override;
+};
+
 } /* namespace expr */
 
 #endif /* EXPOP_H */
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 084/203] Introduce bool_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (82 preceding siblings ...)
  2021-01-01 21:45 ` [PATCH 083/203] Introduce register_operation Tom Tromey
@ 2021-01-01 21:45 ` Tom Tromey
  2021-01-01 21:45 ` [PATCH 085/203] Introduce internalvar_operation Tom Tromey
                   ` (119 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:45 UTC (permalink / raw)
  To: gdb-patches

This adds class bool_operation, which implements OP_BOOL.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* expop.h (class bool_operation): New.
---
 gdb/ChangeLog |  4 ++++
 gdb/expop.h   | 22 ++++++++++++++++++++++
 2 files changed, 26 insertions(+)

diff --git a/gdb/expop.h b/gdb/expop.h
index 32b57a0fff7..2c2f76d1da1 100644
--- a/gdb/expop.h
+++ b/gdb/expop.h
@@ -616,6 +616,28 @@ class register_operation
     override;
 };
 
+class bool_operation
+  : public tuple_holding_operation<bool>
+{
+public:
+
+  using tuple_holding_operation::tuple_holding_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override
+  {
+    struct type *type = language_bool_type (exp->language_defn, exp->gdbarch);
+    return value_from_longest (type, std::get<0> (m_storage));
+  }
+
+  enum exp_opcode opcode () const override
+  { return OP_BOOL; }
+
+  bool constant_p () const override
+  { return true; }
+};
+
 } /* namespace expr */
 
 #endif /* EXPOP_H */
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 085/203] Introduce internalvar_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (83 preceding siblings ...)
  2021-01-01 21:45 ` [PATCH 084/203] Introduce bool_operation Tom Tromey
@ 2021-01-01 21:45 ` Tom Tromey
  2021-01-01 21:45 ` [PATCH 086/203] Introduce string_operation Tom Tromey
                   ` (118 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:45 UTC (permalink / raw)
  To: gdb-patches

This adds class internalvar_operation, which implements
OP_INTERNALVAR.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* expop.h (class internalvar_operation): New.
	* ax-gdb.c (internalvar_operation::do_generate_ax): New method.
---
 gdb/ChangeLog |  5 +++++
 gdb/ax-gdb.c  | 25 +++++++++++++++++++++++++
 gdb/expop.h   | 32 ++++++++++++++++++++++++++++++++
 3 files changed, 62 insertions(+)

diff --git a/gdb/ax-gdb.c b/gdb/ax-gdb.c
index 5ffe5a00da1..e25e2942475 100644
--- a/gdb/ax-gdb.c
+++ b/gdb/ax-gdb.c
@@ -2365,6 +2365,31 @@ register_operation::do_generate_ax (struct expression *exp,
   value->type = register_type (ax->gdbarch, reg);
 }
 
+void
+internalvar_operation::do_generate_ax (struct expression *exp,
+				       struct agent_expr *ax,
+				       struct axs_value *value,
+				       struct type *cast_type)
+{
+  struct internalvar *var = std::get<0> (m_storage);
+  const char *name = internalvar_name (var);
+  struct trace_state_variable *tsv;
+
+  tsv = find_trace_state_variable (name);
+  if (tsv)
+    {
+      ax_tsv (ax, aop_getv, tsv->number);
+      if (ax->tracing)
+	ax_tsv (ax, aop_tracev, tsv->number);
+      /* Trace state variables are always 64-bit integers.  */
+      value->kind = axs_rvalue;
+      value->type = builtin_type (ax->gdbarch)->builtin_long_long;
+    }
+  else if (! compile_internalvar_to_ax (var, ax, value))
+    error (_("$%s is not a trace state variable; GDB agent "
+	     "expressions cannot use convenience variables."), name);
+}
+
 }
 
 /* This handles the middle-to-right-side of code generation for binary
diff --git a/gdb/expop.h b/gdb/expop.h
index 2c2f76d1da1..989d54d90ad 100644
--- a/gdb/expop.h
+++ b/gdb/expop.h
@@ -638,6 +638,38 @@ class bool_operation
   { return true; }
 };
 
+class internalvar_operation
+  : public tuple_holding_operation<internalvar *>
+{
+public:
+
+  using tuple_holding_operation::tuple_holding_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override
+  {
+    return value_of_internalvar (exp->gdbarch,
+				 std::get<0> (m_storage));
+  }
+
+  internalvar *get_internalvar () const
+  {
+    return std::get<0> (m_storage);
+  }
+
+  enum exp_opcode opcode () const override
+  { return OP_INTERNALVAR; }
+
+protected:
+
+  void do_generate_ax (struct expression *exp,
+		       struct agent_expr *ax,
+		       struct axs_value *value,
+		       struct type *cast_type)
+    override;
+};
+
 } /* namespace expr */
 
 #endif /* EXPOP_H */
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 086/203] Introduce string_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (84 preceding siblings ...)
  2021-01-01 21:45 ` [PATCH 085/203] Introduce internalvar_operation Tom Tromey
@ 2021-01-01 21:45 ` Tom Tromey
  2021-01-01 21:45 ` [PATCH 087/203] Introduce ternop_slice_operation Tom Tromey
                   ` (117 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:45 UTC (permalink / raw)
  To: gdb-patches

This adds string_operation, which implements OP_STRING for most
languages (C has its own variant).

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* expop.h (class string_operation): New.
	* eval.c (eval_op_string): No longer static.
---
 gdb/ChangeLog |  5 +++++
 gdb/eval.c    |  2 +-
 gdb/expop.h   | 24 ++++++++++++++++++++++++
 3 files changed, 30 insertions(+), 1 deletion(-)

diff --git a/gdb/eval.c b/gdb/eval.c
index 510a7b720cb..382eca04f15 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1273,7 +1273,7 @@ eval_op_register (struct type *expect_type, struct expression *exp,
     return val;
 }
 
-static struct value *
+struct value *
 eval_op_string (struct type *expect_type, struct expression *exp,
 		enum noside noside, int len, const char *string)
 {
diff --git a/gdb/expop.h b/gdb/expop.h
index 989d54d90ad..ff4e82150e6 100644
--- a/gdb/expop.h
+++ b/gdb/expop.h
@@ -60,6 +60,10 @@ extern struct value *eval_op_func_static_var (struct type *expect_type,
 extern struct value *eval_op_register (struct type *expect_type,
 				       struct expression *exp,
 				       enum noside noside, const char *name);
+extern struct value *eval_op_string (struct type *expect_type,
+				     struct expression *exp,
+				     enum noside noside, int len,
+				     const char *string);
 
 namespace expr
 {
@@ -670,6 +674,26 @@ class internalvar_operation
     override;
 };
 
+class string_operation
+  : public tuple_holding_operation<std::string>
+{
+public:
+
+  using tuple_holding_operation::tuple_holding_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override
+  {
+    const std::string &str = std::get<0> (m_storage);
+    return eval_op_string (expect_type, exp, noside,
+			   str.size (), str.c_str ());
+  }
+
+  enum exp_opcode opcode () const override
+  { return OP_STRING; }
+};
+
 } /* namespace expr */
 
 #endif /* EXPOP_H */
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 087/203] Introduce ternop_slice_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (85 preceding siblings ...)
  2021-01-01 21:45 ` [PATCH 086/203] Introduce string_operation Tom Tromey
@ 2021-01-01 21:45 ` Tom Tromey
  2021-01-01 21:45 ` [PATCH 088/203] Introduce ternop_cond_operation Tom Tromey
                   ` (116 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:45 UTC (permalink / raw)
  To: gdb-patches

This adds class ternop_slice_operation, which implements TERNOP_SLICE.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* expop.h (class ternop_slice_operation): New.
	* eval.c (eval_op_ternop): No longer static.
---
 gdb/ChangeLog |  5 +++++
 gdb/eval.c    |  2 +-
 gdb/expop.h   | 29 +++++++++++++++++++++++++++++
 3 files changed, 35 insertions(+), 1 deletion(-)

diff --git a/gdb/eval.c b/gdb/eval.c
index 382eca04f15..7968d008086 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1312,7 +1312,7 @@ eval_op_concat (struct type *expect_type, struct expression *exp,
 
 /* A helper function for TERNOP_SLICE.  */
 
-static struct value *
+struct value *
 eval_op_ternop (struct type *expect_type, struct expression *exp,
 		enum noside noside,
 		struct value *array, struct value *low, struct value *upper)
diff --git a/gdb/expop.h b/gdb/expop.h
index ff4e82150e6..49a03ce70c6 100644
--- a/gdb/expop.h
+++ b/gdb/expop.h
@@ -64,6 +64,11 @@ extern struct value *eval_op_string (struct type *expect_type,
 				     struct expression *exp,
 				     enum noside noside, int len,
 				     const char *string);
+extern struct value *eval_op_ternop (struct type *expect_type,
+				     struct expression *exp,
+				     enum noside noside,
+				     struct value *array, struct value *low,
+				     struct value *upper);
 
 namespace expr
 {
@@ -694,6 +699,30 @@ class string_operation
   { return OP_STRING; }
 };
 
+class ternop_slice_operation
+  : public maybe_constant_operation<operation_up, operation_up, operation_up>
+{
+public:
+
+  using maybe_constant_operation::maybe_constant_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override
+  {
+    struct value *array
+      = std::get<0> (m_storage)->evaluate (nullptr, exp, noside);
+    struct value *low
+      = std::get<1> (m_storage)->evaluate (nullptr, exp, noside);
+    struct value *upper
+      = std::get<2> (m_storage)->evaluate (nullptr, exp, noside);
+    return eval_op_ternop (expect_type, exp, noside, array, low, upper);
+  }
+
+  enum exp_opcode opcode () const override
+  { return TERNOP_SLICE; }
+};
+
 } /* namespace expr */
 
 #endif /* EXPOP_H */
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 088/203] Introduce ternop_cond_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (86 preceding siblings ...)
  2021-01-01 21:45 ` [PATCH 087/203] Introduce ternop_slice_operation Tom Tromey
@ 2021-01-01 21:45 ` Tom Tromey
  2021-01-01 21:45 ` [PATCH 089/203] Add c-exp.h and c_string_operation Tom Tromey
                   ` (115 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:45 UTC (permalink / raw)
  To: gdb-patches

This adds class ternop_cond_operation, which implements TERNOP_COND.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* expop.h (class ternop_cond_operation): New.
	* ax-gdb.c (ternop_cond_operation::do_generate_ax): New method.
---
 gdb/ChangeLog |  5 +++++
 gdb/ax-gdb.c  | 29 +++++++++++++++++++++++++++++
 gdb/expop.h   | 31 +++++++++++++++++++++++++++++++
 3 files changed, 65 insertions(+)

diff --git a/gdb/ax-gdb.c b/gdb/ax-gdb.c
index e25e2942475..87aa2107872 100644
--- a/gdb/ax-gdb.c
+++ b/gdb/ax-gdb.c
@@ -2390,6 +2390,35 @@ internalvar_operation::do_generate_ax (struct expression *exp,
 	     "expressions cannot use convenience variables."), name);
 }
 
+void
+ternop_cond_operation::do_generate_ax (struct expression *exp,
+				       struct agent_expr *ax,
+				       struct axs_value *value,
+				       struct type *cast_type)
+{
+  struct axs_value value1, value2, value3;
+  int if1, end;
+
+  std::get<0> (m_storage)->generate_ax (exp, ax, &value1);
+  gen_usual_unary (ax, &value1);
+  /* For (A ? B : C), it's easiest to generate subexpression
+     bytecodes in order, but if_goto jumps on true, so we invert
+     the sense of A.  Then we can do B by dropping through, and
+     jump to do C.  */
+  gen_logical_not (ax, &value1, builtin_type (ax->gdbarch)->builtin_int);
+  if1 = ax_goto (ax, aop_if_goto);
+  std::get<1> (m_storage)->generate_ax (exp, ax, &value2);
+  gen_usual_unary (ax, &value2);
+  end = ax_goto (ax, aop_goto);
+  ax_label (ax, if1, ax->len);
+  std::get<2> (m_storage)->generate_ax (exp, ax, &value3);
+  gen_usual_unary (ax, &value3);
+  ax_label (ax, end, ax->len);
+  /* This is arbitrary - what if B and C are incompatible types? */
+  value->type = value2.type;
+  value->kind = value2.kind;
+}
+
 }
 
 /* This handles the middle-to-right-side of code generation for binary
diff --git a/gdb/expop.h b/gdb/expop.h
index 49a03ce70c6..0bb9e081df0 100644
--- a/gdb/expop.h
+++ b/gdb/expop.h
@@ -723,6 +723,37 @@ class ternop_slice_operation
   { return TERNOP_SLICE; }
 };
 
+class ternop_cond_operation
+  : public maybe_constant_operation<operation_up, operation_up, operation_up>
+{
+public:
+
+  using maybe_constant_operation::maybe_constant_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override
+  {
+    struct value *val
+      = std::get<0> (m_storage)->evaluate (nullptr, exp, noside);
+
+    if (value_logical_not (val))
+      return std::get<2> (m_storage)->evaluate (nullptr, exp, noside);
+    return std::get<1> (m_storage)->evaluate (nullptr, exp, noside);
+  }
+
+  enum exp_opcode opcode () const override
+  { return TERNOP_COND; }
+
+protected:
+
+  void do_generate_ax (struct expression *exp,
+		       struct agent_expr *ax,
+		       struct axs_value *value,
+		       struct type *cast_type)
+    override;
+};
+
 } /* namespace expr */
 
 #endif /* EXPOP_H */
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 089/203] Add c-exp.h and c_string_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (87 preceding siblings ...)
  2021-01-01 21:45 ` [PATCH 088/203] Introduce ternop_cond_operation Tom Tromey
@ 2021-01-01 21:45 ` Tom Tromey
  2021-01-01 21:45 ` [PATCH 090/203] Introduce objc_nsstring_operation Tom Tromey
                   ` (114 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:45 UTC (permalink / raw)
  To: gdb-patches

This adds the new file c-exp.h, where C operation classes will be
declared.  The first such class, c_string_operation, is also added
here.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* c-lang.c (c_string_operation::evaluate): New method.
	* c-exp.h: New file.
---
 gdb/ChangeLog |   5 ++
 gdb/c-exp.h   |  46 ++++++++++++++++++
 gdb/c-lang.c  | 126 ++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 177 insertions(+)
 create mode 100644 gdb/c-exp.h

diff --git a/gdb/c-exp.h b/gdb/c-exp.h
new file mode 100644
index 00000000000..5558a773e98
--- /dev/null
+++ b/gdb/c-exp.h
@@ -0,0 +1,46 @@
+/* Definitions for C expressions
+
+   Copyright (C) 2020 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 C_EXP_H
+#define C_EXP_H
+
+#include "expop.h"
+
+namespace expr
+{
+
+class c_string_operation
+  : public tuple_holding_operation<enum c_string_type_values,
+				   std::vector<std::string>>
+{
+public:
+
+  using tuple_holding_operation::tuple_holding_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override;
+
+  enum exp_opcode opcode () const override
+  { return OP_STRING; }
+};
+
+}/* namespace expr */
+
+#endif /* C_EXP_H */
diff --git a/gdb/c-lang.c b/gdb/c-lang.c
index 91a04d78021..07a17b62567 100644
--- a/gdb/c-lang.c
+++ b/gdb/c-lang.c
@@ -36,6 +36,7 @@
 #include <ctype.h>
 #include "gdbcore.h"
 #include "gdbarch.h"
+#include "c-exp.h"
 
 class compile_instance;
 
@@ -729,6 +730,131 @@ evaluate_subexp_c (struct type *expect_type, struct expression *exp,
     }
   return evaluate_subexp_standard (expect_type, exp, pos, noside);
 }
+
+namespace expr
+{
+
+value *
+c_string_operation::evaluate (struct type *expect_type,
+			      struct expression *exp,
+			      enum noside noside)
+{
+  struct type *type;
+  struct value *result;
+  c_string_type dest_type;
+  const char *dest_charset;
+  int satisfy_expected = 0;
+
+  auto_obstack output;
+
+  dest_type = std::get<0> (m_storage);
+
+  switch (dest_type & ~C_CHAR)
+    {
+    case C_STRING:
+      type = language_string_char_type (exp->language_defn,
+					exp->gdbarch);
+      break;
+    case C_WIDE_STRING:
+      type = lookup_typename (exp->language_defn, "wchar_t", NULL, 0);
+      break;
+    case C_STRING_16:
+      type = lookup_typename (exp->language_defn, "char16_t", NULL, 0);
+      break;
+    case C_STRING_32:
+      type = lookup_typename (exp->language_defn, "char32_t", NULL, 0);
+      break;
+    default:
+      internal_error (__FILE__, __LINE__, _("unhandled c_string_type"));
+    }
+
+  /* Ensure TYPE_LENGTH is valid for TYPE.  */
+  check_typedef (type);
+
+  /* If the caller expects an array of some integral type,
+     satisfy them.  If something odder is expected, rely on the
+     caller to cast.  */
+  if (expect_type && expect_type->code () == TYPE_CODE_ARRAY)
+    {
+      struct type *element_type
+	= check_typedef (TYPE_TARGET_TYPE (expect_type));
+
+      if (element_type->code () == TYPE_CODE_INT
+	  || element_type->code () == TYPE_CODE_CHAR)
+	{
+	  type = element_type;
+	  satisfy_expected = 1;
+	}
+    }
+
+  dest_charset = charset_for_string_type (dest_type, exp->gdbarch);
+
+  if (noside != EVAL_SKIP)
+    {
+      for (const std::string &item : std::get<1> (m_storage))
+	parse_one_string (&output, item.c_str (), item.size (),
+			  dest_charset, type);
+    }
+
+  if (noside == EVAL_SKIP)
+    {
+      /* Return a dummy value of the appropriate type.  */
+      if (expect_type != NULL)
+	result = allocate_value (expect_type);
+      else if ((dest_type & C_CHAR) != 0)
+	result = allocate_value (type);
+      else
+	result = value_cstring ("", 0, type);
+      return result;
+    }
+
+  if ((dest_type & C_CHAR) != 0)
+    {
+      LONGEST value;
+
+      if (obstack_object_size (&output) != TYPE_LENGTH (type))
+	error (_("Could not convert character "
+		 "constant to target character set"));
+      value = unpack_long (type, (gdb_byte *) obstack_base (&output));
+      result = value_from_longest (type, value);
+    }
+  else
+    {
+      int i;
+
+      /* Write the terminating character.  */
+      for (i = 0; i < TYPE_LENGTH (type); ++i)
+	obstack_1grow (&output, 0);
+
+      if (satisfy_expected)
+	{
+	  LONGEST low_bound, high_bound;
+	  int element_size = TYPE_LENGTH (type);
+
+	  if (!get_discrete_bounds (expect_type->index_type (),
+				    &low_bound, &high_bound))
+	    {
+	      low_bound = 0;
+	      high_bound = (TYPE_LENGTH (expect_type) / element_size) - 1;
+	    }
+	  if (obstack_object_size (&output) / element_size
+	      > (high_bound - low_bound + 1))
+	    error (_("Too many array elements"));
+
+	  result = allocate_value (expect_type);
+	  memcpy (value_contents_raw (result), obstack_base (&output),
+		  obstack_object_size (&output));
+	}
+      else
+	result = value_cstring ((const char *) obstack_base (&output),
+				obstack_object_size (&output),
+				type);
+    }
+  return result;
+}
+
+} /* namespace expr */
+
 \f
 /* See c-lang.h.  */
 
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 090/203] Introduce objc_nsstring_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (88 preceding siblings ...)
  2021-01-01 21:45 ` [PATCH 089/203] Add c-exp.h and c_string_operation Tom Tromey
@ 2021-01-01 21:45 ` Tom Tromey
  2021-01-01 21:45 ` [PATCH 091/203] Introduce objc_selector_operation Tom Tromey
                   ` (113 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:45 UTC (permalink / raw)
  To: gdb-patches

This adds class objc_nsstring_operation, which implements
OP_OBJC_NSSTRING.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* eval.c: Include c-exp.h.
	* c-exp.h (class objc_nsstring_operation): New.
---
 gdb/ChangeLog |  5 +++++
 gdb/c-exp.h   | 22 ++++++++++++++++++++++
 gdb/eval.c    |  1 +
 3 files changed, 28 insertions(+)

diff --git a/gdb/c-exp.h b/gdb/c-exp.h
index 5558a773e98..a7b11b5a25d 100644
--- a/gdb/c-exp.h
+++ b/gdb/c-exp.h
@@ -21,6 +21,7 @@
 #define C_EXP_H
 
 #include "expop.h"
+#include "objc-lang.h"
 
 namespace expr
 {
@@ -41,6 +42,27 @@ class c_string_operation
   { return OP_STRING; }
 };
 
+class objc_nsstring_operation
+  : public tuple_holding_operation<std::string>
+{
+public:
+
+  using tuple_holding_operation::tuple_holding_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override
+  {
+    if (noside == EVAL_SKIP)
+      return eval_skip_value (exp);
+    const std::string &str = std::get<0> (m_storage);
+    return value_nsstring (exp->gdbarch, str.c_str (), str.size () + 1);
+  }
+
+  enum exp_opcode opcode () const override
+  { return OP_OBJC_NSSTRING; }
+};
+
 }/* namespace expr */
 
 #endif /* C_EXP_H */
diff --git a/gdb/eval.c b/gdb/eval.c
index 7968d008086..0b709ce17a2 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -41,6 +41,7 @@
 #include "typeprint.h"
 #include <ctype.h>
 #include "expop.h"
+#include "c-exp.h"
 
 /* Prototypes for local functions.  */
 
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 091/203] Introduce objc_selector_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (89 preceding siblings ...)
  2021-01-01 21:45 ` [PATCH 090/203] Introduce objc_nsstring_operation Tom Tromey
@ 2021-01-01 21:45 ` Tom Tromey
  2021-01-01 21:45 ` [PATCH 092/203] Introduce complex_operation Tom Tromey
                   ` (112 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:45 UTC (permalink / raw)
  To: gdb-patches

This adds class objc_selector_operation, which implements
OP_OBJC_SELECTOR.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* eval.c (eval_op_objc_selector): No longer static.
	* c-exp.h (class objc_selector_operation): New.
---
 gdb/ChangeLog |  5 +++++
 gdb/c-exp.h   | 25 +++++++++++++++++++++++++
 gdb/eval.c    |  2 +-
 3 files changed, 31 insertions(+), 1 deletion(-)

diff --git a/gdb/c-exp.h b/gdb/c-exp.h
index a7b11b5a25d..dcb4557b2d5 100644
--- a/gdb/c-exp.h
+++ b/gdb/c-exp.h
@@ -23,6 +23,10 @@
 #include "expop.h"
 #include "objc-lang.h"
 
+extern struct value *eval_op_objc_selector (struct type *expect_type,
+					    struct expression *exp,
+					    enum noside noside,
+					    const char *sel);
 namespace expr
 {
 
@@ -63,6 +67,27 @@ class objc_nsstring_operation
   { return OP_OBJC_NSSTRING; }
 };
 
+class objc_selector_operation
+  : public tuple_holding_operation<std::string>
+{
+public:
+
+  using tuple_holding_operation::tuple_holding_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override
+  {
+    if (noside == EVAL_SKIP)
+      return eval_skip_value (exp);
+    return eval_op_objc_selector (expect_type, exp, noside,
+				  std::get<0> (m_storage).c_str ());
+  }
+
+  enum exp_opcode opcode () const override
+  { return OP_OBJC_SELECTOR; }
+};
+
 }/* namespace expr */
 
 #endif /* C_EXP_H */
diff --git a/gdb/eval.c b/gdb/eval.c
index 0b709ce17a2..217e37b8530 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1285,7 +1285,7 @@ eval_op_string (struct type *expect_type, struct expression *exp,
   return value_string (string, len, type);
 }
 
-static struct value *
+struct value *
 eval_op_objc_selector (struct type *expect_type, struct expression *exp,
 		       enum noside noside,
 		       const char *sel)
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 092/203] Introduce complex_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (90 preceding siblings ...)
  2021-01-01 21:45 ` [PATCH 091/203] Introduce objc_selector_operation Tom Tromey
@ 2021-01-01 21:45 ` Tom Tromey
  2021-01-01 21:45 ` [PATCH 093/203] Introduce structop_operation Tom Tromey
                   ` (111 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:45 UTC (permalink / raw)
  To: gdb-patches

This adds class complex_operation, which implements OP_COMPLEX.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* expop.h (class complex_operation): New.
---
 gdb/ChangeLog |  4 ++++
 gdb/expop.h   | 21 +++++++++++++++++++++
 2 files changed, 25 insertions(+)

diff --git a/gdb/expop.h b/gdb/expop.h
index 0bb9e081df0..88ceb6033ac 100644
--- a/gdb/expop.h
+++ b/gdb/expop.h
@@ -754,6 +754,27 @@ class ternop_cond_operation
     override;
 };
 
+class complex_operation
+  : public maybe_constant_operation<operation_up, operation_up, struct type *>
+{
+public:
+
+  using maybe_constant_operation::maybe_constant_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override
+  {
+    value *real = std::get<0> (m_storage)->evaluate (nullptr, exp, noside);
+    value *imag = std::get<1> (m_storage)->evaluate (nullptr, exp, noside);
+    return value_literal_complex (real, imag,
+				  std::get<2> (m_storage));
+  }
+
+  enum exp_opcode opcode () const override
+  { return OP_COMPLEX; }
+};
+
 } /* namespace expr */
 
 #endif /* EXPOP_H */
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 093/203] Introduce structop_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (91 preceding siblings ...)
  2021-01-01 21:45 ` [PATCH 092/203] Introduce complex_operation Tom Tromey
@ 2021-01-01 21:45 ` Tom Tromey
  2021-01-01 21:45 ` [PATCH 094/203] Introduce structop_ptr_operation Tom Tromey
                   ` (110 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:45 UTC (permalink / raw)
  To: gdb-patches

This adds class structop_base_operation and structop_operation, which
implement STRUCTOP_STRUCT.  The base class exists to unify the
completion code between STRUCTOP_STRUCT and STRUCTOP_PTR.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* expop.h (class structop_base_operation)
	(class structop_operation): New.
	* eval.c (eval_op_structop_struct): No longer static.
---
 gdb/ChangeLog |  6 +++++
 gdb/eval.c    |  2 +-
 gdb/expop.h   | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 69 insertions(+), 1 deletion(-)

diff --git a/gdb/eval.c b/gdb/eval.c
index 217e37b8530..2da1cf5fdbc 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1327,7 +1327,7 @@ eval_op_ternop (struct type *expect_type, struct expression *exp,
 
 /* A helper function for STRUCTOP_STRUCT.  */
 
-static struct value *
+struct value *
 eval_op_structop_struct (struct type *expect_type, struct expression *exp,
 			 enum noside noside,
 			 struct value *arg1, const char *string)
diff --git a/gdb/expop.h b/gdb/expop.h
index 88ceb6033ac..c629614f5f1 100644
--- a/gdb/expop.h
+++ b/gdb/expop.h
@@ -69,6 +69,11 @@ extern struct value *eval_op_ternop (struct type *expect_type,
 				     enum noside noside,
 				     struct value *array, struct value *low,
 				     struct value *upper);
+extern struct value *eval_op_structop_struct (struct type *expect_type,
+					      struct expression *exp,
+					      enum noside noside,
+					      struct value *arg1,
+					      const char *string);
 
 namespace expr
 {
@@ -775,6 +780,63 @@ class complex_operation
   { return OP_COMPLEX; }
 };
 
+class structop_base_operation
+  : public tuple_holding_operation<operation_up, std::string>
+{
+public:
+
+  /* Used for completion.  Return the field name.  */
+  const std::string &get_string () const
+  {
+    return std::get<1> (m_storage);
+  }
+
+  /* Used for completion.  Evaluate the LHS for type.  */
+  value *evaluate_lhs (struct expression *exp)
+  {
+    return std::get<0> (m_storage)->evaluate (nullptr, exp,
+					      EVAL_AVOID_SIDE_EFFECTS);
+  }
+
+protected:
+
+  using tuple_holding_operation::tuple_holding_operation;
+};
+
+class structop_operation
+  : public structop_base_operation
+{
+public:
+
+  using structop_base_operation::structop_base_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override
+  {
+    value *val =std::get<0> (m_storage)->evaluate (nullptr, exp, noside);
+    return eval_op_structop_struct (expect_type, exp, noside, val,
+				    std::get<1> (m_storage).c_str ());
+  }
+
+  enum exp_opcode opcode () const override
+  { return STRUCTOP_STRUCT; }
+
+protected:
+
+  void do_generate_ax (struct expression *exp,
+		       struct agent_expr *ax,
+		       struct axs_value *value,
+		       struct type *cast_type)
+    override
+  {
+    gen_expr_structop (exp, STRUCTOP_STRUCT,
+		       std::get<0> (this->m_storage).get (),
+		       std::get<1> (this->m_storage).c_str (),
+		       ax, value);
+  }
+};
+
 } /* namespace expr */
 
 #endif /* EXPOP_H */
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 094/203] Introduce structop_ptr_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (92 preceding siblings ...)
  2021-01-01 21:45 ` [PATCH 093/203] Introduce structop_operation Tom Tromey
@ 2021-01-01 21:45 ` Tom Tromey
  2021-01-01 21:45 ` [PATCH 095/203] Introduce structop_member_operation and structop_mptr_operation Tom Tromey
                   ` (109 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:45 UTC (permalink / raw)
  To: gdb-patches

This adds class structop_ptr_operation, which implements STRUCTOP_PTR.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* expop.h (class structop_ptr_operation): New.
	* eval.c (eval_op_structop_ptr): No longer static.  Remove "op"
	parameter.
---
 gdb/ChangeLog |  6 ++++++
 gdb/eval.c    | 10 +++++-----
 gdb/expop.h   | 39 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 50 insertions(+), 5 deletions(-)

diff --git a/gdb/eval.c b/gdb/eval.c
index 2da1cf5fdbc..156ef8530ce 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1343,9 +1343,9 @@ eval_op_structop_struct (struct type *expect_type, struct expression *exp,
 
 /* A helper function for STRUCTOP_PTR.  */
 
-static struct value *
+struct value *
 eval_op_structop_ptr (struct type *expect_type, struct expression *exp,
-		      enum noside noside, enum exp_opcode op,
+		      enum noside noside,
 		      struct value *arg1, const char *string)
 {
   if (noside == EVAL_SKIP)
@@ -1353,12 +1353,12 @@ eval_op_structop_ptr (struct type *expect_type, struct expression *exp,
 
   /* Check to see if operator '->' has been overloaded.  If so replace
      arg1 with the value returned by evaluating operator->().  */
-  while (unop_user_defined_p (op, arg1))
+  while (unop_user_defined_p (STRUCTOP_PTR, arg1))
     {
       struct value *value = NULL;
       try
 	{
-	  value = value_x_unop (arg1, op, noside);
+	  value = value_x_unop (arg1, STRUCTOP_PTR, noside);
 	}
 
       catch (const gdb_exception_error &except)
@@ -2734,7 +2734,7 @@ evaluate_subexp_standard (struct type *expect_type,
       tem = longest_to_int (exp->elts[pc + 1].longconst);
       (*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1);
       arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      return eval_op_structop_ptr (expect_type, exp, noside, op, arg1,
+      return eval_op_structop_ptr (expect_type, exp, noside, arg1,
 				   &exp->elts[pc + 2].string);
 
     case STRUCTOP_MEMBER:
diff --git a/gdb/expop.h b/gdb/expop.h
index c629614f5f1..85d2eaf063a 100644
--- a/gdb/expop.h
+++ b/gdb/expop.h
@@ -74,6 +74,11 @@ extern struct value *eval_op_structop_struct (struct type *expect_type,
 					      enum noside noside,
 					      struct value *arg1,
 					      const char *string);
+extern struct value *eval_op_structop_ptr (struct type *expect_type,
+					   struct expression *exp,
+					   enum noside noside,
+					   struct value *arg1,
+					   const char *string);
 
 namespace expr
 {
@@ -837,6 +842,40 @@ class structop_operation
   }
 };
 
+class structop_ptr_operation
+  : public structop_base_operation
+{
+public:
+
+  using structop_base_operation::structop_base_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override
+  {
+    value *val = std::get<0> (m_storage)->evaluate (nullptr, exp, noside);
+    return eval_op_structop_ptr (expect_type, exp, noside, val,
+				 std::get<1> (m_storage).c_str ());
+  }
+
+  enum exp_opcode opcode () const override
+  { return STRUCTOP_PTR; }
+
+protected:
+
+  void do_generate_ax (struct expression *exp,
+		       struct agent_expr *ax,
+		       struct axs_value *value,
+		       struct type *cast_type)
+    override
+  {
+    gen_expr_structop (exp, STRUCTOP_PTR,
+		       std::get<0> (this->m_storage).get (),
+		       std::get<1> (this->m_storage).c_str (),
+		       ax, value);
+  }
+};
+
 } /* namespace expr */
 
 #endif /* EXPOP_H */
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 095/203] Introduce structop_member_operation and structop_mptr_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (93 preceding siblings ...)
  2021-01-01 21:45 ` [PATCH 094/203] Introduce structop_ptr_operation Tom Tromey
@ 2021-01-01 21:45 ` Tom Tromey
  2021-01-01 21:45 ` [PATCH 096/203] Introduce concat_operation Tom Tromey
                   ` (108 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:45 UTC (permalink / raw)
  To: gdb-patches

This adds class structop_member_operation and structop_mptr_operation,
which implement STRUCTOP_MEMBER and STRUCTOP_MPTR.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* expop.h (class structop_member_operation)
	(class structop_mptr_operation): New.
	* eval.c (eval_op_member): No longer static.
---
 gdb/ChangeLog |  6 ++++++
 gdb/eval.c    |  2 +-
 gdb/expop.h   | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 55 insertions(+), 1 deletion(-)

diff --git a/gdb/eval.c b/gdb/eval.c
index 156ef8530ce..3aa362db66c 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1402,7 +1402,7 @@ eval_op_structop_ptr (struct type *expect_type, struct expression *exp,
 
 /* A helper function for STRUCTOP_MEMBER.  */
 
-static struct value *
+struct value *
 eval_op_member (struct type *expect_type, struct expression *exp,
 		enum noside noside,
 		struct value *arg1, struct value *arg2)
diff --git a/gdb/expop.h b/gdb/expop.h
index 85d2eaf063a..bfb8f1db6f8 100644
--- a/gdb/expop.h
+++ b/gdb/expop.h
@@ -79,6 +79,10 @@ extern struct value *eval_op_structop_ptr (struct type *expect_type,
 					   enum noside noside,
 					   struct value *arg1,
 					   const char *string);
+extern struct value *eval_op_member (struct type *expect_type,
+				     struct expression *exp,
+				     enum noside noside,
+				     struct value *arg1, struct value *arg2);
 
 namespace expr
 {
@@ -876,6 +880,50 @@ class structop_ptr_operation
   }
 };
 
+class structop_member_operation
+  : public tuple_holding_operation<operation_up, operation_up>
+{
+public:
+
+  using tuple_holding_operation::tuple_holding_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override
+  {
+    value *lhs
+      = std::get<0> (m_storage)->evaluate_for_address (exp, noside);
+    value *rhs
+      = std::get<1> (m_storage)->evaluate (nullptr, exp, noside);
+    return eval_op_member (expect_type, exp, noside, lhs, rhs);
+  }
+
+  enum exp_opcode opcode () const override
+  { return STRUCTOP_MEMBER; }
+};
+
+class structop_mptr_operation
+  : public tuple_holding_operation<operation_up, operation_up>
+{
+public:
+
+  using tuple_holding_operation::tuple_holding_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override
+  {
+    value *lhs
+      = std::get<0> (m_storage)->evaluate (nullptr, exp, noside);
+    value *rhs
+      = std::get<1> (m_storage)->evaluate (nullptr, exp, noside);
+    return eval_op_member (expect_type, exp, noside, lhs, rhs);
+  }
+
+  enum exp_opcode opcode () const override
+  { return STRUCTOP_MPTR; }
+};
+
 } /* namespace expr */
 
 #endif /* EXPOP_H */
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 096/203] Introduce concat_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (94 preceding siblings ...)
  2021-01-01 21:45 ` [PATCH 095/203] Introduce structop_member_operation and structop_mptr_operation Tom Tromey
@ 2021-01-01 21:45 ` Tom Tromey
  2021-01-01 21:45 ` [PATCH 097/203] Introduce add_operation Tom Tromey
                   ` (107 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:45 UTC (permalink / raw)
  To: gdb-patches

This adds class concat_operation, which implements BINOP_CONCAT.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* expop.h (class concat_operation): New.
	* eval.c (eval_op_concat): No longer static.  Remove "op"
	parameter.
	(evaluate_subexp_standard): Update.
---
 gdb/ChangeLog |  7 +++++++
 gdb/eval.c    | 11 +++++------
 gdb/expop.h   | 26 ++++++++++++++++++++++++++
 3 files changed, 38 insertions(+), 6 deletions(-)

diff --git a/gdb/eval.c b/gdb/eval.c
index 3aa362db66c..3942e4afaf2 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1298,15 +1298,14 @@ eval_op_objc_selector (struct type *expect_type, struct expression *exp,
 			     lookup_child_selector (exp->gdbarch, sel));
 }
 
-static struct value *
+struct value *
 eval_op_concat (struct type *expect_type, struct expression *exp,
-		enum noside noside,
-		enum exp_opcode op, struct value *arg1, struct value *arg2)
+		enum noside noside, struct value *arg1, struct value *arg2)
 {
   if (noside == EVAL_SKIP)
     return eval_skip_value (exp);
-  if (binop_user_defined_p (op, arg1, arg2))
-    return value_x_binop (arg1, arg2, op, OP_NULL, noside);
+  if (binop_user_defined_p (BINOP_CONCAT, arg1, arg2))
+    return value_x_binop (arg1, arg2, BINOP_CONCAT, OP_NULL, noside);
   else
     return value_concat (arg1, arg2);
 }
@@ -2766,7 +2765,7 @@ evaluate_subexp_standard (struct type *expect_type,
     case BINOP_CONCAT:
       arg1 = evaluate_subexp_with_coercion (exp, pos, noside);
       arg2 = evaluate_subexp_with_coercion (exp, pos, noside);
-      return eval_op_concat (expect_type, exp, noside, op, arg1, arg2);
+      return eval_op_concat (expect_type, exp, noside, arg1, arg2);
 
     case BINOP_ASSIGN:
       arg1 = evaluate_subexp (nullptr, exp, pos, noside);
diff --git a/gdb/expop.h b/gdb/expop.h
index bfb8f1db6f8..9b7119b9e92 100644
--- a/gdb/expop.h
+++ b/gdb/expop.h
@@ -83,6 +83,10 @@ extern struct value *eval_op_member (struct type *expect_type,
 				     struct expression *exp,
 				     enum noside noside,
 				     struct value *arg1, struct value *arg2);
+extern struct value *eval_op_concat (struct type *expect_type,
+				     struct expression *exp,
+				     enum noside noside,
+				     struct value *arg1, struct value *arg2);
 
 namespace expr
 {
@@ -924,6 +928,28 @@ class structop_mptr_operation
   { return STRUCTOP_MPTR; }
 };
 
+class concat_operation
+  : public maybe_constant_operation<operation_up, operation_up>
+{
+public:
+
+  using maybe_constant_operation::maybe_constant_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override
+  {
+    value *lhs
+      = std::get<0> (m_storage)->evaluate_with_coercion (exp, noside);
+    value *rhs
+      = std::get<1> (m_storage)->evaluate_with_coercion (exp, noside);
+    return eval_op_concat (expect_type, exp, noside, lhs, rhs);
+  }
+
+  enum exp_opcode opcode () const override
+  { return BINOP_CONCAT; }
+};
+
 } /* namespace expr */
 
 #endif /* EXPOP_H */
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 097/203] Introduce add_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (95 preceding siblings ...)
  2021-01-01 21:45 ` [PATCH 096/203] Introduce concat_operation Tom Tromey
@ 2021-01-01 21:45 ` Tom Tromey
  2021-01-01 21:45 ` [PATCH 098/203] Introduce sub_operation Tom Tromey
                   ` (106 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:45 UTC (permalink / raw)
  To: gdb-patches

This adds class add_operation, which implements BINOP_ADD.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* expop.h (class add_operation): New.
	* eval.c (eval_op_add): No longer static.  Remove "op" parameter.
	(evaluate_subexp_standard): Update.
---
 gdb/ChangeLog |  6 ++++++
 gdb/eval.c    | 10 +++++-----
 gdb/expop.h   | 40 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 51 insertions(+), 5 deletions(-)

diff --git a/gdb/eval.c b/gdb/eval.c
index 3942e4afaf2..305143134c5 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1444,15 +1444,15 @@ eval_op_member (struct type *expect_type, struct expression *exp,
 
 /* A helper function for BINOP_ADD.  */
 
-static struct value *
+struct value *
 eval_op_add (struct type *expect_type, struct expression *exp,
-	     enum noside noside, enum exp_opcode op,
+	     enum noside noside,
 	     struct value *arg1, struct value *arg2)
 {
   if (noside == EVAL_SKIP)
     return eval_skip_value (exp);
-  if (binop_user_defined_p (op, arg1, arg2))
-    return value_x_binop (arg1, arg2, op, OP_NULL, noside);
+  if (binop_user_defined_p (BINOP_ADD, arg1, arg2))
+    return value_x_binop (arg1, arg2, BINOP_ADD, OP_NULL, noside);
   else if (ptrmath_type_p (exp->language_defn, value_type (arg1))
 	   && is_integral_or_integral_reference (value_type (arg2)))
     return value_ptradd (arg1, value_as_long (arg2));
@@ -2797,7 +2797,7 @@ evaluate_subexp_standard (struct type *expect_type,
     case BINOP_ADD:
       arg1 = evaluate_subexp_with_coercion (exp, pos, noside);
       arg2 = evaluate_subexp_with_coercion (exp, pos, noside);
-      return eval_op_add (expect_type, exp, noside, op, arg1, arg2);
+      return eval_op_add (expect_type, exp, noside, arg1, arg2);
 
     case BINOP_SUB:
       arg1 = evaluate_subexp_with_coercion (exp, pos, noside);
diff --git a/gdb/expop.h b/gdb/expop.h
index 9b7119b9e92..a571a262775 100644
--- a/gdb/expop.h
+++ b/gdb/expop.h
@@ -87,6 +87,10 @@ extern struct value *eval_op_concat (struct type *expect_type,
 				     struct expression *exp,
 				     enum noside noside,
 				     struct value *arg1, struct value *arg2);
+extern struct value *eval_op_add (struct type *expect_type,
+				  struct expression *exp,
+				  enum noside noside,
+				  struct value *arg1, struct value *arg2);
 
 namespace expr
 {
@@ -950,6 +954,42 @@ class concat_operation
   { return BINOP_CONCAT; }
 };
 
+class add_operation
+  : public maybe_constant_operation<operation_up, operation_up>
+{
+public:
+
+  using maybe_constant_operation::maybe_constant_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override
+  {
+    value *lhs
+      = std::get<0> (m_storage)->evaluate_with_coercion (exp, noside);
+    value *rhs
+      = std::get<1> (m_storage)->evaluate_with_coercion (exp, noside);
+    return eval_op_add (expect_type, exp, noside, lhs, rhs);
+  }
+
+  enum exp_opcode opcode () const override
+  { return BINOP_ADD; }
+
+protected:
+
+  void do_generate_ax (struct expression *exp,
+		       struct agent_expr *ax,
+		       struct axs_value *value,
+		       struct type *cast_type)
+    override
+  {
+    gen_expr_binop (exp, BINOP_ADD,
+		    std::get<0> (this->m_storage).get (),
+		    std::get<1> (this->m_storage).get (),
+		    ax, value);
+  }
+};
+
 } /* namespace expr */
 
 #endif /* EXPOP_H */
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 098/203] Introduce sub_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (96 preceding siblings ...)
  2021-01-01 21:45 ` [PATCH 097/203] Introduce add_operation Tom Tromey
@ 2021-01-01 21:45 ` Tom Tromey
  2021-01-01 21:45 ` [PATCH 099/203] Introduce binop_operation Tom Tromey
                   ` (105 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:45 UTC (permalink / raw)
  To: gdb-patches

This adds class sub_operation, which implements BINOP_SUB.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* expop.h (class sub_operation): New.
	* eval.c (eval_op_sub): No longer static.  Remove "op" parameter.
	(evaluate_subexp_standard): Update.
---
 gdb/ChangeLog |  6 ++++++
 gdb/eval.c    | 10 +++++-----
 gdb/expop.h   | 40 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 51 insertions(+), 5 deletions(-)

diff --git a/gdb/eval.c b/gdb/eval.c
index 305143134c5..ba47f6d999d 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1468,15 +1468,15 @@ eval_op_add (struct type *expect_type, struct expression *exp,
 
 /* A helper function for BINOP_SUB.  */
 
-static struct value *
+struct value *
 eval_op_sub (struct type *expect_type, struct expression *exp,
-	     enum noside noside, enum exp_opcode op,
+	     enum noside noside,
 	     struct value *arg1, struct value *arg2)
 {
   if (noside == EVAL_SKIP)
     return eval_skip_value (exp);
-  if (binop_user_defined_p (op, arg1, arg2))
-    return value_x_binop (arg1, arg2, op, OP_NULL, noside);
+  if (binop_user_defined_p (BINOP_SUB, arg1, arg2))
+    return value_x_binop (arg1, arg2, BINOP_SUB, OP_NULL, noside);
   else if (ptrmath_type_p (exp->language_defn, value_type (arg1))
 	   && ptrmath_type_p (exp->language_defn, value_type (arg2)))
     {
@@ -2802,7 +2802,7 @@ evaluate_subexp_standard (struct type *expect_type,
     case BINOP_SUB:
       arg1 = evaluate_subexp_with_coercion (exp, pos, noside);
       arg2 = evaluate_subexp_with_coercion (exp, pos, noside);
-      return eval_op_sub (expect_type, exp, noside, op, arg1, arg2);
+      return eval_op_sub (expect_type, exp, noside, arg1, arg2);
 
     case BINOP_EXP:
     case BINOP_MUL:
diff --git a/gdb/expop.h b/gdb/expop.h
index a571a262775..2e846668282 100644
--- a/gdb/expop.h
+++ b/gdb/expop.h
@@ -91,6 +91,10 @@ extern struct value *eval_op_add (struct type *expect_type,
 				  struct expression *exp,
 				  enum noside noside,
 				  struct value *arg1, struct value *arg2);
+extern struct value *eval_op_sub (struct type *expect_type,
+				  struct expression *exp,
+				  enum noside noside,
+				  struct value *arg1, struct value *arg2);
 
 namespace expr
 {
@@ -990,6 +994,42 @@ class add_operation
   }
 };
 
+class sub_operation
+  : public maybe_constant_operation<operation_up, operation_up>
+{
+public:
+
+  using maybe_constant_operation::maybe_constant_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override
+  {
+    value *lhs
+      = std::get<0> (m_storage)->evaluate_with_coercion (exp, noside);
+    value *rhs
+      = std::get<1> (m_storage)->evaluate_with_coercion (exp, noside);
+    return eval_op_sub (expect_type, exp, noside, lhs, rhs);
+  }
+
+  enum exp_opcode opcode () const override
+  { return BINOP_SUB; }
+
+protected:
+
+  void do_generate_ax (struct expression *exp,
+		       struct agent_expr *ax,
+		       struct axs_value *value,
+		       struct type *cast_type)
+    override
+  {
+    gen_expr_binop (exp, BINOP_SUB,
+		    std::get<0> (this->m_storage).get (),
+		    std::get<1> (this->m_storage).get (),
+		    ax, value);
+  }
+};
+
 } /* namespace expr */
 
 #endif /* EXPOP_H */
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 099/203] Introduce binop_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (97 preceding siblings ...)
  2021-01-01 21:45 ` [PATCH 098/203] Introduce sub_operation Tom Tromey
@ 2021-01-01 21:45 ` Tom Tromey
  2021-01-01 21:45 ` [PATCH 100/203] Introduce subscript_operation Tom Tromey
                   ` (104 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:45 UTC (permalink / raw)
  To: gdb-patches

This adds two new template classes, binop_operation and
usual_ax_binop_operation, and then uses these to implement a number of
binary operations that follow similar patterns.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* expop.h (class binop_operation, class usual_ax_binop_operation):
	New.
	(exp_operation, intdiv_operation, mod_operation, mul_operation)
	(div_operation, rem_operation, lsh_operation, rsh_operation)
	(bitwise_and_operation, bitwise_ior_operation)
	(bitwise_xor_operation): New typedefs.
	* eval.c (eval_op_binary): No longer static.
---
 gdb/ChangeLog | 10 ++++++++
 gdb/eval.c    |  2 +-
 gdb/expop.h   | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 82 insertions(+), 1 deletion(-)

diff --git a/gdb/eval.c b/gdb/eval.c
index ba47f6d999d..282abc910ce 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1496,7 +1496,7 @@ eval_op_sub (struct type *expect_type, struct expression *exp,
 
 /* Helper function for several different binary operations.  */
 
-static struct value *
+struct value *
 eval_op_binary (struct type *expect_type, struct expression *exp,
 		enum noside noside, enum exp_opcode op,
 		struct value *arg1, struct value *arg2)
diff --git a/gdb/expop.h b/gdb/expop.h
index 2e846668282..f4a33f491e3 100644
--- a/gdb/expop.h
+++ b/gdb/expop.h
@@ -95,6 +95,10 @@ extern struct value *eval_op_sub (struct type *expect_type,
 				  struct expression *exp,
 				  enum noside noside,
 				  struct value *arg1, struct value *arg2);
+extern struct value *eval_op_binary (struct type *expect_type,
+				     struct expression *exp,
+				     enum noside noside, enum exp_opcode op,
+				     struct value *arg1, struct value *arg2);
 
 namespace expr
 {
@@ -1030,6 +1034,73 @@ class sub_operation
   }
 };
 
+typedef struct value *binary_ftype (struct type *expect_type,
+				    struct expression *exp,
+				    enum noside noside, enum exp_opcode op,
+				    struct value *arg1, struct value *arg2);
+
+template<enum exp_opcode OP, binary_ftype FUNC>
+class binop_operation
+  : public maybe_constant_operation<operation_up, operation_up>
+{
+public:
+
+  using maybe_constant_operation::maybe_constant_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override
+  {
+    value *lhs
+      = std::get<0> (m_storage)->evaluate (nullptr, exp, noside);
+    value *rhs
+      = std::get<1> (m_storage)->evaluate (nullptr, exp, noside);
+    return FUNC (expect_type, exp, noside, OP, lhs, rhs);
+  }
+
+  enum exp_opcode opcode () const override
+  { return OP; }
+};
+
+template<enum exp_opcode OP, binary_ftype FUNC>
+class usual_ax_binop_operation
+  : public binop_operation<OP, FUNC>
+{
+public:
+
+  using binop_operation<OP, FUNC>::binop_operation;
+
+protected:
+
+  void do_generate_ax (struct expression *exp,
+		       struct agent_expr *ax,
+		       struct axs_value *value,
+		       struct type *cast_type)
+    override
+  {
+    gen_expr_binop (exp, OP,
+		    std::get<0> (this->m_storage).get (),
+		    std::get<1> (this->m_storage).get (),
+		    ax, value);
+  }
+};
+
+using exp_operation = binop_operation<BINOP_EXP, eval_op_binary>;
+using intdiv_operation = binop_operation<BINOP_INTDIV, eval_op_binary>;
+using mod_operation = binop_operation<BINOP_MOD, eval_op_binary>;
+
+using mul_operation = usual_ax_binop_operation<BINOP_MUL, eval_op_binary>;
+using div_operation = usual_ax_binop_operation<BINOP_DIV, eval_op_binary>;
+using rem_operation = usual_ax_binop_operation<BINOP_REM, eval_op_binary>;
+using lsh_operation = usual_ax_binop_operation<BINOP_LSH, eval_op_binary>;
+using rsh_operation = usual_ax_binop_operation<BINOP_RSH, eval_op_binary>;
+using bitwise_and_operation
+     = usual_ax_binop_operation<BINOP_BITWISE_AND, eval_op_binary>;
+using bitwise_ior_operation
+     = usual_ax_binop_operation<BINOP_BITWISE_IOR, eval_op_binary>;
+using bitwise_xor_operation
+     = usual_ax_binop_operation<BINOP_BITWISE_XOR, eval_op_binary>;
+
 } /* namespace expr */
 
 #endif /* EXPOP_H */
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 100/203] Introduce subscript_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (98 preceding siblings ...)
  2021-01-01 21:45 ` [PATCH 099/203] Introduce binop_operation Tom Tromey
@ 2021-01-01 21:45 ` Tom Tromey
  2021-01-01 21:45 ` [PATCH 101/203] Implement binary comparison operations Tom Tromey
                   ` (103 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:45 UTC (permalink / raw)
  To: gdb-patches

This adds class subscript_operation, which implements BINOP_SUBSCRIPT.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* expop.h (class subscript_operation): New.
	* eval.c (eval_op_subscript): No longer static.
---
 gdb/ChangeLog |  5 +++++
 gdb/eval.c    | 35 ++++++++++++++++++++++++++++++++++-
 gdb/expop.h   | 16 ++++++++++++++++
 3 files changed, 55 insertions(+), 1 deletion(-)

diff --git a/gdb/eval.c b/gdb/eval.c
index 282abc910ce..e67842dea57 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1543,7 +1543,7 @@ eval_op_binary (struct type *expect_type, struct expression *exp,
 
 /* A helper function for BINOP_SUBSCRIPT.  */
 
-static struct value *
+struct value *
 eval_op_subscript (struct type *expect_type, struct expression *exp,
 		   enum noside noside, enum exp_opcode op,
 		   struct value *arg1, struct value *arg2)
@@ -3511,6 +3511,39 @@ var_msym_value_operation::evaluate_for_sizeof (struct expression *exp,
   return value_from_longest (size_type, TYPE_LENGTH (type));
 }
 
+value *
+subscript_operation::evaluate_for_sizeof (struct expression *exp,
+					  enum noside noside)
+{
+  if (noside == EVAL_NORMAL)
+    {
+      value *val = std::get<0> (m_storage)->evaluate (nullptr, exp,
+						      EVAL_AVOID_SIDE_EFFECTS);
+      struct type *type = check_typedef (value_type (val));
+      if (type->code () == TYPE_CODE_ARRAY)
+	{
+	  type = check_typedef (TYPE_TARGET_TYPE (type));
+	  if (type->code () == TYPE_CODE_ARRAY)
+	    {
+	      type = type->index_type ();
+	      /* Only re-evaluate the right hand side if the resulting type
+		 is a variable length type.  */
+	      if (type->bounds ()->flag_bound_evaluated)
+		{
+		  val = evaluate (nullptr, exp, EVAL_NORMAL);
+		  /* FIXME: This should be size_t.  */
+		  struct type *size_type
+		    = builtin_type (exp->gdbarch)->builtin_int;
+		  return value_from_longest
+		    (size_type, (LONGEST) TYPE_LENGTH (value_type (val)));
+		}
+	    }
+	}
+    }
+
+  return operation::evaluate_for_sizeof (exp, noside);
+}
+
 }
 
 /* Evaluate a subexpression of EXP, at index *POS, and return a value
diff --git a/gdb/expop.h b/gdb/expop.h
index f4a33f491e3..556ceaa1e87 100644
--- a/gdb/expop.h
+++ b/gdb/expop.h
@@ -99,6 +99,11 @@ extern struct value *eval_op_binary (struct type *expect_type,
 				     struct expression *exp,
 				     enum noside noside, enum exp_opcode op,
 				     struct value *arg1, struct value *arg2);
+extern struct value *eval_op_subscript (struct type *expect_type,
+					struct expression *exp,
+					enum noside noside, enum exp_opcode op,
+					struct value *arg1,
+					struct value *arg2);
 
 namespace expr
 {
@@ -1101,6 +1106,17 @@ using bitwise_ior_operation
 using bitwise_xor_operation
      = usual_ax_binop_operation<BINOP_BITWISE_XOR, eval_op_binary>;
 
+class subscript_operation
+  : public usual_ax_binop_operation<BINOP_SUBSCRIPT, eval_op_subscript>
+{
+public:
+  using usual_ax_binop_operation<BINOP_SUBSCRIPT,
+				 eval_op_subscript>::usual_ax_binop_operation;
+
+  value *evaluate_for_sizeof (struct expression *exp,
+			      enum noside noside) override;
+};
+
 } /* namespace expr */
 
 #endif /* EXPOP_H */
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 101/203] Implement binary comparison operations
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (99 preceding siblings ...)
  2021-01-01 21:45 ` [PATCH 100/203] Introduce subscript_operation Tom Tromey
@ 2021-01-01 21:45 ` Tom Tromey
  2021-01-01 21:45 ` [PATCH 102/203] Introduce repeat_operation Tom Tromey
                   ` (102 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:45 UTC (permalink / raw)
  To: gdb-patches

This implements the binary comparison operations via a template class.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* expop.h (class comparison_operation): New.
	(equal_operation, notequal_operation, less_operation)
	(gtr_operation, geq_operation, leq_operation): New typedefs.
	* eval.c (eval_op_equal, eval_op_notequal, eval_op_less)
	(eval_op_gtr, eval_op_geq, eval_op_leq): No longer static.
---
 gdb/ChangeLog |  8 +++++++
 gdb/eval.c    | 12 +++++------
 gdb/expop.h   | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 74 insertions(+), 6 deletions(-)

diff --git a/gdb/eval.c b/gdb/eval.c
index e67842dea57..e9c4a1fffd0 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1579,7 +1579,7 @@ eval_op_subscript (struct type *expect_type, struct expression *exp,
 
 /* A helper function for BINOP_EQUAL.  */
 
-static struct value *
+struct value *
 eval_op_equal (struct type *expect_type, struct expression *exp,
 	       enum noside noside, enum exp_opcode op,
 	       struct value *arg1, struct value *arg2)
@@ -1602,7 +1602,7 @@ eval_op_equal (struct type *expect_type, struct expression *exp,
 
 /* A helper function for BINOP_NOTEQUAL.  */
 
-static struct value *
+struct value *
 eval_op_notequal (struct type *expect_type, struct expression *exp,
 		  enum noside noside, enum exp_opcode op,
 		  struct value *arg1, struct value *arg2)
@@ -1625,7 +1625,7 @@ eval_op_notequal (struct type *expect_type, struct expression *exp,
 
 /* A helper function for BINOP_LESS.  */
 
-static struct value *
+struct value *
 eval_op_less (struct type *expect_type, struct expression *exp,
 	      enum noside noside, enum exp_opcode op,
 	      struct value *arg1, struct value *arg2)
@@ -1648,7 +1648,7 @@ eval_op_less (struct type *expect_type, struct expression *exp,
 
 /* A helper function for BINOP_GTR.  */
 
-static struct value *
+struct value *
 eval_op_gtr (struct type *expect_type, struct expression *exp,
 	     enum noside noside, enum exp_opcode op,
 	     struct value *arg1, struct value *arg2)
@@ -1671,7 +1671,7 @@ eval_op_gtr (struct type *expect_type, struct expression *exp,
 
 /* A helper function for BINOP_GEQ.  */
 
-static struct value *
+struct value *
 eval_op_geq (struct type *expect_type, struct expression *exp,
 	     enum noside noside, enum exp_opcode op,
 	     struct value *arg1, struct value *arg2)
@@ -1694,7 +1694,7 @@ eval_op_geq (struct type *expect_type, struct expression *exp,
 
 /* A helper function for BINOP_LEQ.  */
 
-static struct value *
+struct value *
 eval_op_leq (struct type *expect_type, struct expression *exp,
 	     enum noside noside, enum exp_opcode op,
 	     struct value *arg1, struct value *arg2)
diff --git a/gdb/expop.h b/gdb/expop.h
index 556ceaa1e87..27264562a4e 100644
--- a/gdb/expop.h
+++ b/gdb/expop.h
@@ -104,6 +104,36 @@ extern struct value *eval_op_subscript (struct type *expect_type,
 					enum noside noside, enum exp_opcode op,
 					struct value *arg1,
 					struct value *arg2);
+extern struct value *eval_op_equal (struct type *expect_type,
+				    struct expression *exp,
+				    enum noside noside, enum exp_opcode op,
+				    struct value *arg1,
+				    struct value *arg2);
+extern struct value *eval_op_notequal (struct type *expect_type,
+				       struct expression *exp,
+				       enum noside noside, enum exp_opcode op,
+				       struct value *arg1,
+				       struct value *arg2);
+extern struct value *eval_op_less (struct type *expect_type,
+				   struct expression *exp,
+				   enum noside noside, enum exp_opcode op,
+				   struct value *arg1,
+				   struct value *arg2);
+extern struct value *eval_op_gtr (struct type *expect_type,
+				  struct expression *exp,
+				  enum noside noside, enum exp_opcode op,
+				  struct value *arg1,
+				  struct value *arg2);
+extern struct value *eval_op_geq (struct type *expect_type,
+				  struct expression *exp,
+				  enum noside noside, enum exp_opcode op,
+				  struct value *arg1,
+				  struct value *arg2);
+extern struct value *eval_op_leq (struct type *expect_type,
+				  struct expression *exp,
+				  enum noside noside, enum exp_opcode op,
+				  struct value *arg1,
+				  struct value *arg2);
 
 namespace expr
 {
@@ -1117,6 +1147,36 @@ class subscript_operation
 			      enum noside noside) override;
 };
 
+/* Implementation of comparison operations.  */
+template<enum exp_opcode OP, binary_ftype FUNC>
+class comparison_operation
+  : public usual_ax_binop_operation<OP, FUNC>
+{
+public:
+
+  using usual_ax_binop_operation<OP, FUNC>::usual_ax_binop_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override
+  {
+    value *lhs
+      = std::get<0> (this->m_storage)->evaluate (nullptr, exp, noside);
+    value *rhs
+      = std::get<1> (this->m_storage)->evaluate (value_type (lhs), exp,
+						 noside);
+    return FUNC (expect_type, exp, noside, OP, lhs, rhs);
+  }
+};
+
+using equal_operation = comparison_operation<BINOP_EQUAL, eval_op_equal>;
+using notequal_operation
+     = comparison_operation<BINOP_NOTEQUAL, eval_op_notequal>;
+using less_operation = comparison_operation<BINOP_LESS, eval_op_less>;
+using gtr_operation = comparison_operation<BINOP_GTR, eval_op_gtr>;
+using geq_operation = comparison_operation<BINOP_GEQ, eval_op_geq>;
+using leq_operation = comparison_operation<BINOP_LEQ, eval_op_leq>;
+
 } /* namespace expr */
 
 #endif /* EXPOP_H */
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 102/203] Introduce repeat_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (100 preceding siblings ...)
  2021-01-01 21:45 ` [PATCH 101/203] Implement binary comparison operations Tom Tromey
@ 2021-01-01 21:45 ` Tom Tromey
  2021-01-01 21:45 ` [PATCH 103/203] Introduce comma_operation Tom Tromey
                   ` (101 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:45 UTC (permalink / raw)
  To: gdb-patches

This adds class repeat_operation, which implements BINOP_REPEAT.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* expop.h (class repeat_operation): New.
	* eval.c (eval_op_repeat): No longer static.  Remove "op"
	parameter.
	(evaluate_subexp_standard): Update.
	* ax-gdb.c (repeat_operation::do_generate_ax): New method.
---
 gdb/ChangeLog |  8 ++++++++
 gdb/ax-gdb.c  | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/eval.c    |  6 +++---
 gdb/expop.h   | 20 ++++++++++++++++++++
 4 files changed, 81 insertions(+), 3 deletions(-)

diff --git a/gdb/ax-gdb.c b/gdb/ax-gdb.c
index 87aa2107872..332840456fe 100644
--- a/gdb/ax-gdb.c
+++ b/gdb/ax-gdb.c
@@ -2419,6 +2419,56 @@ ternop_cond_operation::do_generate_ax (struct expression *exp,
   value->kind = value2.kind;
 }
 
+/* Generate code for GDB's magical `repeat' operator.
+   LVALUE @ INT creates an array INT elements long, and whose elements
+   have the same type as LVALUE, located in memory so that LVALUE is
+   its first element.  For example, argv[0]@argc gives you the array
+   of command-line arguments.
+
+   Unfortunately, because we have to know the types before we actually
+   have a value for the expression, we can't implement this perfectly
+   without changing the type system, having values that occupy two
+   stack slots, doing weird things with sizeof, etc.  So we require
+   the right operand to be a constant expression.  */
+void
+repeat_operation::do_generate_ax (struct expression *exp,
+				  struct agent_expr *ax,
+				  struct axs_value *value,
+				  struct type *cast_type)
+{
+  struct axs_value value1;
+
+  /* We don't want to turn this into an rvalue, so no conversions
+     here.  */
+  std::get<0> (m_storage)->generate_ax (exp, ax, &value1);
+  if (value1.kind != axs_lvalue_memory)
+    error (_("Left operand of `@' must be an object in memory."));
+
+  /* Evaluate the length; it had better be a constant.  */
+  if (!std::get<1> (m_storage)->constant_p ())
+    error (_("Right operand of `@' must be a "
+	     "constant, in agent expressions."));
+
+  struct value *v
+    = std::get<1> (m_storage)->evaluate (nullptr, exp,
+					 EVAL_AVOID_SIDE_EFFECTS);
+  if (value_type (v)->code () != TYPE_CODE_INT)
+    error (_("Right operand of `@' must be an integer."));
+  int length = value_as_long (v);
+  if (length <= 0)
+    error (_("Right operand of `@' must be positive."));
+
+  /* The top of the stack is already the address of the object, so
+     all we need to do is frob the type of the lvalue.  */
+  /* FIXME-type-allocation: need a way to free this type when we are
+     done with it.  */
+  struct type *array
+    = lookup_array_range_type (value1.type, 0, length - 1);
+
+  value->kind = axs_lvalue_memory;
+  value->type = array;
+}
+
 }
 
 /* This handles the middle-to-right-side of code generation for binary
diff --git a/gdb/eval.c b/gdb/eval.c
index e9c4a1fffd0..06f4c67e1d7 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1717,9 +1717,9 @@ eval_op_leq (struct type *expect_type, struct expression *exp,
 
 /* A helper function for BINOP_REPEAT.  */
 
-static struct value *
+struct value *
 eval_op_repeat (struct type *expect_type, struct expression *exp,
-		enum noside noside,
+		enum noside noside, enum exp_opcode op,
 		struct value *arg1, struct value *arg2)
 {
   if (noside == EVAL_SKIP)
@@ -2921,7 +2921,7 @@ evaluate_subexp_standard (struct type *expect_type,
     case BINOP_REPEAT:
       arg1 = evaluate_subexp (nullptr, exp, pos, noside);
       arg2 = evaluate_subexp (nullptr, exp, pos, noside);
-      return eval_op_repeat (expect_type, exp, noside, arg1, arg2);
+      return eval_op_repeat (expect_type, exp, noside, op, arg1, arg2);
 
     case BINOP_COMMA:
       evaluate_subexp (nullptr, exp, pos, noside);
diff --git a/gdb/expop.h b/gdb/expop.h
index 27264562a4e..419ce05abaf 100644
--- a/gdb/expop.h
+++ b/gdb/expop.h
@@ -134,6 +134,11 @@ extern struct value *eval_op_leq (struct type *expect_type,
 				  enum noside noside, enum exp_opcode op,
 				  struct value *arg1,
 				  struct value *arg2);
+extern struct value *eval_op_repeat (struct type *expect_type,
+				     struct expression *exp,
+				     enum noside noside, enum exp_opcode op,
+				     struct value *arg1,
+				     struct value *arg2);
 
 namespace expr
 {
@@ -1177,6 +1182,21 @@ using gtr_operation = comparison_operation<BINOP_GTR, eval_op_gtr>;
 using geq_operation = comparison_operation<BINOP_GEQ, eval_op_geq>;
 using leq_operation = comparison_operation<BINOP_LEQ, eval_op_leq>;
 
+/* Implement the GDB '@' repeat operator.  */
+class repeat_operation
+  : public binop_operation<BINOP_REPEAT, eval_op_repeat>
+{
+  using binop_operation<BINOP_REPEAT, eval_op_repeat>::binop_operation;
+
+protected:
+
+  void do_generate_ax (struct expression *exp,
+		       struct agent_expr *ax,
+		       struct axs_value *value,
+		       struct type *cast_type)
+    override;
+};
+
 } /* namespace expr */
 
 #endif /* EXPOP_H */
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 103/203] Introduce comma_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (101 preceding siblings ...)
  2021-01-01 21:45 ` [PATCH 102/203] Introduce repeat_operation Tom Tromey
@ 2021-01-01 21:45 ` Tom Tromey
  2021-01-01 21:45 ` [PATCH 104/203] Implement some unary operations Tom Tromey
                   ` (100 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:45 UTC (permalink / raw)
  To: gdb-patches

This adds class comma_operation, which implements BINOP_COMMA.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* ax-gdb.c (comma_operation::do_generate_ax): New method.
---
 gdb/ChangeLog |  4 ++++
 gdb/ax-gdb.c  | 22 ++++++++++++++++++++++
 gdb/expop.h   | 31 +++++++++++++++++++++++++++++++
 3 files changed, 57 insertions(+)

diff --git a/gdb/ax-gdb.c b/gdb/ax-gdb.c
index 332840456fe..8d5e4fff903 100644
--- a/gdb/ax-gdb.c
+++ b/gdb/ax-gdb.c
@@ -2469,6 +2469,28 @@ repeat_operation::do_generate_ax (struct expression *exp,
   value->type = array;
 }
 
+void
+comma_operation::do_generate_ax (struct expression *exp,
+				 struct agent_expr *ax,
+				 struct axs_value *value,
+				 struct type *cast_type)
+{
+  /* Note that we need to be a little subtle about generating code
+     for comma.  In C, we can do some optimizations here because
+     we know the left operand is only being evaluated for effect.
+     However, if the tracing kludge is in effect, then we always
+     need to evaluate the left hand side fully, so that all the
+     variables it mentions get traced.  */
+  struct axs_value value1;
+  std::get<0> (m_storage)->generate_ax (exp, ax, &value1);
+  /* Don't just dispose of the left operand.  We might be tracing,
+     in which case we want to emit code to trace it if it's an
+     lvalue.  */
+  gen_traced_pop (ax, &value1);
+  std::get<1> (m_storage)->generate_ax (exp, ax, value);
+  /* It's the consumer's responsibility to trace the right operand.  */
+}
+
 }
 
 /* This handles the middle-to-right-side of code generation for binary
diff --git a/gdb/expop.h b/gdb/expop.h
index 419ce05abaf..67b265ca8f0 100644
--- a/gdb/expop.h
+++ b/gdb/expop.h
@@ -1197,6 +1197,37 @@ class repeat_operation
     override;
 };
 
+/* C-style comma operator.  */
+class comma_operation
+  : public maybe_constant_operation<operation_up, operation_up>
+{
+public:
+
+  using maybe_constant_operation::maybe_constant_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override
+  {
+    /* The left-hand-side is only evaluated for side effects, so don't
+       bother in other modes.  */
+    if (noside == EVAL_NORMAL)
+      std::get<0> (m_storage)->evaluate (nullptr, exp, noside);
+    return std::get<1> (m_storage)->evaluate (nullptr, exp, noside);
+  }
+
+  enum exp_opcode opcode () const override
+  { return BINOP_COMMA; }
+
+protected:
+
+  void do_generate_ax (struct expression *exp,
+		       struct agent_expr *ax,
+		       struct axs_value *value,
+		       struct type *cast_type)
+    override;
+};
+
 } /* namespace expr */
 
 #endif /* EXPOP_H */
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 104/203] Implement some unary operations
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (102 preceding siblings ...)
  2021-01-01 21:45 ` [PATCH 103/203] Introduce comma_operation Tom Tromey
@ 2021-01-01 21:45 ` Tom Tromey
  2021-01-01 21:45 ` [PATCH 105/203] Implement unary increment and decrement operations Tom Tromey
                   ` (99 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:45 UTC (permalink / raw)
  To: gdb-patches

This introduces a couple of new template classes and then uses them to
implement some simple unary operations.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* expop.h (unary_ftype): New typedef.
	(unop_operation, usual_ax_binop_operation): New templates.
	(unary_plus_operation, unary_neg_operation)
	(unary_complement_operation, unary_logical_not_operation): New
	typedefs.
	* eval.c (eval_op_plus, eval_op_neg, eval_op_complement)
	(eval_op_lognot): No longer static.
	* ax-gdb.c (gen_expr_unop): New function.
---
 gdb/ChangeLog | 11 ++++++++
 gdb/ax-gdb.c  | 47 +++++++++++++++++++++++++++++++
 gdb/eval.c    |  8 +++---
 gdb/expop.h   | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 139 insertions(+), 4 deletions(-)

diff --git a/gdb/ax-gdb.c b/gdb/ax-gdb.c
index 8d5e4fff903..c87b290397d 100644
--- a/gdb/ax-gdb.c
+++ b/gdb/ax-gdb.c
@@ -2694,6 +2694,53 @@ gen_expr_structop (struct expression *exp,
     internal_error (__FILE__, __LINE__,
 		    _("gen_expr: unhandled struct case"));
 }
+
+/* A helper function that emits a unary operation.  */
+
+void
+gen_expr_unop (struct expression *exp,
+	       enum exp_opcode op,
+	       expr::operation *lhs,
+	       struct agent_expr *ax, struct axs_value *value)
+{
+  struct axs_value value1, value2;
+
+  switch (op)
+    {
+    case UNOP_NEG:
+      gen_int_literal (ax, &value1, 0,
+		       builtin_type (ax->gdbarch)->builtin_int);
+      gen_usual_unary (ax, &value1);	/* shouldn't do much */
+      lhs->generate_ax (exp, ax, &value2);
+      gen_usual_unary (ax, &value2);
+      gen_usual_arithmetic (ax, &value1, &value2);
+      gen_binop (ax, value, &value1, &value2, aop_sub, aop_sub, 1, "negation");
+      break;
+
+    case UNOP_PLUS:
+      /* + FOO is equivalent to 0 + FOO, which can be optimized.  */
+      lhs->generate_ax (exp, ax, value);
+      gen_usual_unary (ax, value);
+      break;
+
+    case UNOP_LOGICAL_NOT:
+      lhs->generate_ax (exp, ax, value);
+      gen_usual_unary (ax, value);
+      gen_logical_not (ax, value,  builtin_type (ax->gdbarch)->builtin_int);
+      break;
+
+    case UNOP_COMPLEMENT:
+      lhs->generate_ax (exp, ax, value);
+      gen_usual_unary (ax, value);
+      gen_integral_promotions (ax, value);
+      gen_complement (ax, value);
+      break;
+
+    default:
+      gdb_assert_not_reached ("invalid case in gen_expr_unop");
+    }
+}
+
 \f
 
 /* Given a single variable and a scope, generate bytecodes to trace
diff --git a/gdb/eval.c b/gdb/eval.c
index 06f4c67e1d7..60e065cb0de 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1739,7 +1739,7 @@ eval_op_repeat (struct type *expect_type, struct expression *exp,
 
 /* A helper function for UNOP_PLUS.  */
 
-static struct value *
+struct value *
 eval_op_plus (struct type *expect_type, struct expression *exp,
 	      enum noside noside, enum exp_opcode op,
 	      struct value *arg1)
@@ -1757,7 +1757,7 @@ eval_op_plus (struct type *expect_type, struct expression *exp,
 
 /* A helper function for UNOP_NEG.  */
 
-static struct value *
+struct value *
 eval_op_neg (struct type *expect_type, struct expression *exp,
 	     enum noside noside, enum exp_opcode op,
 	     struct value *arg1)
@@ -1775,7 +1775,7 @@ eval_op_neg (struct type *expect_type, struct expression *exp,
 
 /* A helper function for UNOP_COMPLEMENT.  */
 
-static struct value *
+struct value *
 eval_op_complement (struct type *expect_type, struct expression *exp,
 		    enum noside noside, enum exp_opcode op,
 		    struct value *arg1)
@@ -1793,7 +1793,7 @@ eval_op_complement (struct type *expect_type, struct expression *exp,
 
 /* A helper function for UNOP_LOGICAL_NOT.  */
 
-static struct value *
+struct value *
 eval_op_lognot (struct type *expect_type, struct expression *exp,
 		enum noside noside, enum exp_opcode op,
 		struct value *arg1)
diff --git a/gdb/expop.h b/gdb/expop.h
index 67b265ca8f0..aae42f201bc 100644
--- a/gdb/expop.h
+++ b/gdb/expop.h
@@ -40,6 +40,10 @@ extern void gen_expr_structop (struct expression *exp,
 			       expr::operation *lhs,
 			       const char *name,
 			       struct agent_expr *ax, struct axs_value *value);
+extern void gen_expr_unop (struct expression *exp,
+			   enum exp_opcode op,
+			   expr::operation *lhs,
+			   struct agent_expr *ax, struct axs_value *value);
 
 extern struct value *eval_op_scope (struct type *expect_type,
 				    struct expression *exp,
@@ -139,6 +143,24 @@ extern struct value *eval_op_repeat (struct type *expect_type,
 				     enum noside noside, enum exp_opcode op,
 				     struct value *arg1,
 				     struct value *arg2);
+extern struct value *eval_op_plus (struct type *expect_type,
+				   struct expression *exp,
+				   enum noside noside, enum exp_opcode op,
+				   struct value *arg1);
+extern struct value *eval_op_neg (struct type *expect_type,
+				  struct expression *exp,
+				  enum noside noside, enum exp_opcode op,
+				  struct value *arg1);
+extern struct value *eval_op_complement (struct type *expect_type,
+					 struct expression *exp,
+					 enum noside noside,
+					 enum exp_opcode op,
+					 struct value *arg1);
+extern struct value *eval_op_lognot (struct type *expect_type,
+				     struct expression *exp,
+				     enum noside noside,
+				     enum exp_opcode op,
+				     struct value *arg1);
 
 namespace expr
 {
@@ -1228,6 +1250,61 @@ class comma_operation
     override;
 };
 
+typedef struct value *unary_ftype (struct type *expect_type,
+				   struct expression *exp,
+				   enum noside noside, enum exp_opcode op,
+				   struct value *arg1);
+
+/* Base class for unary operations.  */
+template<enum exp_opcode OP, unary_ftype FUNC>
+class unop_operation
+  : public maybe_constant_operation<operation_up>
+{
+public:
+
+  using maybe_constant_operation::maybe_constant_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override
+  {
+    value *val = std::get<0> (m_storage)->evaluate (nullptr, exp, noside);
+    return FUNC (expect_type, exp, noside, OP, val);
+  }
+
+  enum exp_opcode opcode () const override
+  { return OP; }
+};
+
+/* Unary operations that can also be turned into agent expressions in
+   the "usual" way.  */
+template<enum exp_opcode OP, unary_ftype FUNC>
+class usual_ax_unop_operation
+  : public unop_operation<OP, FUNC>
+{
+  using unop_operation<OP, FUNC>::unop_operation;
+
+protected:
+
+  void do_generate_ax (struct expression *exp,
+		       struct agent_expr *ax,
+		       struct axs_value *value,
+		       struct type *cast_type)
+    override
+  {
+    gen_expr_unop (exp, OP,
+		   std::get<0> (this->m_storage).get (),
+		   ax, value);
+  }
+};
+
+using unary_plus_operation = usual_ax_unop_operation<UNOP_PLUS, eval_op_plus>;
+using unary_neg_operation = usual_ax_unop_operation<UNOP_NEG, eval_op_neg>;
+using unary_complement_operation
+     = usual_ax_unop_operation<UNOP_COMPLEMENT, eval_op_complement>;
+using unary_logical_not_operation
+     = usual_ax_unop_operation<UNOP_LOGICAL_NOT, eval_op_lognot>;
+
 } /* namespace expr */
 
 #endif /* EXPOP_H */
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 105/203] Implement unary increment and decrement operations
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (103 preceding siblings ...)
  2021-01-01 21:45 ` [PATCH 104/203] Implement some unary operations Tom Tromey
@ 2021-01-01 21:45 ` Tom Tromey
  2021-01-01 21:45 ` [PATCH 106/203] Introduce unop_ind_operation Tom Tromey
                   ` (98 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:45 UTC (permalink / raw)
  To: gdb-patches

This implements the unary increment and decrement operations, "++" and
"--".

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* expop.h (unop_incr_operation): New template.
	(preinc_operation, predec_operation, postinc_operation)
	(postdec_operation): New typedefs.
	* eval.c (eval_op_preinc, eval_op_predec, eval_op_postinc)
	(eval_op_postdec): No longer static.
---
 gdb/ChangeLog |  8 ++++++++
 gdb/eval.c    |  8 ++++----
 gdb/expop.h   | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 62 insertions(+), 4 deletions(-)

diff --git a/gdb/eval.c b/gdb/eval.c
index 60e065cb0de..b7f816e28fe 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1887,7 +1887,7 @@ eval_op_memval (struct type *expect_type, struct expression *exp,
 
 /* A helper function for UNOP_PREINCREMENT.  */
 
-static struct value *
+struct value *
 eval_op_preinc (struct type *expect_type, struct expression *exp,
 		enum noside noside, enum exp_opcode op,
 		struct value *arg1)
@@ -1918,7 +1918,7 @@ eval_op_preinc (struct type *expect_type, struct expression *exp,
 
 /* A helper function for UNOP_PREDECREMENT.  */
 
-static struct value *
+struct value *
 eval_op_predec (struct type *expect_type, struct expression *exp,
 		enum noside noside, enum exp_opcode op,
 		struct value *arg1)
@@ -1949,7 +1949,7 @@ eval_op_predec (struct type *expect_type, struct expression *exp,
 
 /* A helper function for UNOP_POSTINCREMENT.  */
 
-static struct value *
+struct value *
 eval_op_postinc (struct type *expect_type, struct expression *exp,
 		 enum noside noside, enum exp_opcode op,
 		 struct value *arg1)
@@ -1983,7 +1983,7 @@ eval_op_postinc (struct type *expect_type, struct expression *exp,
 
 /* A helper function for UNOP_POSTDECREMENT.  */
 
-static struct value *
+struct value *
 eval_op_postdec (struct type *expect_type, struct expression *exp,
 		 enum noside noside, enum exp_opcode op,
 		 struct value *arg1)
diff --git a/gdb/expop.h b/gdb/expop.h
index aae42f201bc..913988d7692 100644
--- a/gdb/expop.h
+++ b/gdb/expop.h
@@ -161,6 +161,26 @@ extern struct value *eval_op_lognot (struct type *expect_type,
 				     enum noside noside,
 				     enum exp_opcode op,
 				     struct value *arg1);
+extern struct value *eval_op_preinc (struct type *expect_type,
+				     struct expression *exp,
+				     enum noside noside,
+				     enum exp_opcode op,
+				     struct value *arg1);
+extern struct value *eval_op_predec (struct type *expect_type,
+				     struct expression *exp,
+				     enum noside noside,
+				     enum exp_opcode op,
+				     struct value *arg1);
+extern struct value *eval_op_postinc (struct type *expect_type,
+				      struct expression *exp,
+				      enum noside noside,
+				      enum exp_opcode op,
+				      struct value *arg1);
+extern struct value *eval_op_postdec (struct type *expect_type,
+				      struct expression *exp,
+				      enum noside noside,
+				      enum exp_opcode op,
+				      struct value *arg1);
 
 namespace expr
 {
@@ -1305,6 +1325,36 @@ using unary_complement_operation
 using unary_logical_not_operation
      = usual_ax_unop_operation<UNOP_LOGICAL_NOT, eval_op_lognot>;
 
+/* Handle pre- and post- increment and -decrement.  */
+template<enum exp_opcode OP, unary_ftype FUNC>
+class unop_incr_operation
+  : public tuple_holding_operation<operation_up>
+{
+public:
+
+  using tuple_holding_operation::tuple_holding_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override
+  {
+    value *val = std::get<0> (m_storage)->evaluate (expect_type, exp, noside);
+    return FUNC (expect_type, exp, noside, OP, val);
+  }
+
+  enum exp_opcode opcode () const override
+  { return OP; }
+};
+
+using preinc_operation
+     = unop_incr_operation<UNOP_PREINCREMENT, eval_op_preinc>;
+using predec_operation
+     = unop_incr_operation<UNOP_PREDECREMENT, eval_op_predec>;
+using postinc_operation
+     = unop_incr_operation<UNOP_POSTINCREMENT, eval_op_postinc>;
+using postdec_operation
+     = unop_incr_operation<UNOP_POSTDECREMENT, eval_op_postdec>;
+
 } /* namespace expr */
 
 #endif /* EXPOP_H */
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 106/203] Introduce unop_ind_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (104 preceding siblings ...)
  2021-01-01 21:45 ` [PATCH 105/203] Implement unary increment and decrement operations Tom Tromey
@ 2021-01-01 21:45 ` Tom Tromey
  2021-01-01 21:45 ` [PATCH 107/203] Introduce type_operation Tom Tromey
                   ` (97 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:45 UTC (permalink / raw)
  To: gdb-patches

This adds class unop_ind_operation, which implements UNOP_IND.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* expop.h (class unop_ind_base_operation)
	(class unop_ind_operation): New.
	* eval.c (eval_op_ind): No longer static.  Remove "op" parameter.
	(unop_ind_base_operation::evaluate_for_address)
	(unop_ind_base_operation::evaluate_for_sizeof): New method.
	* ax-gdb.c (gen_expr_unop) <case UNOP_IND>: New.
---
 gdb/ChangeLog |  9 +++++++++
 gdb/ax-gdb.c  |  8 ++++++++
 gdb/eval.c    | 45 +++++++++++++++++++++++++++++++++++++-----
 gdb/expop.h   | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 111 insertions(+), 5 deletions(-)

diff --git a/gdb/ax-gdb.c b/gdb/ax-gdb.c
index c87b290397d..f7ab50f8cde 100644
--- a/gdb/ax-gdb.c
+++ b/gdb/ax-gdb.c
@@ -2736,6 +2736,14 @@ gen_expr_unop (struct expression *exp,
       gen_complement (ax, value);
       break;
 
+    case UNOP_IND:
+      lhs->generate_ax (exp, ax, value);
+      gen_usual_unary (ax, value);
+      if (!pointer_type (value->type))
+	error (_("Argument of unary `*' is not a pointer."));
+      gen_deref (value);
+      break;
+
     default:
       gdb_assert_not_reached ("invalid case in gen_expr_unop");
     }
diff --git a/gdb/eval.c b/gdb/eval.c
index b7f816e28fe..cca88d49230 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1812,9 +1812,9 @@ eval_op_lognot (struct type *expect_type, struct expression *exp,
 
 /* A helper function for UNOP_IND.  */
 
-static struct value *
+struct value *
 eval_op_ind (struct type *expect_type, struct expression *exp,
-	     enum noside noside, enum exp_opcode op,
+	     enum noside noside,
 	     struct value *arg1)
 {
   struct type *type = check_typedef (value_type (arg1));
@@ -1824,8 +1824,8 @@ eval_op_ind (struct type *expect_type, struct expression *exp,
 	     "to member without an object"));
   if (noside == EVAL_SKIP)
     return eval_skip_value (exp);
-  if (unop_user_defined_p (op, arg1))
-    return value_x_unop (arg1, op, noside);
+  if (unop_user_defined_p (UNOP_IND, arg1))
+    return value_x_unop (arg1, UNOP_IND, noside);
   else if (noside == EVAL_AVOID_SIDE_EFFECTS)
     {
       type = check_typedef (value_type (arg1));
@@ -2949,7 +2949,7 @@ evaluate_subexp_standard (struct type *expect_type,
       if (expect_type && expect_type->code () == TYPE_CODE_PTR)
 	expect_type = TYPE_TARGET_TYPE (check_typedef (expect_type));
       arg1 = evaluate_subexp (expect_type, exp, pos, noside);
-      return eval_op_ind (expect_type, exp, noside, op, arg1);
+      return eval_op_ind (expect_type, exp, noside, arg1);
 
     case UNOP_ADDR:
       /* C++: check for and handle pointer to members.  */
@@ -3276,6 +3276,22 @@ scope_operation::evaluate_for_address (struct expression *exp,
   return x;
 }
 
+value *
+unop_ind_base_operation::evaluate_for_address (struct expression *exp,
+					       enum noside noside)
+{
+  value *x = std::get<0> (m_storage)->evaluate (nullptr, exp, noside);
+
+  /* We can't optimize out "&*" if there's a user-defined operator*.  */
+  if (unop_user_defined_p (UNOP_IND, x))
+    {
+      x = value_x_unop (x, UNOP_IND, noside);
+      return evaluate_subexp_for_address_base (exp, noside, x);
+    }
+
+  return coerce_array (x);
+}
+
 value *
 var_msym_value_operation::evaluate_for_address (struct expression *exp,
 						enum noside noside)
@@ -3544,6 +3560,25 @@ subscript_operation::evaluate_for_sizeof (struct expression *exp,
   return operation::evaluate_for_sizeof (exp, noside);
 }
 
+value *
+unop_ind_base_operation::evaluate_for_sizeof (struct expression *exp,
+					      enum noside noside)
+{
+  value *val = std::get<0> (m_storage)->evaluate (nullptr, exp,
+						  EVAL_AVOID_SIDE_EFFECTS);
+  struct type *type = check_typedef (value_type (val));
+  if (type->code () != TYPE_CODE_PTR
+      && !TYPE_IS_REFERENCE (type)
+      && type->code () != TYPE_CODE_ARRAY)
+    error (_("Attempt to take contents of a non-pointer value."));
+  type = TYPE_TARGET_TYPE (type);
+  if (is_dynamic_type (type))
+    type = value_type (value_ind (val));
+  /* FIXME: This should be size_t.  */
+  struct type *size_type = builtin_type (exp->gdbarch)->builtin_int;
+  return value_from_longest (size_type, (LONGEST) TYPE_LENGTH (type));
+}
+
 }
 
 /* Evaluate a subexpression of EXP, at index *POS, and return a value
diff --git a/gdb/expop.h b/gdb/expop.h
index 913988d7692..caac155295a 100644
--- a/gdb/expop.h
+++ b/gdb/expop.h
@@ -181,6 +181,10 @@ extern struct value *eval_op_postdec (struct type *expect_type,
 				      enum noside noside,
 				      enum exp_opcode op,
 				      struct value *arg1);
+extern struct value *eval_op_ind (struct type *expect_type,
+				  struct expression *exp,
+				  enum noside noside,
+				  struct value *arg1);
 
 namespace expr
 {
@@ -1355,6 +1359,56 @@ using postinc_operation
 using postdec_operation
      = unop_incr_operation<UNOP_POSTDECREMENT, eval_op_postdec>;
 
+/* Base class for implementations of UNOP_IND.  */
+class unop_ind_base_operation
+  : public tuple_holding_operation<operation_up>
+{
+public:
+
+  using tuple_holding_operation::tuple_holding_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override
+  {
+    if (expect_type != nullptr && expect_type->code () == TYPE_CODE_PTR)
+      expect_type = TYPE_TARGET_TYPE (check_typedef (expect_type));
+    value *val = std::get<0> (m_storage)->evaluate (expect_type, exp, noside);
+    return eval_op_ind (expect_type, exp, noside, val);
+  }
+
+  value *evaluate_for_address (struct expression *exp,
+			       enum noside noside) override;
+
+  value *evaluate_for_sizeof (struct expression *exp,
+			      enum noside noside) override;
+
+  enum exp_opcode opcode () const override
+  { return UNOP_IND; }
+};
+
+/* Ordinary UNOP_IND implementation.  */
+class unop_ind_operation
+  : public unop_ind_base_operation
+{
+public:
+
+  using unop_ind_base_operation::unop_ind_base_operation;
+
+protected:
+
+  void do_generate_ax (struct expression *exp,
+		       struct agent_expr *ax,
+		       struct axs_value *value,
+		       struct type *cast_type)
+    override
+  {
+    gen_expr_unop (exp, UNOP_IND,
+		   std::get<0> (this->m_storage).get (),
+		   ax, value);
+  }
+};
+
 } /* namespace expr */
 
 #endif /* EXPOP_H */
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 107/203] Introduce type_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (105 preceding siblings ...)
  2021-01-01 21:45 ` [PATCH 106/203] Introduce unop_ind_operation Tom Tromey
@ 2021-01-01 21:45 ` Tom Tromey
  2021-01-01 21:45 ` [PATCH 108/203] Introduce typeof_operation Tom Tromey
                   ` (96 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:45 UTC (permalink / raw)
  To: gdb-patches

This adds class type_operation, which implements OP_TYPE.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* expop.h (class type_operation): New.
	* eval.c (eval_op_type): No longer static.
---
 gdb/ChangeLog |  5 +++++
 gdb/eval.c    |  2 +-
 gdb/expop.h   | 25 +++++++++++++++++++++++++
 3 files changed, 31 insertions(+), 1 deletion(-)

diff --git a/gdb/eval.c b/gdb/eval.c
index cca88d49230..f07990932b9 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -2017,7 +2017,7 @@ eval_op_postdec (struct type *expect_type, struct expression *exp,
 
 /* A helper function for OP_TYPE.  */
 
-static struct value *
+struct value *
 eval_op_type (struct type *expect_type, struct expression *exp,
 	      enum noside noside, struct type *type)
 {
diff --git a/gdb/expop.h b/gdb/expop.h
index caac155295a..aac3e729de9 100644
--- a/gdb/expop.h
+++ b/gdb/expop.h
@@ -185,6 +185,9 @@ extern struct value *eval_op_ind (struct type *expect_type,
 				  struct expression *exp,
 				  enum noside noside,
 				  struct value *arg1);
+extern struct value *eval_op_type (struct type *expect_type,
+				   struct expression *exp,
+				   enum noside noside, struct type *type);
 
 namespace expr
 {
@@ -1409,6 +1412,28 @@ class unop_ind_operation
   }
 };
 
+/* Implement OP_TYPE.  */
+class type_operation
+  : public tuple_holding_operation<struct type *>
+{
+public:
+
+  using tuple_holding_operation::tuple_holding_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override
+  {
+    return eval_op_type (expect_type, exp, noside, std::get<0> (m_storage));
+  }
+
+  enum exp_opcode opcode () const override
+  { return OP_TYPE; }
+
+  bool constant_p () const override
+  { return true; }
+};
+
 } /* namespace expr */
 
 #endif /* EXPOP_H */
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 108/203] Introduce typeof_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (106 preceding siblings ...)
  2021-01-01 21:45 ` [PATCH 107/203] Introduce type_operation Tom Tromey
@ 2021-01-01 21:45 ` Tom Tromey
  2021-01-01 21:45 ` [PATCH 109/203] Introduce decltype_operation Tom Tromey
                   ` (95 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:45 UTC (permalink / raw)
  To: gdb-patches

This adds class typeof_operation, which implements OP_TYPEOF.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* expop.h (class typeof_operation): New.
---
 gdb/ChangeLog |  4 ++++
 gdb/expop.h   | 25 +++++++++++++++++++++++++
 2 files changed, 29 insertions(+)

diff --git a/gdb/expop.h b/gdb/expop.h
index aac3e729de9..502ad71d067 100644
--- a/gdb/expop.h
+++ b/gdb/expop.h
@@ -1434,6 +1434,31 @@ class type_operation
   { return true; }
 };
 
+/* Implement the "typeof" operation.  */
+class typeof_operation
+  : public maybe_constant_operation<operation_up>
+{
+public:
+
+  using maybe_constant_operation::maybe_constant_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override
+  {
+    if (noside == EVAL_SKIP)
+      return eval_skip_value (exp);
+    else if (noside == EVAL_AVOID_SIDE_EFFECTS)
+      return std::get<0> (m_storage)->evaluate (nullptr, exp,
+						EVAL_AVOID_SIDE_EFFECTS);
+    else
+      error (_("Attempt to use a type as an expression"));
+  }
+
+  enum exp_opcode opcode () const override
+  { return OP_TYPEOF; }
+};
+
 } /* namespace expr */
 
 #endif /* EXPOP_H */
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 109/203] Introduce decltype_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (107 preceding siblings ...)
  2021-01-01 21:45 ` [PATCH 108/203] Introduce typeof_operation Tom Tromey
@ 2021-01-01 21:45 ` Tom Tromey
  2021-01-01 21:45 ` [PATCH 110/203] Introduce typeid_operation Tom Tromey
                   ` (94 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:45 UTC (permalink / raw)
  To: gdb-patches

This adds class decltype_operation, which implements OP_DECLTYPE.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* expop.h (class decltype_operation): New.
---
 gdb/ChangeLog |  4 ++++
 gdb/expop.h   | 47 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 51 insertions(+)

diff --git a/gdb/expop.h b/gdb/expop.h
index 502ad71d067..ba107f10ba0 100644
--- a/gdb/expop.h
+++ b/gdb/expop.h
@@ -1459,6 +1459,53 @@ class typeof_operation
   { return OP_TYPEOF; }
 };
 
+/* Implement 'decltype'.  */
+class decltype_operation
+  : public maybe_constant_operation<operation_up>
+{
+public:
+
+  using maybe_constant_operation::maybe_constant_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override
+  {
+    if (noside == EVAL_SKIP)
+      return eval_skip_value (exp);
+    else if (noside == EVAL_AVOID_SIDE_EFFECTS)
+      {
+	value *result
+	  = std::get<0> (m_storage)->evaluate (nullptr, exp,
+					       EVAL_AVOID_SIDE_EFFECTS);
+	enum exp_opcode sub_op = std::get<0> (m_storage)->opcode ();
+	if (sub_op == BINOP_SUBSCRIPT
+	    || sub_op == STRUCTOP_MEMBER
+	    || sub_op == STRUCTOP_MPTR
+	    || sub_op == UNOP_IND
+	    || sub_op == STRUCTOP_STRUCT
+	    || sub_op == STRUCTOP_PTR
+	    || sub_op == OP_SCOPE)
+	  {
+	    struct type *type = value_type (result);
+
+	    if (!TYPE_IS_REFERENCE (type))
+	      {
+		type = lookup_lvalue_reference_type (type);
+		result = allocate_value (type);
+	      }
+	  }
+
+	return result;
+      }
+    else
+      error (_("Attempt to use a type as an expression"));
+  }
+
+  enum exp_opcode opcode () const override
+  { return OP_DECLTYPE; }
+};
+
 } /* namespace expr */
 
 #endif /* EXPOP_H */
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 110/203] Introduce typeid_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (108 preceding siblings ...)
  2021-01-01 21:45 ` [PATCH 109/203] Introduce decltype_operation Tom Tromey
@ 2021-01-01 21:45 ` Tom Tromey
  2021-01-01 21:45 ` [PATCH 111/203] Introduce unop_addr_operation Tom Tromey
                   ` (93 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:45 UTC (permalink / raw)
  To: gdb-patches

This adds class typeid_operation, which implements OP_TYPEID.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* expop.h (class typeid_operation): New.
---
 gdb/ChangeLog |  4 ++++
 gdb/expop.h   | 29 +++++++++++++++++++++++++++++
 2 files changed, 33 insertions(+)

diff --git a/gdb/expop.h b/gdb/expop.h
index ba107f10ba0..9f23b8afd7c 100644
--- a/gdb/expop.h
+++ b/gdb/expop.h
@@ -1506,6 +1506,35 @@ class decltype_operation
   { return OP_DECLTYPE; }
 };
 
+/* Implement 'typeid'.  */
+class typeid_operation
+  : public tuple_holding_operation<operation_up>
+{
+public:
+
+  using tuple_holding_operation::tuple_holding_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override
+  {
+    enum exp_opcode sub_op = std::get<0> (m_storage)->opcode ();
+    enum noside sub_noside
+      = ((sub_op == OP_TYPE || sub_op == OP_DECLTYPE || sub_op == OP_TYPEOF)
+	 ? EVAL_AVOID_SIDE_EFFECTS
+	 : noside);
+
+    value *result = std::get<0> (m_storage)->evaluate (nullptr, exp,
+						       sub_noside);
+    if (noside != EVAL_NORMAL)
+      return allocate_value (cplus_typeid_type (exp->gdbarch));
+    return cplus_typeid (result);
+  }
+
+  enum exp_opcode opcode () const override
+  { return OP_TYPEID; }
+};
+
 } /* namespace expr */
 
 #endif /* EXPOP_H */
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 111/203] Introduce unop_addr_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (109 preceding siblings ...)
  2021-01-01 21:45 ` [PATCH 110/203] Introduce typeid_operation Tom Tromey
@ 2021-01-01 21:45 ` Tom Tromey
  2021-01-01 21:45 ` [PATCH 112/203] Introduce unop_sizeof_operation Tom Tromey
                   ` (92 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:45 UTC (permalink / raw)
  To: gdb-patches

This adds class unop_addr_operation, which implements UNOP_ADDR.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* expop.h (class unop_addr_operation): New.
	* ax-gdb.c (gen_expr_unop) <case UNOP_ADDR>: New.
---
 gdb/ChangeLog |  5 +++++
 gdb/ax-gdb.c  |  5 +++++
 gdb/expop.h   | 36 ++++++++++++++++++++++++++++++++++++
 3 files changed, 46 insertions(+)

diff --git a/gdb/ax-gdb.c b/gdb/ax-gdb.c
index f7ab50f8cde..64710887534 100644
--- a/gdb/ax-gdb.c
+++ b/gdb/ax-gdb.c
@@ -2744,6 +2744,11 @@ gen_expr_unop (struct expression *exp,
       gen_deref (value);
       break;
 
+    case UNOP_ADDR:
+      lhs->generate_ax (exp, ax, value);
+      gen_address_of (value);
+      break;
+
     default:
       gdb_assert_not_reached ("invalid case in gen_expr_unop");
     }
diff --git a/gdb/expop.h b/gdb/expop.h
index 9f23b8afd7c..8ddc26d329a 100644
--- a/gdb/expop.h
+++ b/gdb/expop.h
@@ -1535,6 +1535,42 @@ class typeid_operation
   { return OP_TYPEID; }
 };
 
+/* Implement the address-of operation.  */
+class unop_addr_operation
+  : public maybe_constant_operation<operation_up>
+{
+public:
+
+  using maybe_constant_operation::maybe_constant_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override
+  {
+    /* C++: check for and handle pointer to members.  */
+    if (noside == EVAL_SKIP)
+      return eval_skip_value (exp);
+    else
+      return std::get<0> (m_storage)->evaluate_for_address (exp, noside);
+  }
+
+  enum exp_opcode opcode () const override
+  { return UNOP_ADDR; }
+
+protected:
+
+  void do_generate_ax (struct expression *exp,
+		       struct agent_expr *ax,
+		       struct axs_value *value,
+		       struct type *cast_type)
+    override
+  {
+    gen_expr_unop (exp, UNOP_ADDR,
+		   std::get<0> (this->m_storage).get (),
+		   ax, value);
+  }
+};
+
 } /* namespace expr */
 
 #endif /* EXPOP_H */
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 112/203] Introduce unop_sizeof_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (110 preceding siblings ...)
  2021-01-01 21:45 ` [PATCH 111/203] Introduce unop_addr_operation Tom Tromey
@ 2021-01-01 21:45 ` Tom Tromey
  2021-01-01 21:45 ` [PATCH 113/203] Introduce unop_alignof_operation Tom Tromey
                   ` (91 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:45 UTC (permalink / raw)
  To: gdb-patches

This adds class unop_sizeof_operation, which implements UNOP_SIZEOF.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* expop.h (class unop_sizeof_operation): New.
	* ax-gdb.c (unop_sizeof_operation::do_generate_ax): New method.
---
 gdb/ChangeLog |  5 +++++
 gdb/ax-gdb.c  | 23 +++++++++++++++++++++++
 gdb/expop.h   | 29 +++++++++++++++++++++++++++++
 3 files changed, 57 insertions(+)

diff --git a/gdb/ax-gdb.c b/gdb/ax-gdb.c
index 64710887534..756f4d7969a 100644
--- a/gdb/ax-gdb.c
+++ b/gdb/ax-gdb.c
@@ -2491,6 +2491,29 @@ comma_operation::do_generate_ax (struct expression *exp,
   /* It's the consumer's responsibility to trace the right operand.  */
 }
 
+void
+unop_sizeof_operation::do_generate_ax (struct expression *exp,
+				       struct agent_expr *ax,
+				       struct axs_value *value,
+				       struct type *cast_type)
+{
+  /* We don't care about the value of the operand expression; we only
+     care about its type.  However, in the current arrangement, the
+     only way to find an expression's type is to generate code for it.
+     So we generate code for the operand, and then throw it away,
+     replacing it with code that simply pushes its size.  */
+  int start = ax->len;
+
+  std::get<0> (m_storage)->generate_ax (exp, ax, value);
+
+  /* Throw away the code we just generated.  */
+  ax->len = start;
+
+  ax_const_l (ax, TYPE_LENGTH (value->type));
+  value->kind = axs_rvalue;
+  value->type = builtin_type (ax->gdbarch)->builtin_int;
+}
+
 }
 
 /* This handles the middle-to-right-side of code generation for binary
diff --git a/gdb/expop.h b/gdb/expop.h
index 8ddc26d329a..22af0c824e2 100644
--- a/gdb/expop.h
+++ b/gdb/expop.h
@@ -1571,6 +1571,35 @@ class unop_addr_operation
   }
 };
 
+/* Implement 'sizeof'.  */
+class unop_sizeof_operation
+  : public maybe_constant_operation<operation_up>
+{
+public:
+
+  using maybe_constant_operation::maybe_constant_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override
+  {
+    if (noside == EVAL_SKIP)
+      return eval_skip_value (exp);
+    return std::get<0> (m_storage)->evaluate_for_sizeof (exp, noside);
+  }
+
+  enum exp_opcode opcode () const override
+  { return UNOP_SIZEOF; }
+
+protected:
+
+  void do_generate_ax (struct expression *exp,
+		       struct agent_expr *ax,
+		       struct axs_value *value,
+		       struct type *cast_type)
+    override;
+};
+
 } /* namespace expr */
 
 #endif /* EXPOP_H */
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 113/203] Introduce unop_alignof_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (111 preceding siblings ...)
  2021-01-01 21:45 ` [PATCH 112/203] Introduce unop_sizeof_operation Tom Tromey
@ 2021-01-01 21:45 ` Tom Tromey
  2021-01-01 21:45 ` [PATCH 114/203] Implement UNOP_MEMVAL and UNOP_MEMVAL_TYPE Tom Tromey
                   ` (90 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:45 UTC (permalink / raw)
  To: gdb-patches

This adds class unop_alignof_operation, which implements UNOP_ALIGNOF.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* expop.h (class unop_alignof_operation): New.
	* eval.c (eval_op_alignof): No longer static.
---
 gdb/ChangeLog |  5 +++++
 gdb/eval.c    |  2 +-
 gdb/expop.h   | 25 +++++++++++++++++++++++++
 3 files changed, 31 insertions(+), 1 deletion(-)

diff --git a/gdb/eval.c b/gdb/eval.c
index f07990932b9..526c80de92b 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1856,7 +1856,7 @@ eval_op_ind (struct type *expect_type, struct expression *exp,
 
 /* A helper function for UNOP_ALIGNOF.  */
 
-static struct value *
+struct value *
 eval_op_alignof (struct type *expect_type, struct expression *exp,
 		 enum noside noside,
 		 struct value *arg1)
diff --git a/gdb/expop.h b/gdb/expop.h
index 22af0c824e2..b5f01550d85 100644
--- a/gdb/expop.h
+++ b/gdb/expop.h
@@ -188,6 +188,10 @@ extern struct value *eval_op_ind (struct type *expect_type,
 extern struct value *eval_op_type (struct type *expect_type,
 				   struct expression *exp,
 				   enum noside noside, struct type *type);
+extern struct value *eval_op_alignof (struct type *expect_type,
+				      struct expression *exp,
+				      enum noside noside,
+				      struct value *arg1);
 
 namespace expr
 {
@@ -1600,6 +1604,27 @@ class unop_sizeof_operation
     override;
 };
 
+/* Implement 'alignof'.  */
+class unop_alignof_operation
+  : public maybe_constant_operation<operation_up>
+{
+public:
+
+  using maybe_constant_operation::maybe_constant_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override
+  {
+    value *val = std::get<0> (m_storage)->evaluate (nullptr, exp,
+						    EVAL_AVOID_SIDE_EFFECTS);
+    return eval_op_alignof (expect_type, exp, noside, val);
+  }
+
+  enum exp_opcode opcode () const override
+  { return UNOP_ALIGNOF; }
+};
+
 } /* namespace expr */
 
 #endif /* EXPOP_H */
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 114/203] Implement UNOP_MEMVAL and UNOP_MEMVAL_TYPE
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (112 preceding siblings ...)
  2021-01-01 21:45 ` [PATCH 113/203] Introduce unop_alignof_operation Tom Tromey
@ 2021-01-01 21:45 ` Tom Tromey
  2021-01-01 21:45 ` [PATCH 115/203] Introduce op_this_operation Tom Tromey
                   ` (89 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:45 UTC (permalink / raw)
  To: gdb-patches

This adds class unop_memval_operation and unop_memval_type_operation,
which implement UNOP_MEMVAL and UNOP_MEMVAL_TYPE.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* expop.h (class unop_memval_operation)
	(class unop_memval_type_operation): New.
	* eval.c (eval_op_memval): No longer static.
	(unop_memval_operation::evaluate_for_address)
	(unop_memval_type_operation::evaluate_for_address)
	(unop_memval_operation::evaluate_for_sizeof)
	(unop_memval_type_operation::evaluate_for_sizeof): New methods.
	* ax-gdb.c (unop_memval_operation::do_generate_ax)
	(unop_memval_type_operation::do_generate_ax): New methods.
---
 gdb/ChangeLog | 12 ++++++++
 gdb/ax-gdb.c  | 40 ++++++++++++++++++++++++++
 gdb/eval.c    | 37 ++++++++++++++++++++++++-
 gdb/expop.h   | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 165 insertions(+), 1 deletion(-)

diff --git a/gdb/ax-gdb.c b/gdb/ax-gdb.c
index 756f4d7969a..6514e40cdbf 100644
--- a/gdb/ax-gdb.c
+++ b/gdb/ax-gdb.c
@@ -2514,6 +2514,46 @@ unop_sizeof_operation::do_generate_ax (struct expression *exp,
   value->type = builtin_type (ax->gdbarch)->builtin_int;
 }
 
+void
+unop_memval_operation::do_generate_ax (struct expression *exp,
+				       struct agent_expr *ax,
+				       struct axs_value *value,
+				       struct type *cast_type)
+{
+  std::get<0> (m_storage)->generate_ax (exp, 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 = std::get<1> (m_storage);
+  value->kind = axs_lvalue_memory;
+}
+
+void
+unop_memval_type_operation::do_generate_ax (struct expression *exp,
+					    struct agent_expr *ax,
+					    struct axs_value *value,
+					    struct type *cast_type)
+{
+  struct value *val
+    = std::get<0> (m_storage)->evaluate (nullptr, exp,
+					 EVAL_AVOID_SIDE_EFFECTS);
+  struct type *type = value_type (val);
+
+  std::get<1> (m_storage)->generate_ax (exp, 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;
+}
+
 }
 
 /* This handles the middle-to-right-side of code generation for binary
diff --git a/gdb/eval.c b/gdb/eval.c
index 526c80de92b..1ada2f3986b 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1872,7 +1872,7 @@ eval_op_alignof (struct type *expect_type, struct expression *exp,
 
 /* A helper function for UNOP_MEMVAL.  */
 
-static struct value *
+struct value *
 eval_op_memval (struct type *expect_type, struct expression *exp,
 		enum noside noside,
 		struct value *arg1, struct type *type)
@@ -3308,6 +3308,25 @@ var_msym_value_operation::evaluate_for_address (struct expression *exp,
     return value_addr (val);
 }
 
+value *
+unop_memval_operation::evaluate_for_address (struct expression *exp,
+					     enum noside noside)
+{
+  return value_cast (lookup_pointer_type (std::get<1> (m_storage)),
+		     std::get<0> (m_storage)->evaluate (nullptr, exp, noside));
+}
+
+value *
+unop_memval_type_operation::evaluate_for_address (struct expression *exp,
+						  enum noside noside)
+{
+  value *typeval = std::get<0> (m_storage)->evaluate (nullptr, exp,
+						      EVAL_AVOID_SIDE_EFFECTS);
+  struct type *type = value_type (typeval);
+  return value_cast (lookup_pointer_type (type),
+		     std::get<1> (m_storage)->evaluate (nullptr, exp, noside));
+}
+
 }
 
 /* Evaluate like `evaluate_subexp' except coercing arrays to pointers.
@@ -3579,6 +3598,22 @@ unop_ind_base_operation::evaluate_for_sizeof (struct expression *exp,
   return value_from_longest (size_type, (LONGEST) TYPE_LENGTH (type));
 }
 
+value *
+unop_memval_operation::evaluate_for_sizeof (struct expression *exp,
+					    enum noside noside)
+{
+  return evaluate_subexp_for_sizeof_base (exp, std::get<1> (m_storage));
+}
+
+value *
+unop_memval_type_operation::evaluate_for_sizeof (struct expression *exp,
+						 enum noside noside)
+{
+  value *typeval = std::get<0> (m_storage)->evaluate (nullptr, exp,
+						      EVAL_AVOID_SIDE_EFFECTS);
+  return evaluate_subexp_for_sizeof_base (exp, value_type (typeval));
+}
+
 }
 
 /* Evaluate a subexpression of EXP, at index *POS, and return a value
diff --git a/gdb/expop.h b/gdb/expop.h
index b5f01550d85..867cd85ead5 100644
--- a/gdb/expop.h
+++ b/gdb/expop.h
@@ -192,6 +192,10 @@ extern struct value *eval_op_alignof (struct type *expect_type,
 				      struct expression *exp,
 				      enum noside noside,
 				      struct value *arg1);
+extern struct value *eval_op_memval (struct type *expect_type,
+				     struct expression *exp,
+				     enum noside noside,
+				     struct value *arg1, struct type *type);
 
 namespace expr
 {
@@ -1625,6 +1629,79 @@ class unop_alignof_operation
   { return UNOP_ALIGNOF; }
 };
 
+/* Implement UNOP_MEMVAL.  */
+class unop_memval_operation
+  : public tuple_holding_operation<operation_up, struct type *>
+{
+public:
+
+  using tuple_holding_operation::tuple_holding_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override
+  {
+    value *val = std::get<0> (m_storage)->evaluate (expect_type, exp, noside);
+    return eval_op_memval (expect_type, exp, noside, val,
+			   std::get<1> (m_storage));
+  }
+
+  value *evaluate_for_sizeof (struct expression *exp,
+			      enum noside noside) override;
+
+  value *evaluate_for_address (struct expression *exp,
+			       enum noside noside) override;
+
+  enum exp_opcode opcode () const override
+  { return UNOP_MEMVAL; }
+
+protected:
+
+  void do_generate_ax (struct expression *exp,
+		       struct agent_expr *ax,
+		       struct axs_value *value,
+		       struct type *cast_type)
+    override;
+};
+
+/* Implement UNOP_MEMVAL_TYPE.  */
+class unop_memval_type_operation
+  : public tuple_holding_operation<operation_up, operation_up>
+{
+public:
+
+  using tuple_holding_operation::tuple_holding_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override
+  {
+    value *typeval
+      = std::get<0> (m_storage)->evaluate (expect_type, exp,
+					   EVAL_AVOID_SIDE_EFFECTS);
+    struct type *type = value_type (typeval);
+    value *val = std::get<1> (m_storage)->evaluate (expect_type, exp, noside);
+    return eval_op_memval (expect_type, exp, noside, val, type);
+  }
+
+  value *evaluate_for_sizeof (struct expression *exp,
+			      enum noside noside) override;
+
+  value *evaluate_for_address (struct expression *exp,
+			       enum noside noside) override;
+
+  enum exp_opcode opcode () const override
+  { return UNOP_MEMVAL_TYPE; }
+
+protected:
+
+  void do_generate_ax (struct expression *exp,
+		       struct agent_expr *ax,
+		       struct axs_value *value,
+		       struct type *cast_type)
+    override;
+};
+
 } /* namespace expr */
 
 #endif /* EXPOP_H */
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 115/203] Introduce op_this_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (113 preceding siblings ...)
  2021-01-01 21:45 ` [PATCH 114/203] Implement UNOP_MEMVAL and UNOP_MEMVAL_TYPE Tom Tromey
@ 2021-01-01 21:45 ` Tom Tromey
  2021-01-01 21:45 ` [PATCH 116/203] Introduce type_instance_operation Tom Tromey
                   ` (88 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:45 UTC (permalink / raw)
  To: gdb-patches

This adds class op_this_operation, which implements OP_THIS.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* expop.h (class op_this_operation): New.
	* ax-gdb.c (op_this_operation::do_generate_ax): New method.
---
 gdb/ChangeLog |  5 +++++
 gdb/ax-gdb.c  | 25 +++++++++++++++++++++++++
 gdb/expop.h   | 27 +++++++++++++++++++++++++++
 3 files changed, 57 insertions(+)

diff --git a/gdb/ax-gdb.c b/gdb/ax-gdb.c
index 6514e40cdbf..98edc6c0727 100644
--- a/gdb/ax-gdb.c
+++ b/gdb/ax-gdb.c
@@ -2554,6 +2554,31 @@ unop_memval_type_operation::do_generate_ax (struct expression *exp,
   value->kind = axs_lvalue_memory;
 }
 
+void
+op_this_operation::do_generate_ax (struct expression *exp,
+				   struct agent_expr *ax,
+				   struct axs_value *value,
+				   struct type *cast_type)
+{
+  struct symbol *sym, *func;
+  const struct block *b;
+  const struct language_defn *lang;
+
+  b = block_for_pc (ax->scope);
+  func = block_linkage_function (b);
+  lang = language_def (func->language ());
+
+  sym = lookup_language_this (lang, b).symbol;
+  if (!sym)
+    error (_("no `%s' found"), lang->name_of_this ());
+
+  gen_var_ref (ax, value, sym);
+
+  if (value->optimized_out)
+    error (_("`%s' has been optimized out, cannot use"),
+	   sym->print_name ());
+}
+
 }
 
 /* This handles the middle-to-right-side of code generation for binary
diff --git a/gdb/expop.h b/gdb/expop.h
index 867cd85ead5..394191ce6e5 100644
--- a/gdb/expop.h
+++ b/gdb/expop.h
@@ -1702,6 +1702,33 @@ class unop_memval_type_operation
     override;
 };
 
+/* Implement the 'this' expression.  */
+class op_this_operation
+  : public tuple_holding_operation<>
+{
+public:
+
+  using tuple_holding_operation::tuple_holding_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override
+  {
+    return value_of_this (exp->language_defn);
+  }
+
+  enum exp_opcode opcode () const override
+  { return OP_THIS; }
+
+protected:
+
+  void do_generate_ax (struct expression *exp,
+		       struct agent_expr *ax,
+		       struct axs_value *value,
+		       struct type *cast_type)
+    override;
+};
+
 } /* namespace expr */
 
 #endif /* EXPOP_H */
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 116/203] Introduce type_instance_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (114 preceding siblings ...)
  2021-01-01 21:45 ` [PATCH 115/203] Introduce op_this_operation Tom Tromey
@ 2021-01-01 21:45 ` Tom Tromey
  2021-01-01 21:45 ` [PATCH 117/203] Introduce assign_operation Tom Tromey
                   ` (87 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:45 UTC (permalink / raw)
  To: gdb-patches

This adds class type_instance_operation, which implements
TYPE_INSTANCE.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* expop.h (class type_instance_operation): New.
	* eval.c (type_instance_operation::evaluate): New method.
---
 gdb/ChangeLog |  5 +++++
 gdb/eval.c    | 18 ++++++++++++++++++
 gdb/expop.h   | 17 +++++++++++++++++
 3 files changed, 40 insertions(+)

diff --git a/gdb/eval.c b/gdb/eval.c
index 1ada2f3986b..65214a2bd3a 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -633,6 +633,24 @@ fake_method::~fake_method ()
   xfree (m_type.fields ());
 }
 
+namespace expr
+{
+
+value *
+type_instance_operation::evaluate (struct type *expect_type,
+				   struct expression *exp,
+				   enum noside noside)
+{
+  type_instance_flags flags = std::get<0> (m_storage);
+  std::vector<type *> &types = std::get<1> (m_storage);
+
+  fake_method fake_expect_type (flags, types.size (), types.data ());
+  return std::get<2> (m_storage)->evaluate (fake_expect_type.type (),
+					    exp, noside);
+}
+
+}
+
 /* Helper for evaluating an OP_VAR_VALUE.  */
 
 value *
diff --git a/gdb/expop.h b/gdb/expop.h
index 394191ce6e5..e172e11a828 100644
--- a/gdb/expop.h
+++ b/gdb/expop.h
@@ -1729,6 +1729,23 @@ class op_this_operation
     override;
 };
 
+/* Implement the "type instance" operation.  */
+class type_instance_operation
+  : public tuple_holding_operation<type_instance_flags, std::vector<type *>,
+				   operation_up>
+{
+public:
+
+  using tuple_holding_operation::tuple_holding_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override;
+
+  enum exp_opcode opcode () const override
+  { return TYPE_INSTANCE; }
+};
+
 } /* namespace expr */
 
 #endif /* EXPOP_H */
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 117/203] Introduce assign_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (115 preceding siblings ...)
  2021-01-01 21:45 ` [PATCH 116/203] Introduce type_instance_operation Tom Tromey
@ 2021-01-01 21:45 ` Tom Tromey
  2021-01-01 21:45 ` [PATCH 118/203] Introduce assign_modify_operation Tom Tromey
                   ` (86 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:45 UTC (permalink / raw)
  To: gdb-patches

This adds class assign_operation, which implements BINOP_ASSIGN.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* expop.h (class assign_operation): New.
	* ax-gdb.c (assign_operation::do_generate_ax): New method.
---
 gdb/ChangeLog |  5 +++++
 gdb/ax-gdb.c  | 30 ++++++++++++++++++++++++++++++
 gdb/expop.h   | 43 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 78 insertions(+)

diff --git a/gdb/ax-gdb.c b/gdb/ax-gdb.c
index 98edc6c0727..d8b5ed78a40 100644
--- a/gdb/ax-gdb.c
+++ b/gdb/ax-gdb.c
@@ -2579,6 +2579,36 @@ op_this_operation::do_generate_ax (struct expression *exp,
 	   sym->print_name ());
 }
 
+void
+assign_operation::do_generate_ax (struct expression *exp,
+				  struct agent_expr *ax,
+				  struct axs_value *value,
+				  struct type *cast_type)
+{
+  operation *subop = std::get<0> (m_storage).get ();
+  if (subop->opcode () != OP_INTERNALVAR)
+    error (_("May only assign to trace state variables"));
+
+  internalvar_operation *ivarop
+    = dynamic_cast<internalvar_operation *> (subop);
+  gdb_assert (ivarop != nullptr);
+
+  const char *name = internalvar_name (ivarop->get_internalvar ());
+  struct trace_state_variable *tsv;
+
+  std::get<1> (m_storage)->generate_ax (exp, ax, value);
+  tsv = find_trace_state_variable (name);
+  if (tsv)
+    {
+      ax_tsv (ax, aop_setv, tsv->number);
+      if (ax->tracing)
+	ax_tsv (ax, aop_tracev, tsv->number);
+    }
+  else
+    error (_("$%s is not a trace state variable, "
+	     "may not assign to it"), name);
+}
+
 }
 
 /* This handles the middle-to-right-side of code generation for binary
diff --git a/gdb/expop.h b/gdb/expop.h
index e172e11a828..5acbca3db61 100644
--- a/gdb/expop.h
+++ b/gdb/expop.h
@@ -1746,6 +1746,49 @@ class type_instance_operation
   { return TYPE_INSTANCE; }
 };
 
+/* The assignment operator.  */
+class assign_operation
+  : public tuple_holding_operation<operation_up, operation_up>
+{
+public:
+
+  using tuple_holding_operation::tuple_holding_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override
+  {
+    value *lhs = std::get<0> (m_storage)->evaluate (nullptr, exp, noside);
+    /* Special-case assignments where the left-hand-side is a
+       convenience variable -- in these, don't bother setting an
+       expected type.  This avoids a weird case where re-assigning a
+       string or array to an internal variable could error with "Too
+       many array elements".  */
+    struct type *xtype = (VALUE_LVAL (lhs) == lval_internalvar
+			  ? nullptr
+			  : value_type (lhs));
+    value *rhs = std::get<1> (m_storage)->evaluate (xtype, exp, noside);
+
+    if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS)
+      return lhs;
+    if (binop_user_defined_p (BINOP_ASSIGN, lhs, rhs))
+      return value_x_binop (lhs, rhs, BINOP_ASSIGN, OP_NULL, noside);
+    else
+      return value_assign (lhs, rhs);
+  }
+
+  enum exp_opcode opcode () const override
+  { return BINOP_ASSIGN; }
+
+protected:
+
+  void do_generate_ax (struct expression *exp,
+		       struct agent_expr *ax,
+		       struct axs_value *value,
+		       struct type *cast_type)
+    override;
+};
+
 } /* namespace expr */
 
 #endif /* EXPOP_H */
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 118/203] Introduce assign_modify_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (116 preceding siblings ...)
  2021-01-01 21:45 ` [PATCH 117/203] Introduce assign_operation Tom Tromey
@ 2021-01-01 21:45 ` Tom Tromey
  2021-01-01 21:45 ` [PATCH 119/203] Introduce unop_cast_operation Tom Tromey
                   ` (85 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:45 UTC (permalink / raw)
  To: gdb-patches

This adds class assign_modify_operation, which implements
BINOP_ASSIGN_MODIFY.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* expop.h (class assign_modify_operation): New.
	* eval.c (eval_binop_assign_modify): No longer static.
	* ax-gdb.c (assign_modify_operation::do_generate_ax): New method.
---
 gdb/ChangeLog |  6 ++++++
 gdb/ax-gdb.c  | 42 ++++++++++++++++++++++++++++++++++++++++++
 gdb/eval.c    |  2 +-
 gdb/expop.h   | 36 ++++++++++++++++++++++++++++++++++++
 4 files changed, 85 insertions(+), 1 deletion(-)

diff --git a/gdb/ax-gdb.c b/gdb/ax-gdb.c
index d8b5ed78a40..f81e5b9ad29 100644
--- a/gdb/ax-gdb.c
+++ b/gdb/ax-gdb.c
@@ -2609,6 +2609,48 @@ assign_operation::do_generate_ax (struct expression *exp,
 	     "may not assign to it"), name);
 }
 
+void
+assign_modify_operation::do_generate_ax (struct expression *exp,
+					 struct agent_expr *ax,
+					 struct axs_value *value,
+					 struct type *cast_type)
+{
+  operation *subop = std::get<1> (m_storage).get ();
+  if (subop->opcode () != OP_INTERNALVAR)
+    error (_("May only assign to trace state variables"));
+
+  internalvar_operation *ivarop
+    = dynamic_cast<internalvar_operation *> (subop);
+  gdb_assert (ivarop != nullptr);
+
+  const char *name = internalvar_name (ivarop->get_internalvar ());
+  struct trace_state_variable *tsv;
+
+  tsv = find_trace_state_variable (name);
+  if (tsv)
+    {
+      /* The tsv will be the left half of the binary operation.  */
+      ax_tsv (ax, aop_getv, tsv->number);
+      if (ax->tracing)
+	ax_tsv (ax, aop_tracev, tsv->number);
+      /* Trace state variables are always 64-bit integers.  */
+      struct axs_value value1, value2;
+      value1.kind = axs_rvalue;
+      value1.type = builtin_type (ax->gdbarch)->builtin_long_long;
+      /* Now do right half of expression.  */
+      std::get<2> (m_storage)->generate_ax (exp, ax, &value2);
+      gen_expr_binop_rest (exp, std::get<0> (m_storage), ax,
+			   value, &value1, &value2);
+      /* We have a result of the binary op, set the tsv.  */
+      ax_tsv (ax, aop_setv, tsv->number);
+      if (ax->tracing)
+	ax_tsv (ax, aop_tracev, tsv->number);
+    }
+  else
+    error (_("$%s is not a trace state variable, "
+	     "may not assign to it"), name);
+}
+
 }
 
 /* This handles the middle-to-right-side of code generation for binary
diff --git a/gdb/eval.c b/gdb/eval.c
index 65214a2bd3a..51a737ac5a5 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -2049,7 +2049,7 @@ eval_op_type (struct type *expect_type, struct expression *exp,
 
 /* A helper function for BINOP_ASSIGN_MODIFY.  */
 
-static struct value *
+struct value *
 eval_binop_assign_modify (struct type *expect_type, struct expression *exp,
 			  enum noside noside, enum exp_opcode op,
 			  struct value *arg1, struct value *arg2)
diff --git a/gdb/expop.h b/gdb/expop.h
index 5acbca3db61..b0ed119a989 100644
--- a/gdb/expop.h
+++ b/gdb/expop.h
@@ -196,6 +196,12 @@ extern struct value *eval_op_memval (struct type *expect_type,
 				     struct expression *exp,
 				     enum noside noside,
 				     struct value *arg1, struct type *type);
+extern struct value *eval_binop_assign_modify (struct type *expect_type,
+					       struct expression *exp,
+					       enum noside noside,
+					       enum exp_opcode op,
+					       struct value *arg1,
+					       struct value *arg2);
 
 namespace expr
 {
@@ -1789,6 +1795,36 @@ class assign_operation
     override;
 };
 
+/* Assignment with modification, like "+=".  */
+class assign_modify_operation
+  : public tuple_holding_operation<exp_opcode, operation_up, operation_up>
+{
+public:
+
+  using tuple_holding_operation::tuple_holding_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override
+  {
+    value *lhs = std::get<1> (m_storage)->evaluate (nullptr, exp, noside);
+    value *rhs = std::get<2> (m_storage)->evaluate (expect_type, exp, noside);
+    return eval_binop_assign_modify (expect_type, exp, noside,
+				     std::get<0> (m_storage), lhs, rhs);
+  }
+
+  enum exp_opcode opcode () const override
+  { return BINOP_ASSIGN_MODIFY; }
+
+protected:
+
+  void do_generate_ax (struct expression *exp,
+		       struct agent_expr *ax,
+		       struct axs_value *value,
+		       struct type *cast_type)
+    override;
+};
+
 } /* namespace expr */
 
 #endif /* EXPOP_H */
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 119/203] Introduce unop_cast_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (117 preceding siblings ...)
  2021-01-01 21:45 ` [PATCH 118/203] Introduce assign_modify_operation Tom Tromey
@ 2021-01-01 21:45 ` Tom Tromey
  2021-01-01 21:46 ` [PATCH 120/203] Introduce unop_cast_type_operation Tom Tromey
                   ` (84 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:45 UTC (permalink / raw)
  To: gdb-patches

This adds class unop_cast_operation, which implements UNOP_CAST.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* expop.h (class unop_cast_operation): New.
	* ax-gdb.c (unop_cast_operation::do_generate_ax): New method.
---
 gdb/ChangeLog |  5 +++++
 gdb/ax-gdb.c  | 10 ++++++++++
 gdb/expop.h   | 28 ++++++++++++++++++++++++++++
 3 files changed, 43 insertions(+)

diff --git a/gdb/ax-gdb.c b/gdb/ax-gdb.c
index f81e5b9ad29..84887da524f 100644
--- a/gdb/ax-gdb.c
+++ b/gdb/ax-gdb.c
@@ -2514,6 +2514,16 @@ unop_sizeof_operation::do_generate_ax (struct expression *exp,
   value->type = builtin_type (ax->gdbarch)->builtin_int;
 }
 
+void
+unop_cast_operation::do_generate_ax (struct expression *exp,
+				     struct agent_expr *ax,
+				     struct axs_value *value,
+				     struct type *cast_type)
+{
+  std::get<0> (m_storage)->generate_ax (exp, ax, value,
+					std::get<1> (m_storage));
+}
+
 void
 unop_memval_operation::do_generate_ax (struct expression *exp,
 				       struct agent_expr *ax,
diff --git a/gdb/expop.h b/gdb/expop.h
index b0ed119a989..664812aec19 100644
--- a/gdb/expop.h
+++ b/gdb/expop.h
@@ -1825,6 +1825,34 @@ class assign_modify_operation
     override;
 };
 
+/* A type cast.  */
+class unop_cast_operation
+  : public maybe_constant_operation<operation_up, struct type *>
+{
+public:
+
+  using maybe_constant_operation::maybe_constant_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override
+  {
+    return std::get<0> (m_storage)->evaluate_for_cast (std::get<1> (m_storage),
+						       exp, noside);
+  }
+
+  enum exp_opcode opcode () const override
+  { return UNOP_CAST; }
+
+protected:
+
+  void do_generate_ax (struct expression *exp,
+		       struct agent_expr *ax,
+		       struct axs_value *value,
+		       struct type *cast_type)
+    override;
+};
+
 } /* namespace expr */
 
 #endif /* EXPOP_H */
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 120/203] Introduce unop_cast_type_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (118 preceding siblings ...)
  2021-01-01 21:45 ` [PATCH 119/203] Introduce unop_cast_operation Tom Tromey
@ 2021-01-01 21:46 ` Tom Tromey
  2021-01-01 21:46 ` [PATCH 121/203] Implement C++ cast operations Tom Tromey
                   ` (83 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:46 UTC (permalink / raw)
  To: gdb-patches

This adds class unop_cast_type_operation, which implements
UNOP_CAST_TYPE.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* expop.h (class unop_cast_type_operation): New.
	* ax-gdb.c (unop_cast_type_operation::do_generate_ax): New
	method.
---
 gdb/ChangeLog |  6 ++++++
 gdb/ax-gdb.c  | 12 ++++++++++++
 gdb/expop.h   | 31 +++++++++++++++++++++++++++++++
 3 files changed, 49 insertions(+)

diff --git a/gdb/ax-gdb.c b/gdb/ax-gdb.c
index 84887da524f..e0970e87d68 100644
--- a/gdb/ax-gdb.c
+++ b/gdb/ax-gdb.c
@@ -2661,6 +2661,18 @@ assign_modify_operation::do_generate_ax (struct expression *exp,
 	     "may not assign to it"), name);
 }
 
+void
+unop_cast_type_operation::do_generate_ax (struct expression *exp,
+					  struct agent_expr *ax,
+					  struct axs_value *value,
+					  struct type *cast_type)
+{
+  struct value *val
+    = std::get<0> (m_storage)->evaluate (nullptr, exp,
+					 EVAL_AVOID_SIDE_EFFECTS);
+  std::get<1> (m_storage)->generate_ax (exp, ax, value, value_type (val));
+}
+
 }
 
 /* This handles the middle-to-right-side of code generation for binary
diff --git a/gdb/expop.h b/gdb/expop.h
index 664812aec19..9102f2bb66d 100644
--- a/gdb/expop.h
+++ b/gdb/expop.h
@@ -1853,6 +1853,37 @@ class unop_cast_operation
     override;
 };
 
+/* A cast, but the type comes from an expression, not a "struct
+   type".  */
+class unop_cast_type_operation
+  : public maybe_constant_operation<operation_up, operation_up>
+{
+public:
+
+  using maybe_constant_operation::maybe_constant_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override
+  {
+    value *val = std::get<0> (m_storage)->evaluate (nullptr, exp,
+						    EVAL_AVOID_SIDE_EFFECTS);
+    return std::get<1> (m_storage)->evaluate_for_cast (value_type (val),
+						       exp, noside);
+  }
+
+  enum exp_opcode opcode () const override
+  { return UNOP_CAST_TYPE; }
+
+protected:
+
+  void do_generate_ax (struct expression *exp,
+		       struct agent_expr *ax,
+		       struct axs_value *value,
+		       struct type *cast_type)
+    override;
+};
+
 } /* namespace expr */
 
 #endif /* EXPOP_H */
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 121/203] Implement C++ cast operations
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (119 preceding siblings ...)
  2021-01-01 21:46 ` [PATCH 120/203] Introduce unop_cast_type_operation Tom Tromey
@ 2021-01-01 21:46 ` Tom Tromey
  2021-01-01 21:46 ` [PATCH 122/203] Introduce var_value_operation Tom Tromey
                   ` (82 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:46 UTC (permalink / raw)
  To: gdb-patches

This adds class cxx_cast_operation, which is used to implement the C++
dynamic_cast and reinterpret_cast operations.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* expop.h (cxx_cast_ftype): New typedef.
	(cxx_cast_operation): New template.
	(dynamic_cast_operation, reinterpret_cast_operation): New
	typedefs.
---
 gdb/ChangeLog |  7 +++++++
 gdb/expop.h   | 34 ++++++++++++++++++++++++++++++++++
 2 files changed, 41 insertions(+)

diff --git a/gdb/expop.h b/gdb/expop.h
index 9102f2bb66d..53ff93c4b83 100644
--- a/gdb/expop.h
+++ b/gdb/expop.h
@@ -1884,6 +1884,40 @@ class unop_cast_type_operation
     override;
 };
 
+typedef value *cxx_cast_ftype (struct type *, value *);
+
+/* This implements dynamic_cast and reinterpret_cast.  static_cast and
+   const_cast are handled by the ordinary case operations.  */
+template<exp_opcode OP, cxx_cast_ftype FUNC>
+class cxx_cast_operation
+  : public maybe_constant_operation<operation_up, operation_up>
+{
+public:
+
+  using maybe_constant_operation::maybe_constant_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override
+  {
+    value *val = std::get<0> (m_storage)->evaluate (nullptr, exp,
+						    EVAL_AVOID_SIDE_EFFECTS);
+    struct type *type = value_type (val);
+    value *rhs = std::get<1> (m_storage)->evaluate (type, exp, noside);
+    if (noside == EVAL_SKIP)
+      return eval_skip_value (exp);
+    return FUNC (type, rhs);
+  }
+
+  enum exp_opcode opcode () const override
+  { return OP; }
+};
+
+using dynamic_cast_operation = cxx_cast_operation<UNOP_DYNAMIC_CAST,
+						  value_dynamic_cast>;
+using reinterpret_cast_operation = cxx_cast_operation<UNOP_REINTERPRET_CAST,
+						      value_reinterpret_cast>;
+
 } /* namespace expr */
 
 #endif /* EXPOP_H */
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 122/203] Introduce var_value_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (120 preceding siblings ...)
  2021-01-01 21:46 ` [PATCH 121/203] Implement C++ cast operations Tom Tromey
@ 2021-01-01 21:46 ` Tom Tromey
  2021-01-01 21:46 ` [PATCH 123/203] Introduce objc_msgcall_operation Tom Tromey
                   ` (81 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:46 UTC (permalink / raw)
  To: gdb-patches

This adds class var_value_operation, which implements OP_VAR_VALUE.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* expop.h (class var_value_operation): New.
	* eval.c (var_value_operation::evaluate)
	(var_value_operation::evaluate_for_address)
	(var_value_operation::evaluate_with_coercion)
	(var_value_operation::evaluate_for_sizeof)
	(var_value_operation::evaluate_for_cast): New methods.
	* ax-gdb.c (var_value_operation::do_generate_ax): New method.
---
 gdb/ChangeLog |  10 +++++
 gdb/ax-gdb.c  |  20 +++++++++
 gdb/eval.c    | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/expop.h   |  45 +++++++++++++++++++++
 4 files changed, 185 insertions(+)

diff --git a/gdb/ax-gdb.c b/gdb/ax-gdb.c
index e0970e87d68..bdf4a6dc39a 100644
--- a/gdb/ax-gdb.c
+++ b/gdb/ax-gdb.c
@@ -2673,6 +2673,26 @@ unop_cast_type_operation::do_generate_ax (struct expression *exp,
   std::get<1> (m_storage)->generate_ax (exp, ax, value, value_type (val));
 }
 
+void
+var_value_operation::do_generate_ax (struct expression *exp,
+				     struct agent_expr *ax,
+				     struct axs_value *value,
+				     struct type *cast_type)
+{
+  gen_var_ref (ax, value, std::get<0> (m_storage));
+
+  if (value->optimized_out)
+    error (_("`%s' has been optimized out, cannot use"),
+	   std::get<0> (m_storage)->print_name ());
+
+  if (value->type->code () == TYPE_CODE_ERROR)
+    {
+      if (cast_type == nullptr)
+	error_unknown_type (std::get<0> (m_storage)->print_name ());
+      value->type = cast_type;
+    }
+}
+
 }
 
 /* This handles the middle-to-right-side of code generation for binary
diff --git a/gdb/eval.c b/gdb/eval.c
index 51a737ac5a5..4b12875f00c 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -683,6 +683,23 @@ evaluate_var_value (enum noside noside, const block *blk, symbol *var)
   return ret;
 }
 
+namespace expr
+
+{
+
+value *
+var_value_operation::evaluate (struct type *expect_type,
+			       struct expression *exp,
+			       enum noside noside)
+{
+  symbol *var = std::get<0> (m_storage);
+  if (SYMBOL_TYPE (var)->code () == TYPE_CODE_ERROR)
+    error_unknown_type (var->print_name ());
+  return evaluate_var_value (noside, std::get<1> (m_storage), var);
+}
+
+} /* namespace expr */
+
 /* Helper for evaluating an OP_VAR_MSYM_VALUE.  */
 
 value *
@@ -3392,6 +3409,54 @@ evaluate_subexp_with_coercion (struct expression *exp,
     }
 }
 
+namespace expr
+{
+
+value *
+var_value_operation::evaluate_for_address (struct expression *exp,
+					   enum noside noside)
+{
+  symbol *var = std::get<0> (m_storage);
+
+  /* C++: The "address" of a reference should yield the address
+   * of the object pointed to.  Let value_addr() deal with it.  */
+  if (TYPE_IS_REFERENCE (SYMBOL_TYPE (var)))
+    return operation::evaluate_for_address (exp, noside);
+
+  if (noside == EVAL_AVOID_SIDE_EFFECTS)
+    {
+      struct type *type = lookup_pointer_type (SYMBOL_TYPE (var));
+      enum address_class sym_class = SYMBOL_CLASS (var);
+
+      if (sym_class == LOC_CONST
+	  || sym_class == LOC_CONST_BYTES
+	  || sym_class == LOC_REGISTER)
+	error (_("Attempt to take address of register or constant."));
+
+      return value_zero (type, not_lval);
+    }
+  else
+    return address_of_variable (var, std::get<1> (m_storage));
+}
+
+value *
+var_value_operation::evaluate_with_coercion (struct expression *exp,
+					     enum noside noside)
+{
+  struct symbol *var = std::get<0> (m_storage);
+  struct type *type = check_typedef (SYMBOL_TYPE (var));
+  if (type->code () == TYPE_CODE_ARRAY
+      && !type->is_vector ()
+      && CAST_IS_CONVERSION (exp->language_defn))
+    {
+      struct value *val = address_of_variable (var, std::get<1> (m_storage));
+      return value_cast (lookup_pointer_type (TYPE_TARGET_TYPE (type)), val);
+    }
+  return evaluate (nullptr, exp, noside);
+}
+
+}
+
 /* Helper function for evaluating the size of a type.  */
 
 static value *
@@ -3632,6 +3697,27 @@ unop_memval_type_operation::evaluate_for_sizeof (struct expression *exp,
   return evaluate_subexp_for_sizeof_base (exp, value_type (typeval));
 }
 
+value *
+var_value_operation::evaluate_for_sizeof (struct expression *exp,
+					  enum noside noside)
+{
+  struct type *type = SYMBOL_TYPE (std::get<0> (m_storage));
+  if (is_dynamic_type (type))
+    {
+      value *val = evaluate (nullptr, exp, EVAL_NORMAL);
+      type = value_type (val);
+      if (type->code () == TYPE_CODE_ARRAY
+	  && is_dynamic_type (type->index_type ())
+	  && type->bounds ()->high.kind () == PROP_UNDEFINED)
+	{
+	  /* FIXME: This should be size_t.  */
+	  struct type *size_type = builtin_type (exp->gdbarch)->builtin_int;
+	  return allocate_optimized_out_value (size_type);
+	}
+    }
+  return evaluate_subexp_for_sizeof_base (exp, type);
+}
+
 }
 
 /* Evaluate a subexpression of EXP, at index *POS, and return a value
@@ -3719,6 +3805,30 @@ var_msym_value_operation::evaluate_for_cast (struct type *to_type,
   return val;
 }
 
+value *
+var_value_operation::evaluate_for_cast (struct type *to_type,
+					struct expression *exp,
+					enum noside noside)
+{
+  value *val = evaluate_var_value (noside,
+				   std::get<1> (m_storage),
+				   std::get<0> (m_storage));
+
+  if (noside == EVAL_SKIP)
+    return eval_skip_value (exp);
+
+  val = value_cast (to_type, val);
+
+  /* Don't allow e.g. '&(int)var_with_no_debug_info'.  */
+  if (VALUE_LVAL (val) == lval_memory)
+    {
+      if (value_lazy (val))
+	value_fetch_lazy (val);
+      VALUE_LVAL (val) = not_lval;
+    }
+  return val;
+}
+
 }
 
 /* Parse a type expression in the string [P..P+LENGTH).  */
diff --git a/gdb/expop.h b/gdb/expop.h
index 53ff93c4b83..0c489c77450 100644
--- a/gdb/expop.h
+++ b/gdb/expop.h
@@ -606,6 +606,51 @@ class scope_operation
     override;
 };
 
+/* Compute the value of a variable.  */
+class var_value_operation
+  : public tuple_holding_operation<symbol *, const block *>
+{
+public:
+
+  using tuple_holding_operation::tuple_holding_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override;
+
+  value *evaluate_with_coercion (struct expression *exp,
+				 enum noside noside) override;
+
+  value *evaluate_for_sizeof (struct expression *exp, enum noside noside)
+    override;
+
+  value *evaluate_for_cast (struct type *expect_type,
+			    struct expression *exp,
+			    enum noside noside) override;
+
+  value *evaluate_for_address (struct expression *exp, enum noside noside)
+    override;
+
+  enum exp_opcode opcode () const override
+  { return OP_VAR_VALUE; }
+
+  bool constant_p () const override
+  {
+    symbol *sym = std::get<0> (m_storage);
+    return (SYMBOL_CLASS (sym) == LOC_CONST
+	    || SYMBOL_CLASS (sym) == LOC_CONST_BYTES
+	    || SYMBOL_CLASS (sym) == LOC_LABEL);
+  }
+
+protected:
+
+  void do_generate_ax (struct expression *exp,
+		       struct agent_expr *ax,
+		       struct axs_value *value,
+		       struct type *cast_type)
+    override;
+};
+
 class long_const_operation
   : public tuple_holding_operation<struct type *, LONGEST>
 {
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 123/203] Introduce objc_msgcall_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (121 preceding siblings ...)
  2021-01-01 21:46 ` [PATCH 122/203] Introduce var_value_operation Tom Tromey
@ 2021-01-01 21:46 ` Tom Tromey
  2021-01-01 21:46 ` [PATCH 124/203] Introduce multi_subscript_operation Tom Tromey
                   ` (80 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:46 UTC (permalink / raw)
  To: gdb-patches

This adds class objc_msgcall_operation, which implements
OP_OBJC_MSGCALL.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* eval.c (objc_msgcall_operation::evaluate): New method.
	* c-exp.h (class objc_msgcall_operation): New.
---
 gdb/ChangeLog |  5 +++++
 gdb/c-exp.h   | 17 +++++++++++++++++
 gdb/eval.c    | 39 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 61 insertions(+)

diff --git a/gdb/c-exp.h b/gdb/c-exp.h
index dcb4557b2d5..2d224c8c633 100644
--- a/gdb/c-exp.h
+++ b/gdb/c-exp.h
@@ -88,6 +88,23 @@ class objc_selector_operation
   { return OP_OBJC_SELECTOR; }
 };
 
+/* An Objective C message call.  */
+class objc_msgcall_operation
+  : public tuple_holding_operation<CORE_ADDR, operation_up,
+				   std::vector<operation_up>>
+{
+public:
+
+  using tuple_holding_operation::tuple_holding_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override;
+
+  enum exp_opcode opcode () const override
+  { return OP_OBJC_MSGCALL; }
+};
+
 }/* namespace expr */
 
 #endif /* C_EXP_H */
diff --git a/gdb/eval.c b/gdb/eval.c
index 4b12875f00c..05fc1972a0e 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -2411,6 +2411,45 @@ eval_multi_subscript (struct type *expect_type, struct expression *exp,
   return (arg1);
 }
 
+namespace expr
+{
+
+value *
+objc_msgcall_operation::evaluate (struct type *expect_type,
+				  struct expression *exp,
+				  enum noside noside)
+{
+  enum noside sub_no_side = EVAL_NORMAL;
+  struct type *selector_type = builtin_type (exp->gdbarch)->builtin_data_ptr;
+
+  if (noside == EVAL_AVOID_SIDE_EFFECTS)
+    sub_no_side = EVAL_NORMAL;
+  else
+    sub_no_side = noside;
+  value *target
+    = std::get<1> (m_storage)->evaluate (selector_type, exp, sub_no_side);
+
+  if (value_as_long (target) == 0)
+    sub_no_side = EVAL_AVOID_SIDE_EFFECTS;
+  else
+    sub_no_side = noside;
+  std::vector<operation_up> &args = std::get<2> (m_storage);
+  value **argvec = XALLOCAVEC (struct value *, args.size () + 3);
+  argvec[0] = nullptr;
+  argvec[1] = nullptr;
+  for (int i = 0; i < args.size (); ++i)
+    argvec[i + 2] = args[i]->evaluate_with_coercion (exp, sub_no_side);
+  argvec[args.size () + 2] = nullptr;
+
+  return eval_op_objc_msgcall (expect_type, exp, noside, std::
+			       get<0> (m_storage), target,
+			       gdb::make_array_view (argvec,
+						     args.size () + 3));
+}
+
+}
+
+
 struct value *
 evaluate_subexp_standard (struct type *expect_type,
 			  struct expression *exp, int *pos,
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 124/203] Introduce multi_subscript_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (122 preceding siblings ...)
  2021-01-01 21:46 ` [PATCH 123/203] Introduce objc_msgcall_operation Tom Tromey
@ 2021-01-01 21:46 ` Tom Tromey
  2021-01-01 21:46 ` [PATCH 125/203] Introduce ada_wrapped_operation Tom Tromey
                   ` (79 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:46 UTC (permalink / raw)
  To: gdb-patches

This adds class multi_subscript_operation, which implements
MULTI_SUBSCRIPT.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* expop.h (class multi_subscript_operation): New.
	* eval.c (multi_subscript_operation::evaluate): New method.
---
 gdb/ChangeLog |  5 +++++
 gdb/eval.c    | 13 +++++++++++++
 gdb/expop.h   | 16 ++++++++++++++++
 3 files changed, 34 insertions(+)

diff --git a/gdb/eval.c b/gdb/eval.c
index 05fc1972a0e..b1087d1329d 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -2447,8 +2447,21 @@ objc_msgcall_operation::evaluate (struct type *expect_type,
 						     args.size () + 3));
 }
 
+value *
+multi_subscript_operation::evaluate (struct type *expect_type,
+				     struct expression *exp,
+				     enum noside noside)
+{
+  value *arg1 = std::get<0> (m_storage)->evaluate_with_coercion (exp, noside);
+  std::vector<operation_up> &values = std::get<1> (m_storage);
+  value **argvec = XALLOCAVEC (struct value *, values.size ());
+  for (int ix = 0; ix < values.size (); ++ix)
+    argvec[ix] = values[ix]->evaluate_with_coercion (exp, noside);
+  return eval_multi_subscript (expect_type, exp, noside, arg1,
+			       gdb::make_array_view (argvec, values.size ()));
 }
 
+}
 
 struct value *
 evaluate_subexp_standard (struct type *expect_type,
diff --git a/gdb/expop.h b/gdb/expop.h
index 0c489c77450..21c7b9e25da 100644
--- a/gdb/expop.h
+++ b/gdb/expop.h
@@ -1963,6 +1963,22 @@ using dynamic_cast_operation = cxx_cast_operation<UNOP_DYNAMIC_CAST,
 using reinterpret_cast_operation = cxx_cast_operation<UNOP_REINTERPRET_CAST,
 						      value_reinterpret_cast>;
 
+/* Multi-dimensional subscripting.  */
+class multi_subscript_operation
+  : public tuple_holding_operation<operation_up, std::vector<operation_up>>
+{
+public:
+
+  using tuple_holding_operation::tuple_holding_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override;
+
+  enum exp_opcode opcode () const override
+  { return MULTI_SUBSCRIPT; }
+};
+
 } /* namespace expr */
 
 #endif /* EXPOP_H */
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 125/203] Introduce ada_wrapped_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (123 preceding siblings ...)
  2021-01-01 21:46 ` [PATCH 124/203] Introduce multi_subscript_operation Tom Tromey
@ 2021-01-01 21:46 ` Tom Tromey
  2021-01-01 21:46 ` [PATCH 126/203] Introduce ada_string_operation Tom Tromey
                   ` (78 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:46 UTC (permalink / raw)
  To: gdb-patches

This adds class ada_wrapped_operation, which is used to wrap some
generic operations with a bit of Ada-specific handling.  This
corresponds to the old "default" case in ada_evaluate_subexp.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* ada-lang.c (ada_wrapped_operation::evaluate): New method.
	* ada-exp.h: New file.
---
 gdb/ChangeLog  |  5 +++++
 gdb/ada-exp.h  | 47 +++++++++++++++++++++++++++++++++++++++++++++++
 gdb/ada-lang.c | 29 +++++++++++++++++++++++++++++
 3 files changed, 81 insertions(+)
 create mode 100644 gdb/ada-exp.h

diff --git a/gdb/ada-exp.h b/gdb/ada-exp.h
new file mode 100644
index 00000000000..3f780dc9ff4
--- /dev/null
+++ b/gdb/ada-exp.h
@@ -0,0 +1,47 @@
+/* Definitions for Ada expressions
+
+   Copyright (C) 2020 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 ADA_EXP_H
+#define ADA_EXP_H
+
+#include "expop.h"
+
+namespace expr
+{
+
+/* In Ada, some generic operations must be wrapped with a handler that
+   handles some Ada-specific type conversions.  */
+class ada_wrapped_operation
+  : public tuple_holding_operation<operation_up>
+{
+public:
+
+  using tuple_holding_operation::tuple_holding_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override;
+
+  enum exp_opcode opcode () const override
+  { return std::get<0> (m_storage)->opcode (); }
+};
+
+} /* namespace expr */
+
+#endif /* ADA_EXP_H */
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index e46c2bdbbe5..7855cd32eb3 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -57,6 +57,7 @@
 #include "gdbsupport/function-view.h"
 #include "gdbsupport/byte-vector.h"
 #include <algorithm>
+#include "ada-exp.h"
 
 /* Define whether or not the C operator '/' truncates towards zero for
    differently signed operands (truncation direction is undefined in C).
@@ -10543,6 +10544,34 @@ ada_binop_exp (struct type *expect_type,
     }
 }
 
+namespace expr
+{
+
+value *
+ada_wrapped_operation::evaluate (struct type *expect_type,
+				 struct expression *exp,
+				 enum noside noside)
+{
+  value *result = std::get<0> (m_storage)->evaluate (expect_type, exp, noside);
+  if (noside == EVAL_NORMAL)
+    result = unwrap_value (result);
+
+  /* If evaluating an OP_FLOAT and an EXPECT_TYPE was provided,
+     then we need to perform the conversion manually, because
+     evaluate_subexp_standard doesn't do it.  This conversion is
+     necessary in Ada because the different kinds of float/fixed
+     types in Ada have different representations.
+
+     Similarly, we need to perform the conversion from OP_LONG
+     ourselves.  */
+  if ((opcode () == OP_FLOAT || opcode () == OP_LONG) && expect_type != NULL)
+    result = ada_value_cast (expect_type, result);
+
+  return result;
+}
+
+}
+
 /* Implement the evaluate_exp routine in the exp_descriptor structure
    for the Ada language.  */
 
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 126/203] Introduce ada_string_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (124 preceding siblings ...)
  2021-01-01 21:46 ` [PATCH 125/203] Introduce ada_wrapped_operation Tom Tromey
@ 2021-01-01 21:46 ` Tom Tromey
  2021-01-01 21:46 ` [PATCH 127/203] Introduce ada_qual_operation Tom Tromey
                   ` (77 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:46 UTC (permalink / raw)
  To: gdb-patches

This adds class ada_string_operation, which implements string
constants for Ada.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* ada-lang.c (ada_string_operation::evaluate): New method.
	* ada-exp.h (class ada_string_operation): New.
---
 gdb/ChangeLog  |  5 +++++
 gdb/ada-exp.h  | 13 +++++++++++++
 gdb/ada-lang.c | 13 +++++++++++++
 3 files changed, 31 insertions(+)

diff --git a/gdb/ada-exp.h b/gdb/ada-exp.h
index 3f780dc9ff4..88ed0c53b46 100644
--- a/gdb/ada-exp.h
+++ b/gdb/ada-exp.h
@@ -42,6 +42,19 @@ class ada_wrapped_operation
   { return std::get<0> (m_storage)->opcode (); }
 };
 
+/* An Ada string constant.  */
+class ada_string_operation
+  : public string_operation
+{
+public:
+
+  using string_operation::string_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override;
+};
+
 } /* namespace expr */
 
 #endif /* ADA_EXP_H */
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 7855cd32eb3..d74c11f9a36 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -10570,6 +10570,19 @@ ada_wrapped_operation::evaluate (struct type *expect_type,
   return result;
 }
 
+value *
+ada_string_operation::evaluate (struct type *expect_type,
+				struct expression *exp,
+				enum noside noside)
+{
+  value *result = string_operation::evaluate (expect_type, exp, noside);
+  /* The result type will have code OP_STRING, bashed there from 
+     OP_ARRAY.  Bash it back.  */
+  if (value_type (result)->code () == TYPE_CODE_STRING)
+    value_type (result)->set_code (TYPE_CODE_ARRAY);
+  return result;
+}
+
 }
 
 /* Implement the evaluate_exp routine in the exp_descriptor structure
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 127/203] Introduce ada_qual_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (125 preceding siblings ...)
  2021-01-01 21:46 ` [PATCH 126/203] Introduce ada_string_operation Tom Tromey
@ 2021-01-01 21:46 ` Tom Tromey
  2021-01-01 21:46 ` [PATCH 128/203] Introduce ada_ternop_range_operation Tom Tromey
                   ` (76 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:46 UTC (permalink / raw)
  To: gdb-patches

This adds class ada_qual_operation, which implements UNOP_QUAL.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* ada-lang.c (ada_qual_operation::evaluate): New method.
	* ada-exp.h (class ada_qual_operation): New.
---
 gdb/ChangeLog  |  5 +++++
 gdb/ada-exp.h  | 16 ++++++++++++++++
 gdb/ada-lang.c |  9 +++++++++
 3 files changed, 30 insertions(+)

diff --git a/gdb/ada-exp.h b/gdb/ada-exp.h
index 88ed0c53b46..9a8c8dffd5c 100644
--- a/gdb/ada-exp.h
+++ b/gdb/ada-exp.h
@@ -55,6 +55,22 @@ class ada_string_operation
 		   enum noside noside) override;
 };
 
+/* The Ada TYPE'(EXP) construct.  */
+class ada_qual_operation
+  : public tuple_holding_operation<operation_up, struct type *>
+{
+public:
+
+  using tuple_holding_operation::tuple_holding_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override;
+
+  enum exp_opcode opcode () const override
+  { return UNOP_QUAL; }
+};
+
 } /* namespace expr */
 
 #endif /* ADA_EXP_H */
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index d74c11f9a36..60ef5ae75ee 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -10583,6 +10583,15 @@ ada_string_operation::evaluate (struct type *expect_type,
   return result;
 }
 
+value *
+ada_qual_operation::evaluate (struct type *expect_type,
+			      struct expression *exp,
+			      enum noside noside)
+{
+  struct type *type = std::get<1> (m_storage);
+  return std::get<0> (m_storage)->evaluate (type, exp, noside);
+}
+
 }
 
 /* Implement the evaluate_exp routine in the exp_descriptor structure
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 128/203] Introduce ada_ternop_range_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (126 preceding siblings ...)
  2021-01-01 21:46 ` [PATCH 127/203] Introduce ada_qual_operation Tom Tromey
@ 2021-01-01 21:46 ` Tom Tromey
  2021-01-01 21:46 ` [PATCH 129/203] Implement several Fortran operations Tom Tromey
                   ` (75 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:46 UTC (permalink / raw)
  To: gdb-patches

This adds class ada_ternop_range_operation, which implements
TERNOP_IN_RANGE.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* ada-lang.c (ada_ternop_range_operation::evaluate): New method.
	* ada-exp.h (class ada_ternop_range_operation): New.
---
 gdb/ChangeLog  |  5 +++++
 gdb/ada-exp.h  | 16 ++++++++++++++++
 gdb/ada-lang.c | 11 +++++++++++
 3 files changed, 32 insertions(+)

diff --git a/gdb/ada-exp.h b/gdb/ada-exp.h
index 9a8c8dffd5c..17a04ea15c6 100644
--- a/gdb/ada-exp.h
+++ b/gdb/ada-exp.h
@@ -71,6 +71,22 @@ class ada_qual_operation
   { return UNOP_QUAL; }
 };
 
+/* Ternary in-range operator.  */
+class ada_ternop_range_operation
+  : public tuple_holding_operation<operation_up, operation_up, operation_up>
+{
+public:
+
+  using tuple_holding_operation::tuple_holding_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override;
+
+  enum exp_opcode opcode () const override
+  { return TERNOP_IN_RANGE; }
+};
+
 } /* namespace expr */
 
 #endif /* ADA_EXP_H */
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 60ef5ae75ee..90592d5f2b9 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -10592,6 +10592,17 @@ ada_qual_operation::evaluate (struct type *expect_type,
   return std::get<0> (m_storage)->evaluate (type, exp, noside);
 }
 
+value *
+ada_ternop_range_operation::evaluate (struct type *expect_type,
+				      struct expression *exp,
+				      enum noside noside)
+{
+  value *arg0 = std::get<0> (m_storage)->evaluate (nullptr, exp, noside);
+  value *arg1 = std::get<1> (m_storage)->evaluate (nullptr, exp, noside);
+  value *arg2 = std::get<2> (m_storage)->evaluate (nullptr, exp, noside);
+  return eval_ternop_in_range (expect_type, exp, noside, arg0, arg1, arg2);
+}
+
 }
 
 /* Implement the evaluate_exp routine in the exp_descriptor structure
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 129/203] Implement several Fortran operations
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (127 preceding siblings ...)
  2021-01-01 21:46 ` [PATCH 128/203] Introduce ada_ternop_range_operation Tom Tromey
@ 2021-01-01 21:46 ` Tom Tromey
  2021-01-01 21:46 ` [PATCH 130/203] Implement some Rust operations Tom Tromey
                   ` (74 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:46 UTC (permalink / raw)
  To: gdb-patches

This implements several straightforward Fortran operations, primarily
by reusing existing template classes.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* f-lang.c (eval_op_f_abs, eval_op_f_mod, eval_op_f_ceil)
	(eval_op_f_floor, eval_op_f_modulo, eval_op_f_cmplx)
	(eval_op_f_kind): No longer static.  Add "opcode" parameter.
	(evaluate_subexp_f): Update.
	* f-exp.h: New file.
---
 gdb/ChangeLog |   8 ++++
 gdb/f-exp.h   | 101 ++++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/f-lang.c  |  36 +++++++++++-------
 3 files changed, 131 insertions(+), 14 deletions(-)
 create mode 100644 gdb/f-exp.h

diff --git a/gdb/f-exp.h b/gdb/f-exp.h
new file mode 100644
index 00000000000..4b3fdd4a53e
--- /dev/null
+++ b/gdb/f-exp.h
@@ -0,0 +1,101 @@
+/* Definitions for Fortran expressions
+
+   Copyright (C) 2020 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 FORTRAN_EXP_H
+#define FORTRAN_EXP_H
+
+#include "expop.h"
+
+extern struct value *eval_op_f_abs (struct type *expect_type,
+				    struct expression *exp,
+				    enum noside noside,
+				    enum exp_opcode opcode,
+				    struct value *arg1);
+extern struct value *eval_op_f_mod (struct type *expect_type,
+				    struct expression *exp,
+				    enum noside noside,
+				    enum exp_opcode opcode,
+				    struct value *arg1, struct value *arg2);
+extern struct value *eval_op_f_ceil (struct type *expect_type,
+				     struct expression *exp,
+				     enum noside noside,
+				     enum exp_opcode opcode,
+				     struct value *arg1);
+extern struct value *eval_op_f_floor (struct type *expect_type,
+				      struct expression *exp,
+				      enum noside noside,
+				      enum exp_opcode opcode,
+				      struct value *arg1);
+extern struct value *eval_op_f_modulo (struct type *expect_type,
+				       struct expression *exp,
+				       enum noside noside,
+				       enum exp_opcode opcode,
+				       struct value *arg1, struct value *arg2);
+extern struct value *eval_op_f_cmplx (struct type *expect_type,
+				      struct expression *exp,
+				      enum noside noside,
+				      enum exp_opcode opcode,
+				      struct value *arg1, struct value *arg2);
+extern struct value *eval_op_f_kind (struct type *expect_type,
+				     struct expression *exp,
+				     enum noside noside,
+				     enum exp_opcode opcode,
+				     struct value *arg1);
+
+namespace expr
+{
+
+using fortran_abs_operation = unop_operation<UNOP_ABS, eval_op_f_abs>;
+using fortran_ceil_operation = unop_operation<UNOP_FORTRAN_CEILING,
+					      eval_op_f_ceil>;
+using fortran_floor_operation = unop_operation<UNOP_FORTRAN_FLOOR,
+					       eval_op_f_floor>;
+using fortran_kind_operation = unop_operation<UNOP_FORTRAN_KIND,
+					      eval_op_f_kind>;
+
+using fortran_mod_operation = binop_operation<BINOP_MOD, eval_op_f_mod>;
+using fortran_modulo_operation = binop_operation<BINOP_FORTRAN_MODULO,
+						 eval_op_f_modulo>;
+
+/* The Fortran "complex" operation.  */
+class fortran_cmplx_operation
+  : public tuple_holding_operation<operation_up, operation_up>
+{
+public:
+
+  using tuple_holding_operation::tuple_holding_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override
+  {
+    value *arg1 = std::get<0> (m_storage)->evaluate (nullptr, exp, noside);
+    value *arg2 = std::get<1> (m_storage)->evaluate (value_type (arg1),
+						     exp, noside);
+    return eval_op_f_cmplx (expect_type, exp, noside, BINOP_FORTRAN_CMPLX,
+			    arg1, arg2);
+  }
+
+  enum exp_opcode opcode () const override
+  { return BINOP_FORTRAN_CMPLX; }
+};
+
+} /* namespace expr */
+
+#endif /* FORTRAN_EXP_H */
diff --git a/gdb/f-lang.c b/gdb/f-lang.c
index d0932389726..c680e136976 100644
--- a/gdb/f-lang.c
+++ b/gdb/f-lang.c
@@ -38,6 +38,7 @@
 #include "gdbarch.h"
 #include "gdbcmd.h"
 #include "f-array-walker.h"
+#include "f-exp.h"
 
 #include <math.h>
 
@@ -704,9 +705,10 @@ fortran_value_subarray (struct value *array, struct expression *exp,
 
 /* A helper function for UNOP_ABS.  */
 
-static struct value *
+struct value *
 eval_op_f_abs (struct type *expect_type, struct expression *exp,
 	       enum noside noside,
+	       enum exp_opcode opcode,
 	       struct value *arg1)
 {
   if (noside == EVAL_SKIP)
@@ -733,9 +735,10 @@ eval_op_f_abs (struct type *expect_type, struct expression *exp,
 
 /* A helper function for BINOP_MOD.  */
 
-static struct value *
+struct value *
 eval_op_f_mod (struct type *expect_type, struct expression *exp,
 	       enum noside noside,
+	       enum exp_opcode opcode,
 	       struct value *arg1, struct value *arg2)
 {
   if (noside == EVAL_SKIP)
@@ -771,9 +774,10 @@ eval_op_f_mod (struct type *expect_type, struct expression *exp,
 
 /* A helper function for UNOP_FORTRAN_CEILING.  */
 
-static struct value *
+struct value *
 eval_op_f_ceil (struct type *expect_type, struct expression *exp,
 		enum noside noside,
+		enum exp_opcode opcode,
 		struct value *arg1)
 {
   if (noside == EVAL_SKIP)
@@ -790,9 +794,10 @@ eval_op_f_ceil (struct type *expect_type, struct expression *exp,
 
 /* A helper function for UNOP_FORTRAN_FLOOR.  */
 
-static struct value *
+struct value *
 eval_op_f_floor (struct type *expect_type, struct expression *exp,
 		 enum noside noside,
+		 enum exp_opcode opcode,
 		 struct value *arg1)
 {
   if (noside == EVAL_SKIP)
@@ -809,9 +814,10 @@ eval_op_f_floor (struct type *expect_type, struct expression *exp,
 
 /* A helper function for BINOP_FORTRAN_MODULO.  */
 
-static struct value *
+struct value *
 eval_op_f_modulo (struct type *expect_type, struct expression *exp,
 		  enum noside noside,
+		  enum exp_opcode opcode,
 		  struct value *arg1, struct value *arg2)
 {
   if (noside == EVAL_SKIP)
@@ -850,9 +856,10 @@ eval_op_f_modulo (struct type *expect_type, struct expression *exp,
 
 /* A helper function for BINOP_FORTRAN_CMPLX.  */
 
-static struct value *
+struct value *
 eval_op_f_cmplx (struct type *expect_type, struct expression *exp,
 		 enum noside noside,
+		 enum exp_opcode opcode,
 		 struct value *arg1, struct value *arg2)
 {
   if (noside == EVAL_SKIP)
@@ -863,9 +870,10 @@ eval_op_f_cmplx (struct type *expect_type, struct expression *exp,
 
 /* A helper function for UNOP_FORTRAN_KIND.  */
 
-static struct value *
+struct value *
 eval_op_f_kind (struct type *expect_type, struct expression *exp,
 		enum noside noside,
+		enum exp_opcode opcode,
 		struct value *arg1)
 {
   struct type *type = value_type (arg1);
@@ -909,34 +917,34 @@ evaluate_subexp_f (struct type *expect_type, struct expression *exp,
 
     case UNOP_ABS:
       arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      return eval_op_f_abs (expect_type, exp, noside, arg1);
+      return eval_op_f_abs (expect_type, exp, noside, op, arg1);
 
     case BINOP_MOD:
       arg1 = evaluate_subexp (nullptr, exp, pos, noside);
       arg2 = evaluate_subexp (value_type (arg1), exp, pos, noside);
-      return eval_op_f_mod (expect_type, exp, noside, arg1, arg2);
+      return eval_op_f_mod (expect_type, exp, noside, op, arg1, arg2);
 
     case UNOP_FORTRAN_CEILING:
       arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      return eval_op_f_ceil (expect_type, exp, noside, arg1);
+      return eval_op_f_ceil (expect_type, exp, noside, op, arg1);
 
     case UNOP_FORTRAN_FLOOR:
       arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      return eval_op_f_floor (expect_type, exp, noside, arg1);
+      return eval_op_f_floor (expect_type, exp, noside, op, arg1);
 
     case BINOP_FORTRAN_MODULO:
       arg1 = evaluate_subexp (nullptr, exp, pos, noside);
       arg2 = evaluate_subexp (value_type (arg1), exp, pos, noside);
-      return eval_op_f_modulo (expect_type, exp, noside, arg1, arg2);
+      return eval_op_f_modulo (expect_type, exp, noside, op, arg1, arg2);
 
     case BINOP_FORTRAN_CMPLX:
       arg1 = evaluate_subexp (nullptr, exp, pos, noside);
       arg2 = evaluate_subexp (value_type (arg1), exp, pos, noside);
-      return eval_op_f_cmplx (expect_type, exp, noside, arg1, arg2);
+      return eval_op_f_cmplx (expect_type, exp, noside, op, arg1, arg2);
 
     case UNOP_FORTRAN_KIND:
       arg1 = evaluate_subexp (NULL, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
-      return eval_op_f_kind (expect_type, exp, noside, arg1);
+      return eval_op_f_kind (expect_type, exp, noside, op, arg1);
 
     case OP_F77_UNDETERMINED_ARGLIST:
       /* Remember that in F77, functions, substring ops and array subscript
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 130/203] Implement some Rust operations
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (128 preceding siblings ...)
  2021-01-01 21:46 ` [PATCH 129/203] Implement several Fortran operations Tom Tromey
@ 2021-01-01 21:46 ` Tom Tromey
  2021-01-01 21:46 ` [PATCH 131/203] Introduce rust_unop_ind_operation Tom Tromey
                   ` (73 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:46 UTC (permalink / raw)
  To: gdb-patches

This implements some straightforward Rust operations, using existing
template classes.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* rust-lang.c (eval_op_rust_complement, eval_op_rust_array): No
	longer static.  Add "opcode" parameter.
	(rust_evaluate_subexp): Update.
	* rust-exp.h: New file.
---
 gdb/ChangeLog   |  7 +++++++
 gdb/rust-exp.h  | 47 +++++++++++++++++++++++++++++++++++++++++++++++
 gdb/rust-lang.c | 14 +++++++++-----
 3 files changed, 63 insertions(+), 5 deletions(-)
 create mode 100644 gdb/rust-exp.h

diff --git a/gdb/rust-exp.h b/gdb/rust-exp.h
new file mode 100644
index 00000000000..cce1fd9a7d9
--- /dev/null
+++ b/gdb/rust-exp.h
@@ -0,0 +1,47 @@
+/* Definitions for Rust expressions
+
+   Copyright (C) 2020 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 RUST_EXP_H
+#define RUST_EXP_H
+
+#include "expop.h"
+
+extern struct value *eval_op_rust_complement (struct type *expect_type,
+					      struct expression *exp,
+					      enum noside noside,
+					      enum exp_opcode opcode,
+					      struct value *value);
+extern struct value *eval_op_rust_array (struct type *expect_type,
+					 struct expression *exp,
+					 enum noside noside,
+					 enum exp_opcode opcode,
+					 struct value *ncopies,
+					 struct value *elt);
+
+namespace expr
+{
+
+using rust_unop_compl_operation = unop_operation<UNOP_COMPLEMENT,
+						  eval_op_rust_complement>;
+using rust_array_operation = binop_operation<OP_RUST_ARRAY,
+					     eval_op_rust_array>;
+
+} /* namespace expr */
+
+#endif /* RUST_EXP_H */
diff --git a/gdb/rust-lang.c b/gdb/rust-lang.c
index a7c62610a1d..1305ee092fa 100644
--- a/gdb/rust-lang.c
+++ b/gdb/rust-lang.c
@@ -39,6 +39,7 @@
 #include <vector>
 #include "cli/cli-style.h"
 #include "parser-defs.h"
+#include "rust-exp.h"
 
 /* See rust-lang.h.  */
 
@@ -1339,9 +1340,10 @@ eval_op_rust_ind (struct type *expect_type, struct expression *exp,
 
 /* A helper function for UNOP_COMPLEMENT.  */
 
-static struct value *
+struct value *
 eval_op_rust_complement (struct type *expect_type, struct expression *exp,
 			 enum noside noside,
+			 enum exp_opcode opcode,
 			 struct value *value)
 {
   if (noside == EVAL_SKIP)
@@ -1356,9 +1358,10 @@ eval_op_rust_complement (struct type *expect_type, struct expression *exp,
 
 /* A helper function for OP_ARRAY.  */
 
-static struct value *
+struct value *
 eval_op_rust_array (struct type *expect_type, struct expression *exp,
 		    enum noside noside,
+		    enum exp_opcode opcode,
 		    struct value *elt, struct value *ncopies)
 {
   int copies = value_as_long (ncopies);
@@ -1505,8 +1508,9 @@ rust_evaluate_subexp (struct type *expect_type, struct expression *exp,
 		      int *pos, enum noside noside)
 {
   struct value *result;
+  enum exp_opcode op = exp->elts[*pos].opcode;
 
-  switch (exp->elts[*pos].opcode)
+  switch (op)
     {
     case UNOP_IND:
       {
@@ -1528,7 +1532,7 @@ rust_evaluate_subexp (struct type *expect_type, struct expression *exp,
 
 	++*pos;
 	value = evaluate_subexp (nullptr, exp, pos, noside);
-	result = eval_op_rust_complement (expect_type, exp, noside, value);
+	result = eval_op_rust_complement (expect_type, exp, noside, op, value);
       }
       break;
 
@@ -1621,7 +1625,7 @@ rust_evaluate_subexp (struct type *expect_type, struct expression *exp,
 
 	elt = rust_evaluate_subexp (NULL, exp, pos, noside);
 	ncopies = rust_evaluate_subexp (NULL, exp, pos, noside);
-	return eval_op_rust_array (expect_type, exp, noside, elt, ncopies);
+	return eval_op_rust_array (expect_type, exp, noside, op, elt, ncopies);
       }
       break;
 
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 131/203] Introduce rust_unop_ind_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (129 preceding siblings ...)
  2021-01-01 21:46 ` [PATCH 130/203] Implement some Rust operations Tom Tromey
@ 2021-01-01 21:46 ` Tom Tromey
  2021-01-01 21:46 ` [PATCH 132/203] Introduce rust_subscript_operation Tom Tromey
                   ` (72 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:46 UTC (permalink / raw)
  To: gdb-patches

This adds class rust_unop_ind_operation, which implements UNOP_IND for
Rust.  Rust requires a special case here to handle trait objects.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* rust-lang.c (eval_op_rust_ind): No longer static.  Add "opcode"
	parameter.
	(rust_evaluate_subexp): Update.
	* rust-exp.h (class rust_unop_ind_operation): New.
---
 gdb/ChangeLog   |  7 +++++++
 gdb/rust-exp.h  | 25 +++++++++++++++++++++++++
 gdb/rust-lang.c |  5 +++--
 3 files changed, 35 insertions(+), 2 deletions(-)

diff --git a/gdb/rust-exp.h b/gdb/rust-exp.h
index cce1fd9a7d9..d16f921ca00 100644
--- a/gdb/rust-exp.h
+++ b/gdb/rust-exp.h
@@ -33,6 +33,11 @@ extern struct value *eval_op_rust_array (struct type *expect_type,
 					 enum exp_opcode opcode,
 					 struct value *ncopies,
 					 struct value *elt);
+extern struct value *eval_op_rust_ind (struct type *expect_type,
+				       struct expression *exp,
+				       enum noside noside,
+				       enum exp_opcode opcode,
+				       struct value *value);
 
 namespace expr
 {
@@ -42,6 +47,26 @@ using rust_unop_compl_operation = unop_operation<UNOP_COMPLEMENT,
 using rust_array_operation = binop_operation<OP_RUST_ARRAY,
 					     eval_op_rust_array>;
 
+/* The Rust indirection operation.  */
+class rust_unop_ind_operation
+  : public unop_ind_operation
+{
+public:
+
+  using unop_ind_operation::unop_ind_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override
+  {
+    if (noside != EVAL_NORMAL)
+      return unop_ind_operation::evaluate (expect_type, exp, noside);
+
+    value *arg1 = std::get<0> (m_storage)->evaluate (nullptr, exp, noside);
+    return eval_op_rust_ind (expect_type, exp, noside, UNOP_IND, arg1);
+  }
+};
+
 } /* namespace expr */
 
 #endif /* RUST_EXP_H */
diff --git a/gdb/rust-lang.c b/gdb/rust-lang.c
index 1305ee092fa..2c3f72ed404 100644
--- a/gdb/rust-lang.c
+++ b/gdb/rust-lang.c
@@ -1325,9 +1325,10 @@ rust_subscript (struct type *expect_type, struct expression *exp,
 
 /* A helper function for UNOP_IND.  */
 
-static struct value *
+struct value *
 eval_op_rust_ind (struct type *expect_type, struct expression *exp,
 		  enum noside noside,
+		  enum exp_opcode opcode,
 		  struct value *value)
 {
   gdb_assert (noside == EVAL_NORMAL);
@@ -1521,7 +1522,7 @@ rust_evaluate_subexp (struct type *expect_type, struct expression *exp,
 	    ++*pos;
 	    struct value *value = evaluate_subexp (expect_type, exp, pos,
 						   noside);
-	    result = eval_op_rust_ind (expect_type, exp, noside, value);
+	    result = eval_op_rust_ind (expect_type, exp, noside, op, value);
 	  }
       }
       break;
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 132/203] Introduce rust_subscript_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (130 preceding siblings ...)
  2021-01-01 21:46 ` [PATCH 131/203] Introduce rust_unop_ind_operation Tom Tromey
@ 2021-01-01 21:46 ` Tom Tromey
  2021-01-01 21:46 ` [PATCH 133/203] Introduce rust_range_operation Tom Tromey
                   ` (71 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:46 UTC (permalink / raw)
  To: gdb-patches

This adds class rust_subscript_operation, which implements
BINOP_SUBSCRIPT for Rust.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* rust-lang.c (rust_subscript): No longer static.
	* rust-exp.h (class rust_subscript_operation): New.
---
 gdb/ChangeLog   |  5 +++++
 gdb/rust-exp.h  | 57 +++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/rust-lang.c |  2 +-
 3 files changed, 63 insertions(+), 1 deletion(-)

diff --git a/gdb/rust-exp.h b/gdb/rust-exp.h
index d16f921ca00..7571009ea39 100644
--- a/gdb/rust-exp.h
+++ b/gdb/rust-exp.h
@@ -38,6 +38,10 @@ extern struct value *eval_op_rust_ind (struct type *expect_type,
 				       enum noside noside,
 				       enum exp_opcode opcode,
 				       struct value *value);
+extern struct value *rust_subscript (struct type *expect_type,
+				     struct expression *exp,
+				     enum noside noside, bool for_addr,
+				     struct value *lhs, struct value *rhs);
 
 namespace expr
 {
@@ -67,6 +71,59 @@ class rust_unop_ind_operation
   }
 };
 
+/* Subscript operator for Rust.  */
+class rust_subscript_operation
+  : public tuple_holding_operation<operation_up, operation_up>
+{
+public:
+
+  using tuple_holding_operation::tuple_holding_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override
+  {
+    value *arg1 = std::get<0> (m_storage)->evaluate (nullptr, exp, noside);
+    value *arg2 = std::get<1> (m_storage)->evaluate (nullptr, exp, noside);
+    return rust_subscript (expect_type, exp, noside, false, arg1, arg2);
+  }
+
+  value *slice (struct type *expect_type,
+		struct expression *exp,
+		enum noside noside)
+  {
+    value *arg1 = std::get<0> (m_storage)->evaluate (nullptr, exp, noside);
+    value *arg2 = std::get<1> (m_storage)->evaluate (nullptr, exp, noside);
+    return rust_subscript (expect_type, exp, noside, true, arg1, arg2);
+  }
+
+  enum exp_opcode opcode () const override
+  { return BINOP_SUBSCRIPT; }
+};
+
+class rust_unop_addr_operation
+  : public tuple_holding_operation<operation_up>
+{
+public:
+
+  using tuple_holding_operation::tuple_holding_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override
+  {
+    operation *oper = std::get<0> (m_storage).get ();
+    rust_subscript_operation *sub_op
+      = dynamic_cast<rust_subscript_operation *> (oper);
+    if (sub_op != nullptr)
+      return sub_op->slice (expect_type, exp, noside);
+    return oper->evaluate_for_address (exp, noside);
+  }
+
+  enum exp_opcode opcode () const override
+  { return UNOP_ADDR; }
+};
+
 } /* namespace expr */
 
 #endif /* RUST_EXP_H */
diff --git a/gdb/rust-lang.c b/gdb/rust-lang.c
index 2c3f72ed404..0035a58adc4 100644
--- a/gdb/rust-lang.c
+++ b/gdb/rust-lang.c
@@ -1168,7 +1168,7 @@ rust_compute_range (struct type *type, struct value *range,
 
 /* A helper for rust_evaluate_subexp that handles BINOP_SUBSCRIPT.  */
 
-static struct value *
+struct value *
 rust_subscript (struct type *expect_type, struct expression *exp,
 		enum noside noside, bool for_addr,
 		struct value *lhs, struct value *rhs)
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 133/203] Introduce rust_range_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (131 preceding siblings ...)
  2021-01-01 21:46 ` [PATCH 132/203] Introduce rust_subscript_operation Tom Tromey
@ 2021-01-01 21:46 ` Tom Tromey
  2021-01-01 21:46 ` [PATCH 134/203] Implement Rust field operations Tom Tromey
                   ` (70 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:46 UTC (permalink / raw)
  To: gdb-patches

This adds class rust_range_operation, which implements OP_RANGE.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* rust-lang.c (rust_range): No longer static.
	* rust-exp.h (class rust_range_operation): New.
---
 gdb/ChangeLog   |  5 +++++
 gdb/rust-exp.h  | 30 ++++++++++++++++++++++++++++++
 gdb/rust-lang.c |  2 +-
 3 files changed, 36 insertions(+), 1 deletion(-)

diff --git a/gdb/rust-exp.h b/gdb/rust-exp.h
index 7571009ea39..263d41a79d4 100644
--- a/gdb/rust-exp.h
+++ b/gdb/rust-exp.h
@@ -42,6 +42,10 @@ extern struct value *rust_subscript (struct type *expect_type,
 				     struct expression *exp,
 				     enum noside noside, bool for_addr,
 				     struct value *lhs, struct value *rhs);
+extern struct value *rust_range (struct type *expect_type,
+				 struct expression *exp,
+				 enum noside noside, enum range_flag kind,
+				 struct value *low, struct value *high);
 
 namespace expr
 {
@@ -124,6 +128,32 @@ class rust_unop_addr_operation
   { return UNOP_ADDR; }
 };
 
+/* The Rust range operators.  */
+class rust_range_operation
+  : public tuple_holding_operation<enum range_flag, operation_up, operation_up>
+{
+public:
+
+  using tuple_holding_operation::tuple_holding_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override
+  {
+    auto kind = std::get<0> (m_storage);
+    value *low = nullptr;
+    if (std::get<1> (m_storage) != nullptr)
+      low = std::get<1> (m_storage)->evaluate (nullptr, exp, noside);
+    value *high = nullptr;
+    if (std::get<2> (m_storage) != nullptr)
+      high = std::get<2> (m_storage)->evaluate (nullptr, exp, noside);
+    return rust_range (expect_type, exp, noside, kind, low, high);
+  }
+
+  enum exp_opcode opcode () const override
+  { return OP_RANGE; }
+};
+
 } /* namespace expr */
 
 #endif /* RUST_EXP_H */
diff --git a/gdb/rust-lang.c b/gdb/rust-lang.c
index 0035a58adc4..68fbaf1642a 100644
--- a/gdb/rust-lang.c
+++ b/gdb/rust-lang.c
@@ -1041,7 +1041,7 @@ rust_evaluate_funcall (struct expression *exp, int *pos, enum noside noside)
 
 /* A helper for rust_evaluate_subexp that handles OP_RANGE.  */
 
-static struct value *
+struct value *
 rust_range (struct type *expect_type, struct expression *exp,
 	    enum noside noside, enum range_flag kind,
 	    struct value *low, struct value *high)
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 134/203] Implement Rust field operations
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (132 preceding siblings ...)
  2021-01-01 21:46 ` [PATCH 133/203] Introduce rust_range_operation Tom Tromey
@ 2021-01-01 21:46 ` Tom Tromey
  2021-01-01 21:46 ` [PATCH 135/203] Introduce rust_aggregate_operation Tom Tromey
                   ` (69 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:46 UTC (permalink / raw)
  To: gdb-patches

This implements the field operations STRUCTOP_STRUCT and
STRUCTOP_ANONYMOUS, for Rust.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* rust-lang.c (eval_op_rust_struct_anon, eval_op_rust_structop):
	No longer static.
	* rust-exp.h (class rust_struct_anon): New.
	(class rust_structop): New.
---
 gdb/ChangeLog   |  7 +++++++
 gdb/rust-exp.h  | 53 +++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/rust-lang.c |  4 ++--
 3 files changed, 62 insertions(+), 2 deletions(-)

diff --git a/gdb/rust-exp.h b/gdb/rust-exp.h
index 263d41a79d4..19e945c806b 100644
--- a/gdb/rust-exp.h
+++ b/gdb/rust-exp.h
@@ -46,6 +46,16 @@ extern struct value *rust_range (struct type *expect_type,
 				 struct expression *exp,
 				 enum noside noside, enum range_flag kind,
 				 struct value *low, struct value *high);
+extern struct value *eval_op_rust_struct_anon (struct type *expect_type,
+					       struct expression *exp,
+					       enum noside noside,
+					       int field_number,
+					       struct value *lhs);
+extern struct value *eval_op_rust_structop (struct type *expect_type,
+					    struct expression *exp,
+					    enum noside noside,
+					    struct value *lhs,
+					    const char *field_name);
 
 namespace expr
 {
@@ -154,6 +164,49 @@ class rust_range_operation
   { return OP_RANGE; }
 };
 
+/* Tuple field reference (using an integer).  */
+class rust_struct_anon
+  : public tuple_holding_operation<int, operation_up>
+{
+public:
+
+  using tuple_holding_operation::tuple_holding_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override
+  {
+    value *lhs = std::get<1> (m_storage)->evaluate (nullptr, exp, noside);
+    return eval_op_rust_struct_anon (expect_type, exp, noside,
+				     std::get<0> (m_storage), lhs);
+
+  }
+
+  enum exp_opcode opcode () const override
+  { return STRUCTOP_ANONYMOUS; }
+};
+
+/* Structure (or union or enum) field reference.  */
+class rust_structop
+  : public structop_base_operation
+{
+public:
+
+  using structop_base_operation::structop_base_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override
+  {
+    value *lhs = std::get<0> (m_storage)->evaluate (nullptr, exp, noside);
+    return eval_op_rust_structop (expect_type, exp, noside, lhs,
+				  std::get<1> (m_storage).c_str ());
+  }
+
+  enum exp_opcode opcode () const override
+  { return STRUCTOP_STRUCT; }
+};
+
 } /* namespace expr */
 
 #endif /* RUST_EXP_H */
diff --git a/gdb/rust-lang.c b/gdb/rust-lang.c
index 68fbaf1642a..95b19776edf 100644
--- a/gdb/rust-lang.c
+++ b/gdb/rust-lang.c
@@ -1388,7 +1388,7 @@ eval_op_rust_array (struct type *expect_type, struct expression *exp,
 
 /* A helper function for STRUCTOP_ANONYMOUS.  */
 
-static struct value *
+struct value *
 eval_op_rust_struct_anon (struct type *expect_type, struct expression *exp,
 			  enum noside noside,
 			  int field_number, struct value *lhs)
@@ -1455,7 +1455,7 @@ tuple structs, and tuple-like enum variants"));
 
 /* A helper function for STRUCTOP_STRUCT.  */
 
-static struct value *
+struct value *
 eval_op_rust_structop (struct type *expect_type, struct expression *exp,
 		       enum noside noside,
 		       struct value *lhs, const char *field_name)
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 135/203] Introduce rust_aggregate_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (133 preceding siblings ...)
  2021-01-01 21:46 ` [PATCH 134/203] Implement Rust field operations Tom Tromey
@ 2021-01-01 21:46 ` Tom Tromey
  2021-01-01 21:46 ` [PATCH 136/203] Add two simple Modula-2 operations Tom Tromey
                   ` (68 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:46 UTC (permalink / raw)
  To: gdb-patches

This adds class rust_aggregate_operation, which implements
OP_AGGREGATE for Rust.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* rust-lang.c (rust_aggregate_operation::evaluate): New method.
	* rust-exp.h (class rust_aggregate_operation): New.
---
 gdb/ChangeLog   |  5 +++++
 gdb/rust-exp.h  | 18 +++++++++++++++
 gdb/rust-lang.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 81 insertions(+)

diff --git a/gdb/rust-exp.h b/gdb/rust-exp.h
index 19e945c806b..6e529f8e600 100644
--- a/gdb/rust-exp.h
+++ b/gdb/rust-exp.h
@@ -207,6 +207,24 @@ class rust_structop
   { return STRUCTOP_STRUCT; }
 };
 
+/* Rust aggregate initialization.  */
+class rust_aggregate_operation
+  : public tuple_holding_operation<struct type *, operation_up,
+				   std::vector<std::pair<std::string,
+							 operation_up>>>
+{
+public:
+
+  using tuple_holding_operation::tuple_holding_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override;
+
+  enum exp_opcode opcode () const override
+  { return OP_AGGREGATE; }
+};
+
 } /* namespace expr */
 
 #endif /* RUST_EXP_H */
diff --git a/gdb/rust-lang.c b/gdb/rust-lang.c
index 95b19776edf..992319ffd2b 100644
--- a/gdb/rust-lang.c
+++ b/gdb/rust-lang.c
@@ -1700,6 +1700,64 @@ rust_evaluate_subexp (struct type *expect_type, struct expression *exp,
   return result;
 }
 
+namespace expr
+{
+
+value *
+rust_aggregate_operation::evaluate (struct type *expect_type,
+				    struct expression *exp,
+				    enum noside noside)
+{
+  struct type *type = std::get<0> (m_storage);
+  CORE_ADDR addr = 0;
+  struct value *addrval = NULL;
+  value *result;
+
+  if (noside == EVAL_NORMAL)
+    {
+      addrval = value_allocate_space_in_inferior (TYPE_LENGTH (type));
+      addr = value_as_long (addrval);
+      result = value_at_lazy (type, addr);
+    }
+
+  if (std::get<1> (m_storage) != nullptr)
+    {
+      struct value *init = std::get<1> (m_storage)->evaluate (nullptr, exp,
+							      noside);
+
+      if (noside == EVAL_NORMAL)
+	{
+	  /* This isn't quite right but will do for the time
+	     being, seeing that we can't implement the Copy
+	     trait anyway.  */
+	  value_assign (result, init);
+	}
+    }
+
+  for (const auto &item : std::get<2> (m_storage))
+    {
+      value *val = item.second->evaluate (nullptr, exp, noside);
+      if (noside == EVAL_NORMAL)
+	{
+	  const char *fieldname = item.first.c_str ();
+	  value *field = value_struct_elt (&result, nullptr, fieldname,
+					   nullptr, "structure");
+	  value_assign (field, val);
+	}
+    }
+
+  if (noside == EVAL_SKIP)
+    result = value_from_longest (builtin_type (exp->gdbarch)->builtin_int, 1);
+  else if (noside == EVAL_AVOID_SIDE_EFFECTS)
+    result = allocate_value (type);
+  else
+    result = value_at_lazy (type, addr);
+
+  return result;
+}
+
+}
+
 /* operator_length implementation for Rust.  */
 
 static void
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 136/203] Add two simple Modula-2 operations
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (134 preceding siblings ...)
  2021-01-01 21:46 ` [PATCH 135/203] Introduce rust_aggregate_operation Tom Tromey
@ 2021-01-01 21:46 ` Tom Tromey
  2021-01-07 15:16   ` Gaius Mulley
  2021-01-01 21:46 ` [PATCH 137/203] Implement the "&&" and "||" operators Tom Tromey
                   ` (67 subsequent siblings)
  203 siblings, 1 reply; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:46 UTC (permalink / raw)
  To: gdb-patches

This adds a couple of simple Modula-2 operations.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* m2-lang.c (eval_op_m2_high, eval_op_m2_subscript): No longer
	static.
	* m2-exp.h: New file.
---
 gdb/ChangeLog |  6 ++++
 gdb/m2-exp.h  | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/m2-lang.c |  5 +--
 3 files changed, 93 insertions(+), 2 deletions(-)
 create mode 100644 gdb/m2-exp.h

diff --git a/gdb/m2-exp.h b/gdb/m2-exp.h
new file mode 100644
index 00000000000..e034963a9a6
--- /dev/null
+++ b/gdb/m2-exp.h
@@ -0,0 +1,84 @@
+/* Definitions for Modula-2 expressions
+
+   Copyright (C) 2020 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 M2_EXP_H
+#define M2_EXP_H
+
+#include "expop.h"
+
+extern struct value *eval_op_m2_high (struct type *expect_type,
+				      struct expression *exp,
+				      enum noside noside,
+				      struct value *arg1);
+extern struct value *eval_op_m2_subscript (struct type *expect_type,
+					   struct expression *exp,
+					   enum noside noside,
+					   struct value *arg1,
+					   struct value *arg2);
+
+namespace expr
+{
+
+/* The Modula-2 "HIGH" operation.  */
+class m2_unop_high_operation
+  : public tuple_holding_operation<operation_up>
+{
+public:
+
+  using tuple_holding_operation::tuple_holding_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override
+  {
+    value *arg1 = std::get<0> (m_storage)->evaluate_with_coercion (exp,
+								   noside);
+    return eval_op_m2_high (expect_type, exp, noside, arg1);
+  }
+
+  enum exp_opcode opcode () const override
+  { return UNOP_HIGH; }
+};
+
+/* Subscripting for Modula-2.  */
+class m2_binop_subscript_operation
+  : public tuple_holding_operation<operation_up, operation_up>
+{
+public:
+
+  using tuple_holding_operation::tuple_holding_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override
+  {
+    value *arg1 = std::get<0> (m_storage)->evaluate_with_coercion (exp,
+								   noside);
+    value *arg2 = std::get<1> (m_storage)->evaluate_with_coercion (exp,
+								   noside);
+    return eval_op_m2_subscript (expect_type, exp, noside, arg1, arg2);
+  }
+
+  enum exp_opcode opcode () const override
+  { return BINOP_SUBSCRIPT; }
+};
+
+} /* namespace expr */
+
+#endif /* M2_EXP_H */
diff --git a/gdb/m2-lang.c b/gdb/m2-lang.c
index f5e80eee9c6..60d373ec2b9 100644
--- a/gdb/m2-lang.c
+++ b/gdb/m2-lang.c
@@ -28,10 +28,11 @@
 #include "c-lang.h"
 #include "valprint.h"
 #include "gdbarch.h"
+#include "m2-exp.h"
 
 /* A helper function for UNOP_HIGH.  */
 
-static struct value *
+struct value *
 eval_op_m2_high (struct type *expect_type, struct expression *exp,
 		 enum noside noside,
 		 struct value *arg1)
@@ -62,7 +63,7 @@ eval_op_m2_high (struct type *expect_type, struct expression *exp,
 
 /* A helper function for BINOP_SUBSCRIPT.  */
 
-static struct value *
+struct value *
 eval_op_m2_subscript (struct type *expect_type, struct expression *exp,
 		      enum noside noside,
 		      struct value *arg1, struct value *arg2)
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 137/203] Implement the "&&" and "||" operators
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (135 preceding siblings ...)
  2021-01-01 21:46 ` [PATCH 136/203] Add two simple Modula-2 operations Tom Tromey
@ 2021-01-01 21:46 ` Tom Tromey
  2021-01-01 21:46 ` [PATCH 138/203] Implement some Ada unary operations Tom Tromey
                   ` (66 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:46 UTC (permalink / raw)
  To: gdb-patches

This implements the "&&" and "||" operators.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* expop.h (class logical_and_operation)
	(class logical_or_operation): New.
	* eval.c (logical_and_operation::evaluate)
	(logical_or_operation::evaluate): New methods.
	* ax-gdb.c (logical_and_operation::do_generate_ax)
	(logical_or_operation::do_generate_ax): New methods.
---
 gdb/ChangeLog |  9 ++++++++
 gdb/ax-gdb.c  | 56 +++++++++++++++++++++++++++++++++++++++++++++
 gdb/eval.c    | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/expop.h   | 48 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 176 insertions(+)

diff --git a/gdb/ax-gdb.c b/gdb/ax-gdb.c
index bdf4a6dc39a..8ec3dd7cc3d 100644
--- a/gdb/ax-gdb.c
+++ b/gdb/ax-gdb.c
@@ -2693,6 +2693,62 @@ var_value_operation::do_generate_ax (struct expression *exp,
     }
 }
 
+void
+logical_and_operation::do_generate_ax (struct expression *exp,
+				       struct agent_expr *ax,
+				       struct axs_value *value,
+				       struct type *cast_type)
+{
+  struct axs_value value1, value2;
+  int if1, go1, if2, go2, end;
+
+  /* Generate the obvious sequence of tests and jumps.  */
+  std::get<0> (m_storage)->generate_ax (exp, ax, &value1);
+  gen_usual_unary (ax, &value1);
+  if1 = ax_goto (ax, aop_if_goto);
+  go1 = ax_goto (ax, aop_goto);
+  ax_label (ax, if1, ax->len);
+  std::get<1> (m_storage)->generate_ax (exp, ax, &value2);
+  gen_usual_unary (ax, &value2);
+  if2 = ax_goto (ax, aop_if_goto);
+  go2 = ax_goto (ax, aop_goto);
+  ax_label (ax, if2, ax->len);
+  ax_const_l (ax, 1);
+  end = ax_goto (ax, aop_goto);
+  ax_label (ax, go1, ax->len);
+  ax_label (ax, go2, ax->len);
+  ax_const_l (ax, 0);
+  ax_label (ax, end, ax->len);
+  value->kind = axs_rvalue;
+  value->type = builtin_type (ax->gdbarch)->builtin_int;
+}
+
+void
+logical_or_operation::do_generate_ax (struct expression *exp,
+				      struct agent_expr *ax,
+				      struct axs_value *value,
+				      struct type *cast_type)
+{
+  struct axs_value value1, value2;
+  int if1, if2, end;
+
+  /* Generate the obvious sequence of tests and jumps.  */
+  std::get<0> (m_storage)->generate_ax (exp, ax, &value1);
+  gen_usual_unary (ax, &value1);
+  if1 = ax_goto (ax, aop_if_goto);
+  std::get<1> (m_storage)->generate_ax (exp, ax, &value2);
+  gen_usual_unary (ax, &value2);
+  if2 = ax_goto (ax, aop_if_goto);
+  ax_const_l (ax, 0);
+  end = ax_goto (ax, aop_goto);
+  ax_label (ax, if1, ax->len);
+  ax_label (ax, if2, ax->len);
+  ax_const_l (ax, 1);
+  ax_label (ax, end, ax->len);
+  value->kind = axs_rvalue;
+  value->type = builtin_type (ax->gdbarch)->builtin_int;
+}
+
 }
 
 /* This handles the middle-to-right-side of code generation for binary
diff --git a/gdb/eval.c b/gdb/eval.c
index b1087d1329d..495cd4b26a3 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -2461,6 +2461,69 @@ multi_subscript_operation::evaluate (struct type *expect_type,
 			       gdb::make_array_view (argvec, values.size ()));
 }
 
+value *
+logical_and_operation::evaluate (struct type *expect_type,
+				 struct expression *exp,
+				 enum noside noside)
+{
+  value *arg1 = std::get<0> (m_storage)->evaluate (nullptr, exp, noside);
+  if (noside == EVAL_SKIP)
+    return eval_skip_value (exp);
+
+  value *arg2 = std::get<1> (m_storage)->evaluate (nullptr, exp,
+						   EVAL_AVOID_SIDE_EFFECTS);
+
+  if (binop_user_defined_p (BINOP_LOGICAL_AND, arg1, arg2))
+    {
+      arg2 = std::get<1> (m_storage)->evaluate (nullptr, exp, noside);
+      return value_x_binop (arg1, arg2, BINOP_LOGICAL_AND, OP_NULL, noside);
+    }
+  else
+    {
+      int tem = value_logical_not (arg1);
+      if (!tem)
+	{
+	  arg2 = std::get<1> (m_storage)->evaluate (nullptr, exp, noside);
+	  tem = value_logical_not (arg2);
+	}
+      struct type *type = language_bool_type (exp->language_defn,
+					      exp->gdbarch);
+      return value_from_longest (type, !tem);
+    }
+}
+
+value *
+logical_or_operation::evaluate (struct type *expect_type,
+				struct expression *exp,
+				enum noside noside)
+{
+  value *arg1 = std::get<0> (m_storage)->evaluate (nullptr, exp, noside);
+  if (noside == EVAL_SKIP)
+    return eval_skip_value (exp);
+
+  value *arg2 = std::get<1> (m_storage)->evaluate (nullptr, exp,
+						   EVAL_AVOID_SIDE_EFFECTS);
+
+  if (binop_user_defined_p (BINOP_LOGICAL_OR, arg1, arg2))
+    {
+      arg2 = std::get<1> (m_storage)->evaluate (nullptr, exp, noside);
+      return value_x_binop (arg1, arg2, BINOP_LOGICAL_OR, OP_NULL, noside);
+    }
+  else
+    {
+      int tem = value_logical_not (arg1);
+      if (tem)
+	{
+	  arg2 = std::get<1> (m_storage)->evaluate (nullptr, exp, noside);
+	  tem = value_logical_not (arg2);
+	}
+
+      struct type *type = language_bool_type (exp->language_defn,
+					      exp->gdbarch);
+      return value_from_longest (type, !tem);
+    }
+}
+
 }
 
 struct value *
diff --git a/gdb/expop.h b/gdb/expop.h
index 21c7b9e25da..f858f591baf 100644
--- a/gdb/expop.h
+++ b/gdb/expop.h
@@ -1979,6 +1979,54 @@ class multi_subscript_operation
   { return MULTI_SUBSCRIPT; }
 };
 
+/* The "&&" operator.  */
+class logical_and_operation
+  : public maybe_constant_operation<operation_up, operation_up>
+{
+public:
+
+  using maybe_constant_operation::maybe_constant_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override;
+
+  enum exp_opcode opcode () const override
+  { return BINOP_LOGICAL_AND; }
+
+protected:
+
+  void do_generate_ax (struct expression *exp,
+		       struct agent_expr *ax,
+		       struct axs_value *value,
+		       struct type *cast_type)
+    override;
+};
+
+/* The "||" operator.  */
+class logical_or_operation
+  : public maybe_constant_operation<operation_up, operation_up>
+{
+public:
+
+  using maybe_constant_operation::maybe_constant_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override;
+
+  enum exp_opcode opcode () const override
+  { return BINOP_LOGICAL_OR; }
+
+protected:
+
+  void do_generate_ax (struct expression *exp,
+		       struct agent_expr *ax,
+		       struct axs_value *value,
+		       struct type *cast_type)
+    override;
+};
+
 } /* namespace expr */
 
 #endif /* EXPOP_H */
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 138/203] Implement some Ada unary operations
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (136 preceding siblings ...)
  2021-01-01 21:46 ` [PATCH 137/203] Implement the "&&" and "||" operators Tom Tromey
@ 2021-01-01 21:46 ` Tom Tromey
  2021-01-01 21:46 ` [PATCH 139/203] Introduce ada_unop_range_operation Tom Tromey
                   ` (65 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:46 UTC (permalink / raw)
  To: gdb-patches

This implements a few Ada unary operations, using the existing
unop_operation template class.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* ada-lang.c (ada_unop_neg, ada_atr_tag, ada_atr_size, ada_abs):
	No longer static.
	* ada-exp.h (ada_neg_operation, ada_atr_tag_operation)
	(ada_atr_size_operation, ada_abs_operation): New typedefs.
---
 gdb/ChangeLog  |  7 +++++++
 gdb/ada-exp.h  | 22 ++++++++++++++++++++++
 gdb/ada-lang.c |  8 ++++----
 3 files changed, 33 insertions(+), 4 deletions(-)

diff --git a/gdb/ada-exp.h b/gdb/ada-exp.h
index 17a04ea15c6..8f114b3a145 100644
--- a/gdb/ada-exp.h
+++ b/gdb/ada-exp.h
@@ -22,6 +22,23 @@
 
 #include "expop.h"
 
+extern struct value *ada_unop_neg (struct type *expect_type,
+				   struct expression *exp,
+				   enum noside noside, enum exp_opcode op,
+				   struct value *arg1);
+extern struct value *ada_atr_tag (struct type *expect_type,
+				  struct expression *exp,
+				  enum noside noside, enum exp_opcode op,
+				  struct value *arg1);
+extern struct value *ada_atr_size (struct type *expect_type,
+				   struct expression *exp,
+				   enum noside noside, enum exp_opcode op,
+				   struct value *arg1);
+extern struct value *ada_abs (struct type *expect_type,
+			      struct expression *exp,
+			      enum noside noside, enum exp_opcode op,
+			      struct value *arg1);
+
 namespace expr
 {
 
@@ -87,6 +104,11 @@ class ada_ternop_range_operation
   { return TERNOP_IN_RANGE; }
 };
 
+using ada_neg_operation = unop_operation<UNOP_NEG, ada_unop_neg>;
+using ada_atr_tag_operation = unop_operation<OP_ATR_TAG, ada_atr_tag>;
+using ada_atr_size_operation = unop_operation<OP_ATR_SIZE, ada_atr_size>;
+using ada_abs_operation = unop_operation<UNOP_ABS, ada_abs>;
+
 } /* namespace expr */
 
 #endif /* ADA_EXP_H */
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 90592d5f2b9..32a64916d0e 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -10110,7 +10110,7 @@ eval_ternop_in_range (struct type *expect_type, struct expression *exp,
 
 /* A helper function for UNOP_NEG.  */
 
-static value *
+value *
 ada_unop_neg (struct type *expect_type,
 	      struct expression *exp,
 	      enum noside noside, enum exp_opcode op,
@@ -10166,7 +10166,7 @@ ada_unop_in_range (struct type *expect_type,
 
 /* A helper function for OP_ATR_TAG.  */
 
-static value *
+value *
 ada_atr_tag (struct type *expect_type,
 	     struct expression *exp,
 	     enum noside noside, enum exp_opcode op,
@@ -10180,7 +10180,7 @@ ada_atr_tag (struct type *expect_type,
 
 /* A helper function for OP_ATR_SIZE.  */
 
-static value *
+value *
 ada_atr_size (struct type *expect_type,
 	      struct expression *exp,
 	      enum noside noside, enum exp_opcode op,
@@ -10205,7 +10205,7 @@ ada_atr_size (struct type *expect_type,
 
 /* A helper function for UNOP_ABS.  */
 
-static value *
+value *
 ada_abs (struct type *expect_type,
 	 struct expression *exp,
 	 enum noside noside, enum exp_opcode op,
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 139/203] Introduce ada_unop_range_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (137 preceding siblings ...)
  2021-01-01 21:46 ` [PATCH 138/203] Implement some Ada unary operations Tom Tromey
@ 2021-01-01 21:46 ` Tom Tromey
  2021-01-01 21:46 ` [PATCH 140/203] Introduce class adl_func_operation Tom Tromey
                   ` (64 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:46 UTC (permalink / raw)
  To: gdb-patches

This adds class ada_unop_range_operation, which implements
UNOP_IN_RANGE.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* ada-lang.c (ada_unop_in_range): No longer static.
	* ada-exp.h (class ada_unop_range_operation): New.
---
 gdb/ChangeLog  |  5 +++++
 gdb/ada-exp.h  | 25 +++++++++++++++++++++++++
 gdb/ada-lang.c |  2 +-
 3 files changed, 31 insertions(+), 1 deletion(-)

diff --git a/gdb/ada-exp.h b/gdb/ada-exp.h
index 8f114b3a145..de69210bd2a 100644
--- a/gdb/ada-exp.h
+++ b/gdb/ada-exp.h
@@ -38,6 +38,10 @@ extern struct value *ada_abs (struct type *expect_type,
 			      struct expression *exp,
 			      enum noside noside, enum exp_opcode op,
 			      struct value *arg1);
+extern struct value *ada_unop_in_range (struct type *expect_type,
+					struct expression *exp,
+					enum noside noside, enum exp_opcode op,
+					struct value *arg1, struct type *type);
 
 namespace expr
 {
@@ -109,6 +113,27 @@ using ada_atr_tag_operation = unop_operation<OP_ATR_TAG, ada_atr_tag>;
 using ada_atr_size_operation = unop_operation<OP_ATR_SIZE, ada_atr_size>;
 using ada_abs_operation = unop_operation<UNOP_ABS, ada_abs>;
 
+/* The in-range operation, given a type.  */
+class ada_unop_range_operation
+  : public tuple_holding_operation<operation_up, struct type *>
+{
+public:
+
+  using tuple_holding_operation::tuple_holding_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override
+  {
+    value *val = std::get<0> (m_storage)->evaluate (nullptr, exp, noside);
+    return ada_unop_in_range (expect_type, exp, noside, UNOP_IN_RANGE,
+			      val, std::get<1> (m_storage));
+  }
+
+  enum exp_opcode opcode () const override
+  { return UNOP_IN_RANGE; }
+};
+
 } /* namespace expr */
 
 #endif /* ADA_EXP_H */
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 32a64916d0e..e2c9de69b65 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -10129,7 +10129,7 @@ ada_unop_neg (struct type *expect_type,
 
 /* A helper function for UNOP_IN_RANGE.  */
 
-static value *
+value *
 ada_unop_in_range (struct type *expect_type,
 		   struct expression *exp,
 		   enum noside noside, enum exp_opcode op,
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 140/203] Introduce class adl_func_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (138 preceding siblings ...)
  2021-01-01 21:46 ` [PATCH 139/203] Introduce ada_unop_range_operation Tom Tromey
@ 2021-01-01 21:46 ` Tom Tromey
  2021-01-01 21:46 ` [PATCH 141/203] Introduce array_operation Tom Tromey
                   ` (63 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:46 UTC (permalink / raw)
  To: gdb-patches

This adds class adl_func_operation, which implements
argument-dependent lookup function calls.

Other function calls will be handled in a different way.  However,
because ADL calls were created in a single spot in the C++ parser, and
because they had different semantics from the other cases, it was
convenient to treat them specially.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* expop.h (class adl_func_operation): New.
	* eval.c (adl_func_operation::evaluate): New method.
---
 gdb/ChangeLog |  5 +++++
 gdb/eval.c    | 23 +++++++++++++++++++++++
 gdb/expop.h   | 19 +++++++++++++++++++
 3 files changed, 47 insertions(+)

diff --git a/gdb/eval.c b/gdb/eval.c
index 495cd4b26a3..62b3f219ca4 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -2524,6 +2524,29 @@ logical_or_operation::evaluate (struct type *expect_type,
     }
 }
 
+value *
+adl_func_operation::evaluate (struct type *expect_type,
+			      struct expression *exp,
+			      enum noside noside)
+{
+  std::vector<operation_up> &arg_ops = std::get<2> (m_storage);
+  std::vector<value *> args (arg_ops.size ());
+  for (int i = 0; i < arg_ops.size (); ++i)
+    args[i] = arg_ops[i]->evaluate_with_coercion (exp, noside);
+
+  struct symbol *symp;
+  find_overload_match (args, std::get<0> (m_storage).c_str (),
+		       NON_METHOD,
+		       nullptr, nullptr,
+		       nullptr, &symp, nullptr, 0, noside);
+  if (SYMBOL_TYPE (symp)->code () == TYPE_CODE_ERROR)
+    error_unknown_type (symp->print_name ());
+  value *callee = evaluate_var_value (noside, std::get<1> (m_storage), symp);
+  return evaluate_subexp_do_call (exp, noside, callee, args,
+				  nullptr, expect_type);
+
+}
+
 }
 
 struct value *
diff --git a/gdb/expop.h b/gdb/expop.h
index f858f591baf..a8aa0f43acc 100644
--- a/gdb/expop.h
+++ b/gdb/expop.h
@@ -2027,6 +2027,25 @@ class logical_or_operation
     override;
 };
 
+/* This class implements ADL (aka Koenig) function calls for C++.  It
+   holds the name of the function to call, the block in which the
+   lookup should be done, and a vector of arguments.  */
+class adl_func_operation
+  : public tuple_holding_operation<std::string, const block *,
+				   std::vector<operation_up>>
+{
+public:
+
+  using tuple_holding_operation::tuple_holding_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override;
+
+  enum exp_opcode opcode () const override
+  { return OP_ADL_FUNC; }
+};
+
 } /* namespace expr */
 
 #endif /* EXPOP_H */
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 141/203] Introduce array_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (139 preceding siblings ...)
  2021-01-01 21:46 ` [PATCH 140/203] Introduce class adl_func_operation Tom Tromey
@ 2021-01-01 21:46 ` Tom Tromey
  2021-01-01 21:46 ` [PATCH 142/203] Implement function call operations Tom Tromey
                   ` (62 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:46 UTC (permalink / raw)
  To: gdb-patches

This adds class array_operation, which implements OP_ARRAY.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* expop.h (class array_operation): New.
	* eval.c (array_operation::evaluate_struct_tuple)
	(array_operation::evaluate): New methods.
---
 gdb/ChangeLog |   6 ++
 gdb/eval.c    | 200 ++++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/expop.h   |  22 ++++++
 3 files changed, 228 insertions(+)

diff --git a/gdb/eval.c b/gdb/eval.c
index 62b3f219ca4..2589e35ae30 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -2547,6 +2547,206 @@ adl_func_operation::evaluate (struct type *expect_type,
 
 }
 
+/* This function evaluates brace-initializers (in C/C++) for
+   structure types.  */
+
+struct value *
+array_operation::evaluate_struct_tuple (struct value *struct_val,
+					struct expression *exp,
+					enum noside noside, int nargs)
+{
+  const std::vector<operation_up> &in_args = std::get<2> (m_storage);
+  struct type *struct_type = check_typedef (value_type (struct_val));
+  struct type *field_type;
+  int fieldno = -1;
+
+  int idx = 0;
+  while (--nargs >= 0)
+    {
+      struct value *val = NULL;
+      int bitpos, bitsize;
+      bfd_byte *addr;
+
+      fieldno++;
+      /* Skip static fields.  */
+      while (fieldno < struct_type->num_fields ()
+	     && field_is_static (&struct_type->field (fieldno)))
+	fieldno++;
+      if (fieldno >= struct_type->num_fields ())
+	error (_("too many initializers"));
+      field_type = struct_type->field (fieldno).type ();
+      if (field_type->code () == TYPE_CODE_UNION
+	  && TYPE_FIELD_NAME (struct_type, fieldno)[0] == '0')
+	error (_("don't know which variant you want to set"));
+
+      /* Here, struct_type is the type of the inner struct,
+	 while substruct_type is the type of the inner struct.
+	 These are the same for normal structures, but a variant struct
+	 contains anonymous union fields that contain substruct fields.
+	 The value fieldno is the index of the top-level (normal or
+	 anonymous union) field in struct_field, while the value
+	 subfieldno is the index of the actual real (named inner) field
+	 in substruct_type.  */
+
+      field_type = struct_type->field (fieldno).type ();
+      if (val == 0)
+	val = in_args[idx++]->evaluate (field_type, exp, noside);
+
+      /* Now actually set the field in struct_val.  */
+
+      /* Assign val to field fieldno.  */
+      if (value_type (val) != field_type)
+	val = value_cast (field_type, val);
+
+      bitsize = TYPE_FIELD_BITSIZE (struct_type, fieldno);
+      bitpos = TYPE_FIELD_BITPOS (struct_type, fieldno);
+      addr = value_contents_writeable (struct_val) + bitpos / 8;
+      if (bitsize)
+	modify_field (struct_type, addr,
+		      value_as_long (val), bitpos % 8, bitsize);
+      else
+	memcpy (addr, value_contents (val),
+		TYPE_LENGTH (value_type (val)));
+
+    }
+  return struct_val;
+}
+
+value *
+array_operation::evaluate (struct type *expect_type,
+			   struct expression *exp,
+			   enum noside noside)
+{
+  int tem;
+  int tem2 = std::get<0> (m_storage);
+  int tem3 = std::get<1> (m_storage);
+  const std::vector<operation_up> &in_args = std::get<2> (m_storage);
+  int nargs = tem3 - tem2 + 1;
+  struct type *type = expect_type ? check_typedef (expect_type) : nullptr;
+
+  if (expect_type != nullptr && noside != EVAL_SKIP
+      && type->code () == TYPE_CODE_STRUCT)
+    {
+      struct value *rec = allocate_value (expect_type);
+
+      memset (value_contents_raw (rec), '\0', TYPE_LENGTH (type));
+      return evaluate_struct_tuple (rec, exp, noside, nargs);
+    }
+
+  if (expect_type != nullptr && noside != EVAL_SKIP
+      && type->code () == TYPE_CODE_ARRAY)
+    {
+      struct type *range_type = type->index_type ();
+      struct type *element_type = TYPE_TARGET_TYPE (type);
+      struct value *array = allocate_value (expect_type);
+      int element_size = TYPE_LENGTH (check_typedef (element_type));
+      LONGEST low_bound, high_bound, index;
+
+      if (!get_discrete_bounds (range_type, &low_bound, &high_bound))
+	{
+	  low_bound = 0;
+	  high_bound = (TYPE_LENGTH (type) / element_size) - 1;
+	}
+      index = low_bound;
+      memset (value_contents_raw (array), 0, TYPE_LENGTH (expect_type));
+      for (tem = nargs; --nargs >= 0;)
+	{
+	  struct value *element;
+
+	  element = in_args[index - low_bound]->evaluate (element_type,
+							  exp, noside);
+	  if (value_type (element) != element_type)
+	    element = value_cast (element_type, element);
+	  if (index > high_bound)
+	    /* To avoid memory corruption.  */
+	    error (_("Too many array elements"));
+	  memcpy (value_contents_raw (array)
+		  + (index - low_bound) * element_size,
+		  value_contents (element),
+		  element_size);
+	  index++;
+	}
+      return array;
+    }
+
+  if (expect_type != nullptr && noside != EVAL_SKIP
+      && type->code () == TYPE_CODE_SET)
+    {
+      struct value *set = allocate_value (expect_type);
+      gdb_byte *valaddr = value_contents_raw (set);
+      struct type *element_type = type->index_type ();
+      struct type *check_type = element_type;
+      LONGEST low_bound, high_bound;
+
+      /* Get targettype of elementtype.  */
+      while (check_type->code () == TYPE_CODE_RANGE
+	     || check_type->code () == TYPE_CODE_TYPEDEF)
+	check_type = TYPE_TARGET_TYPE (check_type);
+
+      if (!get_discrete_bounds (element_type, &low_bound, &high_bound))
+	error (_("(power)set type with unknown size"));
+      memset (valaddr, '\0', TYPE_LENGTH (type));
+      int idx = 0;
+      for (tem = 0; tem < nargs; tem++)
+	{
+	  LONGEST range_low, range_high;
+	  struct type *range_low_type, *range_high_type;
+	  struct value *elem_val;
+
+	  elem_val = in_args[idx++]->evaluate (element_type, exp, noside);
+	  range_low_type = range_high_type = value_type (elem_val);
+	  range_low = range_high = value_as_long (elem_val);
+
+	  /* Check types of elements to avoid mixture of elements from
+	     different types. Also check if type of element is "compatible"
+	     with element type of powerset.  */
+	  if (range_low_type->code () == TYPE_CODE_RANGE)
+	    range_low_type = TYPE_TARGET_TYPE (range_low_type);
+	  if (range_high_type->code () == TYPE_CODE_RANGE)
+	    range_high_type = TYPE_TARGET_TYPE (range_high_type);
+	  if ((range_low_type->code () != range_high_type->code ())
+	      || (range_low_type->code () == TYPE_CODE_ENUM
+		  && (range_low_type != range_high_type)))
+	    /* different element modes.  */
+	    error (_("POWERSET tuple elements of different mode"));
+	  if ((check_type->code () != range_low_type->code ())
+	      || (check_type->code () == TYPE_CODE_ENUM
+		  && range_low_type != check_type))
+	    error (_("incompatible POWERSET tuple elements"));
+	  if (range_low > range_high)
+	    {
+	      warning (_("empty POWERSET tuple range"));
+	      continue;
+	    }
+	  if (range_low < low_bound || range_high > high_bound)
+	    error (_("POWERSET tuple element out of range"));
+	  range_low -= low_bound;
+	  range_high -= low_bound;
+	  for (; range_low <= range_high; range_low++)
+	    {
+	      int bit_index = (unsigned) range_low % TARGET_CHAR_BIT;
+
+	      if (gdbarch_byte_order (exp->gdbarch) == BFD_ENDIAN_BIG)
+		bit_index = TARGET_CHAR_BIT - 1 - bit_index;
+	      valaddr[(unsigned) range_low / TARGET_CHAR_BIT]
+		|= 1 << bit_index;
+	    }
+	}
+      return set;
+    }
+
+  value **argvec = XALLOCAVEC (struct value *, nargs);
+  for (tem = 0; tem < nargs; tem++)
+    {
+      /* Ensure that array expressions are coerced into pointer
+	 objects.  */
+      argvec[tem] = in_args[tem]->evaluate_with_coercion (exp, noside);
+    }
+  if (noside == EVAL_SKIP)
+    return eval_skip_value (exp);
+  return value_array (tem2, tem3, argvec);
+}
+
 }
 
 struct value *
diff --git a/gdb/expop.h b/gdb/expop.h
index a8aa0f43acc..08e40345e76 100644
--- a/gdb/expop.h
+++ b/gdb/expop.h
@@ -2046,6 +2046,28 @@ class adl_func_operation
   { return OP_ADL_FUNC; }
 };
 
+/* The OP_ARRAY operation.  */
+class array_operation
+  : public tuple_holding_operation<int, int, std::vector<operation_up>>
+{
+public:
+
+  using tuple_holding_operation::tuple_holding_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override;
+
+  enum exp_opcode opcode () const override
+  { return OP_ARRAY; }
+
+private:
+
+  struct value *evaluate_struct_tuple (struct value *struct_val,
+				       struct expression *exp,
+				       enum noside noside, int nargs);
+};
+
 } /* namespace expr */
 
 #endif /* EXPOP_H */
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 142/203] Implement function call operations
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (140 preceding siblings ...)
  2021-01-01 21:46 ` [PATCH 141/203] Introduce array_operation Tom Tromey
@ 2021-01-01 21:46 ` Tom Tromey
  2021-01-01 21:46 ` [PATCH 143/203] Implement Rust funcall operation Tom Tromey
                   ` (61 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:46 UTC (permalink / raw)
  To: gdb-patches

This implement function call operations.

The current function call code relies on some very lengthy code
(evaluate_funcall is 398 lines...) to distinguish between the
different opcodes that might appear in the callee position.

Rather than try to replicate this, and have a function that tried to
dissect many different kinds of operation subclass, this patch instead
puts the work into the callee.  A new operation::evaluate_funcall
method is added, and then this is overridden in the classes that
require special treatment.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* expression.h (class operation) <evaluate_funcall>: New method.
	* expop.h (class scope_operation) <evaluate_funcall>: New method.
	(class var_value_operation) <evaluate_funcall>: New method.
	(class structop_base_operation) <evaluate_funcall>: New method.
	(class structop_member_base): New class.
	(class structop_member_operation): Derive from
	structop_member_base.
	(class structop_mptr_operation): Derive from
	structop_member_base.
	(class funcall_operation): New class.
	* eval.c (operation::evaluate_funcall)
	(var_value_operation::evaluate_funcall)
	(scope_operation::evaluate_funcall)
	(structop_member_base::evaluate_funcall)
	(structop_base_operation::evaluate_funcall): New methods.
---
 gdb/ChangeLog    |  18 +++
 gdb/eval.c       | 279 +++++++++++++++++++++++++++++++++++++++++++++++
 gdb/expop.h      |  55 +++++++++-
 gdb/expression.h |   9 ++
 4 files changed, 358 insertions(+), 3 deletions(-)

diff --git a/gdb/eval.c b/gdb/eval.c
index 2589e35ae30..ff3c58cd4a8 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1202,6 +1202,285 @@ evaluate_funcall (type *expect_type, expression *exp, int *pos,
 				  var_func_name, expect_type);
 }
 
+namespace expr
+{
+
+value *
+operation::evaluate_funcall (struct type *expect_type,
+			     struct expression *exp,
+			     enum noside noside,
+			     const std::vector<operation_up> &args)
+{
+  std::vector<value *> vals (args.size ());
+
+  value *callee = evaluate_with_coercion (exp, noside);
+  for (int i = 0; i < args.size (); ++i)
+    vals[i] = args[i]->evaluate_with_coercion (exp, noside);
+
+  return evaluate_subexp_do_call (exp, noside, callee, vals,
+				  nullptr, expect_type);
+}
+
+value *
+var_value_operation::evaluate_funcall (struct type *expect_type,
+				       struct expression *exp,
+				       enum noside noside,
+				       const std::vector<operation_up> &args)
+{
+  if (!overload_resolution
+      || exp->language_defn->la_language != language_cplus)
+    return operation::evaluate_funcall (expect_type, exp, noside, args);
+
+  std::vector<value *> argvec (args.size ());
+  for (int i = 0; i < args.size (); ++i)
+    argvec[i] = args[i]->evaluate_with_coercion (exp, noside);
+
+  struct symbol *symp;
+  find_overload_match (argvec, NULL, NON_METHOD,
+		       NULL, std::get<0> (m_storage),
+		       NULL, &symp, NULL, 0, noside);
+
+  if (SYMBOL_TYPE (symp)->code () == TYPE_CODE_ERROR)
+    error_unknown_type (symp->print_name ());
+  value *callee = evaluate_var_value (noside, std::get<1> (m_storage), symp);
+
+  return evaluate_subexp_do_call (exp, noside, callee, argvec,
+				  nullptr, expect_type);
+}
+
+value *
+scope_operation::evaluate_funcall (struct type *expect_type,
+				   struct expression *exp,
+				   enum noside noside,
+				   const std::vector<operation_up> &args)
+{
+  if (!overload_resolution
+      || exp->language_defn->la_language != language_cplus)
+    return operation::evaluate_funcall (expect_type, exp, noside, args);
+
+  /* Unpack it locally so we can properly handle overload
+     resolution.  */
+  const std::string &name = std::get<1> (m_storage);
+  struct type *type = std::get<0> (m_storage);
+
+  symbol *function = NULL;
+  const char *function_name = NULL;
+  std::vector<value *> argvec (1 + args.size ());
+  if (type->code () == TYPE_CODE_NAMESPACE)
+    {
+      function = cp_lookup_symbol_namespace (type->name (),
+					     name.c_str (),
+					     get_selected_block (0),
+					     VAR_DOMAIN).symbol;
+      if (function == NULL)
+	error (_("No symbol \"%s\" in namespace \"%s\"."),
+	       name.c_str (), type->name ());
+    }
+  else
+    {
+      gdb_assert (type->code () == TYPE_CODE_STRUCT
+		  || type->code () == TYPE_CODE_UNION);
+      function_name = name.c_str ();
+
+      /* We need a properly typed value for method lookup.  */
+      argvec[0] = value_zero (type, lval_memory);
+    }
+
+  for (int i = 0; i < args.size (); ++i)
+    argvec[i + 1] = args[i]->evaluate_with_coercion (exp, noside);
+  gdb::array_view<value *> arg_view = argvec;
+
+  value *callee = nullptr;
+  if (function_name != nullptr)
+    {
+      int static_memfuncp;
+
+      find_overload_match (arg_view, function_name, METHOD,
+			   &argvec[0], nullptr, &callee, nullptr,
+			   &static_memfuncp, 0, noside);
+      if (!static_memfuncp)
+	{
+	  /* For the time being, we don't handle this.  */
+	  error (_("Call to overloaded function %s requires "
+		   "`this' pointer"),
+		 function_name);
+	}
+
+      arg_view = arg_view.slice (1);
+    }
+  else
+    {
+      symbol *symp;
+      arg_view = arg_view.slice (1);
+      find_overload_match (arg_view, nullptr,
+			   NON_METHOD, nullptr, function,
+			   nullptr, &symp, nullptr, 1, noside);
+      callee = value_of_variable (symp, get_selected_block (0));
+    }
+
+  return evaluate_subexp_do_call (exp, noside, callee, arg_view,
+				  nullptr, expect_type);
+}
+
+value *
+structop_member_base::evaluate_funcall (struct type *expect_type,
+					struct expression *exp,
+					enum noside noside,
+					const std::vector<operation_up> &args)
+{
+  /* First, evaluate the structure into lhs.  */
+  value *lhs;
+  if (opcode () == STRUCTOP_MEMBER)
+    lhs = std::get<0> (m_storage)->evaluate_for_address (exp, noside);
+  else
+    lhs = std::get<0> (m_storage)->evaluate (nullptr, exp, noside);
+
+  std::vector<value *> vals (args.size () + 1);
+  gdb::array_view<value *> val_view = vals;
+  /* If the function is a virtual function, then the aggregate
+     value (providing the structure) plays its part by providing
+     the vtable.  Otherwise, it is just along for the ride: call
+     the function directly.  */
+  value *rhs = std::get<1> (m_storage)->evaluate (nullptr, exp, noside);
+  value *callee;
+
+  type *a1_type = check_typedef (value_type (rhs));
+  if (a1_type->code () == TYPE_CODE_METHODPTR)
+    {
+      if (noside == EVAL_AVOID_SIDE_EFFECTS)
+	callee = value_zero (TYPE_TARGET_TYPE (a1_type), not_lval);
+      else
+	callee = cplus_method_ptr_to_value (&lhs, rhs);
+
+      vals[0] = lhs;
+    }
+  else if (a1_type->code () == TYPE_CODE_MEMBERPTR)
+    {
+      struct type *type_ptr
+	= lookup_pointer_type (TYPE_SELF_TYPE (a1_type));
+      struct type *target_type_ptr
+	= lookup_pointer_type (TYPE_TARGET_TYPE (a1_type));
+
+      /* Now, convert this value to an address.  */
+      lhs = value_cast (type_ptr, lhs);
+
+      long mem_offset = value_as_long (rhs);
+
+      callee = value_from_pointer (target_type_ptr,
+				   value_as_long (lhs) + mem_offset);
+      callee = value_ind (callee);
+
+      val_view = val_view.slice (1);
+    }
+  else
+    error (_("Non-pointer-to-member value used in pointer-to-member "
+	     "construct"));
+
+  for (int i = 0; i < args.size (); ++i)
+    vals[i + 1] = args[i]->evaluate_with_coercion (exp, noside);
+
+  return evaluate_subexp_do_call (exp, noside, callee, val_view,
+				  nullptr, expect_type);
+
+}
+
+value *
+structop_base_operation::evaluate_funcall
+     (struct type *expect_type, struct expression *exp, enum noside noside,
+      const std::vector<operation_up> &args)
+{
+  std::vector<value *> vals (args.size () + 1);
+  /* First, evaluate the structure into vals[0].  */
+  enum exp_opcode op = opcode ();
+  if (op == STRUCTOP_STRUCT)
+    {
+      /* If v is a variable in a register, and the user types
+	 v.method (), this will produce an error, because v has no
+	 address.
+
+	 A possible way around this would be to allocate a copy of
+	 the variable on the stack, copy in the contents, call the
+	 function, and copy out the contents.  I.e. convert this
+	 from call by reference to call by copy-return (or
+	 whatever it's called).  However, this does not work
+	 because it is not the same: the method being called could
+	 stash a copy of the address, and then future uses through
+	 that address (after the method returns) would be expected
+	 to use the variable itself, not some copy of it.  */
+      vals[0] = std::get<0> (m_storage)->evaluate_for_address (exp, noside);
+    }
+  else
+    {
+      vals[0] = std::get<0> (m_storage)->evaluate (nullptr, exp, noside);
+      /* Check to see if the operator '->' has been overloaded.
+	 If the operator has been overloaded replace vals[0] with the
+	 value returned by the custom operator and continue
+	 evaluation.  */
+      while (unop_user_defined_p (op, vals[0]))
+	{
+	  struct value *value = nullptr;
+	  try
+	    {
+	      value = value_x_unop (vals[0], op, noside);
+	    }
+	  catch (const gdb_exception_error &except)
+	    {
+	      if (except.error == NOT_FOUND_ERROR)
+		break;
+	      else
+		throw;
+	    }
+
+	  vals[0] = value;
+	}
+    }
+
+  for (int i = 0; i < args.size (); ++i)
+    vals[i + 1] = args[i]->evaluate_with_coercion (exp, noside);
+  gdb::array_view<value *> arg_view = vals;
+
+  int static_memfuncp;
+  value *callee;
+  const char *tstr = std::get<1> (m_storage).c_str ();
+  if (overload_resolution
+      && exp->language_defn->la_language == language_cplus)
+    {
+      /* Language is C++, do some overload resolution before
+	 evaluation.  */
+      value *val0 = vals[0];
+      find_overload_match (arg_view, tstr, METHOD,
+			   &val0, nullptr, &callee, nullptr,
+			   &static_memfuncp, 0, noside);
+      vals[0] = val0;
+    }
+  else
+    /* Non-C++ case -- or no overload resolution.  */
+    {
+      struct value *temp = vals[0];
+
+      callee = value_struct_elt (&temp, &vals[1], tstr,
+				 &static_memfuncp,
+				 op == STRUCTOP_STRUCT
+				 ? "structure" : "structure pointer");
+      /* value_struct_elt updates temp with the correct value of the
+	 ``this'' pointer if necessary, so modify it to reflect any
+	 ``this'' changes.  */
+      vals[0] = value_from_longest (lookup_pointer_type (value_type (temp)),
+				    value_address (temp)
+				    + value_embedded_offset (temp));
+    }
+
+  /* Take out `this' if needed.  */
+  if (static_memfuncp)
+    arg_view = arg_view.slice (1);
+
+  return evaluate_subexp_do_call (exp, noside, callee, arg_view,
+				  nullptr, expect_type);
+}
+
+
+} /* namespace expr */
+
 /* Return true if type is integral or reference to integral */
 
 static bool
diff --git a/gdb/expop.h b/gdb/expop.h
index 08e40345e76..de4b876de39 100644
--- a/gdb/expop.h
+++ b/gdb/expop.h
@@ -594,6 +594,11 @@ class scope_operation
   value *evaluate_for_address (struct expression *exp,
 			       enum noside noside) override;
 
+  value *evaluate_funcall (struct type *expect_type,
+			   struct expression *exp,
+			   enum noside noside,
+			   const std::vector<operation_up> &args) override;
+
   enum exp_opcode opcode () const override
   { return OP_SCOPE; }
 
@@ -631,6 +636,11 @@ class var_value_operation
   value *evaluate_for_address (struct expression *exp, enum noside noside)
     override;
 
+  value *evaluate_funcall (struct type *expect_type,
+			   struct expression *exp,
+			   enum noside noside,
+			   const std::vector<operation_up> &args) override;
+
   enum exp_opcode opcode () const override
   { return OP_VAR_VALUE; }
 
@@ -971,6 +981,11 @@ class structop_base_operation
 					      EVAL_AVOID_SIDE_EFFECTS);
   }
 
+  value *evaluate_funcall (struct type *expect_type,
+			   struct expression *exp,
+			   enum noside noside,
+			   const std::vector<operation_up> &args) override;
+
 protected:
 
   using tuple_holding_operation::tuple_holding_operation;
@@ -1044,13 +1059,26 @@ class structop_ptr_operation
   }
 };
 
-class structop_member_operation
+class structop_member_base
   : public tuple_holding_operation<operation_up, operation_up>
 {
 public:
 
   using tuple_holding_operation::tuple_holding_operation;
 
+  value *evaluate_funcall (struct type *expect_type,
+			   struct expression *exp,
+			   enum noside noside,
+			   const std::vector<operation_up> &args) override;
+};
+
+class structop_member_operation
+  : public structop_member_base
+{
+public:
+
+  using structop_member_base::structop_member_base;
+
   value *evaluate (struct type *expect_type,
 		   struct expression *exp,
 		   enum noside noside) override
@@ -1067,11 +1095,11 @@ class structop_member_operation
 };
 
 class structop_mptr_operation
-  : public tuple_holding_operation<operation_up, operation_up>
+  : public structop_member_base
 {
 public:
 
-  using tuple_holding_operation::tuple_holding_operation;
+  using structop_member_base::structop_member_base;
 
   value *evaluate (struct type *expect_type,
 		   struct expression *exp,
@@ -2068,6 +2096,27 @@ class array_operation
 				       enum noside noside, int nargs);
 };
 
+/* A function call.  This holds the callee operation and the
+   arguments.  */
+class funcall_operation
+  : public tuple_holding_operation<operation_up, std::vector<operation_up>>
+{
+public:
+
+  using tuple_holding_operation::tuple_holding_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override
+  {
+    return std::get<0> (m_storage)->evaluate_funcall (expect_type, exp, noside,
+						      std::get<1> (m_storage));
+  }
+
+  enum exp_opcode opcode () const override
+  { return OP_FUNCALL; }
+};
+
 } /* namespace expr */
 
 #endif /* EXPOP_H */
diff --git a/gdb/expression.h b/gdb/expression.h
index 08a6424fdd2..a850f64d160 100644
--- a/gdb/expression.h
+++ b/gdb/expression.h
@@ -144,6 +144,15 @@ class operation
   virtual value *evaluate_for_address (struct expression *exp,
 				       enum noside noside);
 
+  /* Evaluate a function call, with this object as the callee.
+     EXPECT_TYPE, EXP, and NOSIDE have the same meaning as in
+     'evaluate'.  ARGS holds the operations that should be evaluated
+     to get the arguments to the call.  */
+  virtual value *evaluate_funcall (struct type *expect_type,
+				   struct expression *exp,
+				   enum noside noside,
+				   const std::vector<operation_up> &args);
+
   /* True if this is a constant expression.  */
   virtual bool constant_p () const
   { return false; }
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 143/203] Implement Rust funcall operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (141 preceding siblings ...)
  2021-01-01 21:46 ` [PATCH 142/203] Implement function call operations Tom Tromey
@ 2021-01-01 21:46 ` Tom Tromey
  2021-01-01 21:46 ` [PATCH 144/203] Introduce fortran_undetermined Tom Tromey
                   ` (60 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:46 UTC (permalink / raw)
  To: gdb-patches

This adds the special code needed to handle the Rust function call
operation.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* rust-lang.c (rust_structop::evaluate_funcall): New method.
	* rust-exp.h (class rust_structop) <evaluate_funcall>: Declare
	method.
---
 gdb/ChangeLog   |  6 ++++++
 gdb/rust-exp.h  |  5 +++++
 gdb/rust-lang.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 61 insertions(+)

diff --git a/gdb/rust-exp.h b/gdb/rust-exp.h
index 6e529f8e600..1019922fe8a 100644
--- a/gdb/rust-exp.h
+++ b/gdb/rust-exp.h
@@ -203,6 +203,11 @@ class rust_structop
 				  std::get<1> (m_storage).c_str ());
   }
 
+  value *evaluate_funcall (struct type *expect_type,
+			   struct expression *exp,
+			   enum noside noside,
+			   const std::vector<operation_up> &args) override;
+
   enum exp_opcode opcode () const override
   { return STRUCTOP_STRUCT; }
 };
diff --git a/gdb/rust-lang.c b/gdb/rust-lang.c
index 992319ffd2b..7605b64b384 100644
--- a/gdb/rust-lang.c
+++ b/gdb/rust-lang.c
@@ -1756,6 +1756,56 @@ rust_aggregate_operation::evaluate (struct type *expect_type,
   return result;
 }
 
+value *
+rust_structop::evaluate_funcall (struct type *expect_type,
+				 struct expression *exp,
+				 enum noside noside,
+				 const std::vector<operation_up> &ops)
+{
+  std::vector<struct value *> args (ops.size () + 1);
+
+  /* Evaluate the argument to STRUCTOP_STRUCT, then find its
+     type in order to look up the method.  */
+  args[0] = std::get<0> (m_storage)->evaluate (nullptr, exp, noside);
+  /* We don't yet implement real Deref semantics.  */
+  while (value_type (args[0])->code () == TYPE_CODE_PTR)
+    args[0] = value_ind (args[0]);
+
+  struct type *type = value_type (args[0]);
+  if ((type->code () != TYPE_CODE_STRUCT
+       && type->code () != TYPE_CODE_UNION
+       && type->code () != TYPE_CODE_ENUM)
+      || rust_tuple_type_p (type))
+    error (_("Method calls only supported on struct or enum types"));
+  if (type->name () == NULL)
+    error (_("Method call on nameless type"));
+
+  std::string name = (std::string (type->name ()) + "::"
+		      + std::get<1> (m_storage));
+
+  const struct block *block = get_selected_block (0);
+  struct block_symbol sym = lookup_symbol (name.c_str (), block,
+					   VAR_DOMAIN, NULL);
+  if (sym.symbol == NULL)
+    error (_("Could not find function named '%s'"), name.c_str ());
+
+  struct type *fn_type = SYMBOL_TYPE (sym.symbol);
+  if (fn_type->num_fields () == 0)
+    error (_("Function '%s' takes no arguments"), name.c_str ());
+
+  if (fn_type->field (0).type ()->code () == TYPE_CODE_PTR)
+    args[0] = value_addr (args[0]);
+
+  value *function = address_of_variable (sym.symbol, block);
+
+  for (int i = 0; i < ops.size (); ++i)
+    args[i + 1] = ops[i]->evaluate (nullptr, exp, noside);
+
+  if (noside == EVAL_AVOID_SIDE_EFFECTS)
+    return value_zero (TYPE_TARGET_TYPE (fn_type), not_lval);
+  return call_function_by_hand (function, NULL, args);
+}
+
 }
 
 /* operator_length implementation for Rust.  */
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 144/203] Introduce fortran_undetermined
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (142 preceding siblings ...)
  2021-01-01 21:46 ` [PATCH 143/203] Implement Rust funcall operation Tom Tromey
@ 2021-01-01 21:46 ` Tom Tromey
  2021-01-01 21:46 ` [PATCH 145/203] Introduce opencl_cast_type_operation Tom Tromey
                   ` (59 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:46 UTC (permalink / raw)
  To: gdb-patches

This adds class fortran_undetermined, which implements
OP_F77_UNDETERMINED_ARGLIST.  fortran_range_operation is also added
here, as it is needed by fortran_undetermined.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* f-lang.c (fortran_undetermined::value_subarray)
	(fortran_undetermined::evaluate): New methods.
	* f-exp.h (class fortran_range_operation)
	(class fortran_undetermined): New classes.
---
 gdb/ChangeLog |   7 +
 gdb/f-exp.h   |  63 +++++++
 gdb/f-lang.c  | 486 ++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 556 insertions(+)

diff --git a/gdb/f-exp.h b/gdb/f-exp.h
index 4b3fdd4a53e..b569c33ad9c 100644
--- a/gdb/f-exp.h
+++ b/gdb/f-exp.h
@@ -96,6 +96,69 @@ class fortran_cmplx_operation
   { return BINOP_FORTRAN_CMPLX; }
 };
 
+/* OP_RANGE for Fortran.  */
+class fortran_range_operation
+  : public tuple_holding_operation<enum range_flag, operation_up, operation_up,
+				   operation_up>
+{
+public:
+
+  using tuple_holding_operation::tuple_holding_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override
+  {
+    error (_("ranges not allowed in this context"));
+  }
+
+  range_flag get_flags () const
+  {
+    return std::get<0> (m_storage);
+  }
+
+  value *evaluate0 (struct expression *exp, enum noside noside) const
+  {
+    return std::get<1> (m_storage)->evaluate (nullptr, exp, noside);
+  }
+
+  value *evaluate1 (struct expression *exp, enum noside noside) const
+  {
+    return std::get<2> (m_storage)->evaluate (nullptr, exp, noside);
+  }
+
+  value *evaluate2 (struct expression *exp, enum noside noside) const
+  {
+    return std::get<3> (m_storage)->evaluate (nullptr, exp, noside);
+  }
+
+  enum exp_opcode opcode () const override
+  { return OP_RANGE; }
+};
+
+/* In F77, functions, substring ops and array subscript operations
+   cannot be disambiguated at parse time.  This operation handles
+   both, deciding which do to at evaluation time.  */
+class fortran_undetermined
+  : public tuple_holding_operation<operation_up, std::vector<operation_up>>
+{
+public:
+
+  using tuple_holding_operation::tuple_holding_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override;
+
+  enum exp_opcode opcode () const override
+  { return OP_F77_UNDETERMINED_ARGLIST; }
+
+private:
+
+  value *value_subarray (value *array, struct expression *exp,
+			 enum noside noside);
+};
+
 } /* namespace expr */
 
 #endif /* FORTRAN_EXP_H */
diff --git a/gdb/f-lang.c b/gdb/f-lang.c
index c680e136976..207c2ecefd7 100644
--- a/gdb/f-lang.c
+++ b/gdb/f-lang.c
@@ -1033,6 +1033,492 @@ evaluate_subexp_f (struct type *expect_type, struct expression *exp,
   return nullptr;
 }
 
+namespace expr
+{
+
+/* Called from evaluate to perform array indexing, and sub-range
+   extraction, for Fortran.  As well as arrays this function also
+   handles strings as they can be treated like arrays of characters.
+   ARRAY is the array or string being accessed.  EXP and NOSIDE are as
+   for evaluate.  */
+
+value *
+fortran_undetermined::value_subarray (value *array,
+				      struct expression *exp,
+				      enum noside noside)
+{
+  type *original_array_type = check_typedef (value_type (array));
+  bool is_string_p = original_array_type->code () == TYPE_CODE_STRING;
+  const std::vector<operation_up> &ops = std::get<1> (m_storage);
+  int nargs = ops.size ();
+
+  /* Perform checks for ARRAY not being available.  The somewhat overly
+     complex logic here is just to keep backward compatibility with the
+     errors that we used to get before FORTRAN_VALUE_SUBARRAY was
+     rewritten.  Maybe a future task would streamline the error messages we
+     get here, and update all the expected test results.  */
+  if (ops[0]->opcode () != OP_RANGE)
+    {
+      if (type_not_associated (original_array_type))
+	error (_("no such vector element (vector not associated)"));
+      else if (type_not_allocated (original_array_type))
+	error (_("no such vector element (vector not allocated)"));
+    }
+  else
+    {
+      if (type_not_associated (original_array_type))
+	error (_("array not associated"));
+      else if (type_not_allocated (original_array_type))
+	error (_("array not allocated"));
+    }
+
+  /* First check that the number of dimensions in the type we are slicing
+     matches the number of arguments we were passed.  */
+  int ndimensions = calc_f77_array_dims (original_array_type);
+  if (nargs != ndimensions)
+    error (_("Wrong number of subscripts"));
+
+  /* This will be initialised below with the type of the elements held in
+     ARRAY.  */
+  struct type *inner_element_type;
+
+  /* Extract the types of each array dimension from the original array
+     type.  We need these available so we can fill in the default upper and
+     lower bounds if the user requested slice doesn't provide that
+     information.  Additionally unpacking the dimensions like this gives us
+     the inner element type.  */
+  std::vector<struct type *> dim_types;
+  {
+    dim_types.reserve (ndimensions);
+    struct type *type = original_array_type;
+    for (int i = 0; i < ndimensions; ++i)
+      {
+	dim_types.push_back (type);
+	type = TYPE_TARGET_TYPE (type);
+      }
+    /* TYPE is now the inner element type of the array, we start the new
+       array slice off as this type, then as we process the requested slice
+       (from the user) we wrap new types around this to build up the final
+       slice type.  */
+    inner_element_type = type;
+  }
+
+  /* As we analyse the new slice type we need to understand if the data
+     being referenced is contiguous.  Do decide this we must track the size
+     of an element at each dimension of the new slice array.  Initially the
+     elements of the inner most dimension of the array are the same inner
+     most elements as the original ARRAY.  */
+  LONGEST slice_element_size = TYPE_LENGTH (inner_element_type);
+
+  /* Start off assuming all data is contiguous, this will be set to false
+     if access to any dimension results in non-contiguous data.  */
+  bool is_all_contiguous = true;
+
+  /* The TOTAL_OFFSET is the distance in bytes from the start of the
+     original ARRAY to the start of the new slice.  This is calculated as
+     we process the information from the user.  */
+  LONGEST total_offset = 0;
+
+  /* A structure representing information about each dimension of the
+     resulting slice.  */
+  struct slice_dim
+  {
+    /* Constructor.  */
+    slice_dim (LONGEST l, LONGEST h, LONGEST s, struct type *idx)
+      : low (l),
+	high (h),
+	stride (s),
+	index (idx)
+    { /* Nothing.  */ }
+
+    /* The low bound for this dimension of the slice.  */
+    LONGEST low;
+
+    /* The high bound for this dimension of the slice.  */
+    LONGEST high;
+
+    /* The byte stride for this dimension of the slice.  */
+    LONGEST stride;
+
+    struct type *index;
+  };
+
+  /* The dimensions of the resulting slice.  */
+  std::vector<slice_dim> slice_dims;
+
+  /* Process the incoming arguments.   These arguments are in the reverse
+     order to the array dimensions, that is the first argument refers to
+     the last array dimension.  */
+  if (fortran_array_slicing_debug)
+    debug_printf ("Processing array access:\n");
+  for (int i = 0; i < nargs; ++i)
+    {
+      /* For each dimension of the array the user will have either provided
+	 a ranged access with optional lower bound, upper bound, and
+	 stride, or the user will have supplied a single index.  */
+      struct type *dim_type = dim_types[ndimensions - (i + 1)];
+      fortran_range_operation *range_op
+	= dynamic_cast<fortran_range_operation *> (ops[i].get ());
+      if (range_op != nullptr)
+	{
+	  enum range_flag range_flag = range_op->get_flags ();
+
+	  LONGEST low, high, stride;
+	  low = high = stride = 0;
+
+	  if ((range_flag & RANGE_LOW_BOUND_DEFAULT) == 0)
+	    low = value_as_long (range_op->evaluate0 (exp, noside));
+	  else
+	    low = f77_get_lowerbound (dim_type);
+	  if ((range_flag & RANGE_HIGH_BOUND_DEFAULT) == 0)
+	    high = value_as_long (range_op->evaluate1 (exp, noside));
+	  else
+	    high = f77_get_upperbound (dim_type);
+	  if ((range_flag & RANGE_HAS_STRIDE) == RANGE_HAS_STRIDE)
+	    stride = value_as_long (range_op->evaluate2 (exp, noside));
+	  else
+	    stride = 1;
+
+	  if (stride == 0)
+	    error (_("stride must not be 0"));
+
+	  /* Get information about this dimension in the original ARRAY.  */
+	  struct type *target_type = TYPE_TARGET_TYPE (dim_type);
+	  struct type *index_type = dim_type->index_type ();
+	  LONGEST lb = f77_get_lowerbound (dim_type);
+	  LONGEST ub = f77_get_upperbound (dim_type);
+	  LONGEST sd = index_type->bit_stride ();
+	  if (sd == 0)
+	    sd = TYPE_LENGTH (target_type) * 8;
+
+	  if (fortran_array_slicing_debug)
+	    {
+	      debug_printf ("|-> Range access\n");
+	      std::string str = type_to_string (dim_type);
+	      debug_printf ("|   |-> Type: %s\n", str.c_str ());
+	      debug_printf ("|   |-> Array:\n");
+	      debug_printf ("|   |   |-> Low bound: %s\n", plongest (lb));
+	      debug_printf ("|   |   |-> High bound: %s\n", plongest (ub));
+	      debug_printf ("|   |   |-> Bit stride: %s\n", plongest (sd));
+	      debug_printf ("|   |   |-> Byte stride: %s\n", plongest (sd / 8));
+	      debug_printf ("|   |   |-> Type size: %s\n",
+			    pulongest (TYPE_LENGTH (dim_type)));
+	      debug_printf ("|   |   '-> Target type size: %s\n",
+			    pulongest (TYPE_LENGTH (target_type)));
+	      debug_printf ("|   |-> Accessing:\n");
+	      debug_printf ("|   |   |-> Low bound: %s\n",
+			    plongest (low));
+	      debug_printf ("|   |   |-> High bound: %s\n",
+			    plongest (high));
+	      debug_printf ("|   |   '-> Element stride: %s\n",
+			    plongest (stride));
+	    }
+
+	  /* Check the user hasn't asked for something invalid.  */
+	  if (high > ub || low < lb)
+	    error (_("array subscript out of bounds"));
+
+	  /* Calculate what this dimension of the new slice array will look
+	     like.  OFFSET is the byte offset from the start of the
+	     previous (more outer) dimension to the start of this
+	     dimension.  E_COUNT is the number of elements in this
+	     dimension.  REMAINDER is the number of elements remaining
+	     between the last included element and the upper bound.  For
+	     example an access '1:6:2' will include elements 1, 3, 5 and
+	     have a remainder of 1 (element #6).  */
+	  LONGEST lowest = std::min (low, high);
+	  LONGEST offset = (sd / 8) * (lowest - lb);
+	  LONGEST e_count = std::abs (high - low) + 1;
+	  e_count = (e_count + (std::abs (stride) - 1)) / std::abs (stride);
+	  LONGEST new_low = 1;
+	  LONGEST new_high = new_low + e_count - 1;
+	  LONGEST new_stride = (sd * stride) / 8;
+	  LONGEST last_elem = low + ((e_count - 1) * stride);
+	  LONGEST remainder = high - last_elem;
+	  if (low > high)
+	    {
+	      offset += std::abs (remainder) * TYPE_LENGTH (target_type);
+	      if (stride > 0)
+		error (_("incorrect stride and boundary combination"));
+	    }
+	  else if (stride < 0)
+	    error (_("incorrect stride and boundary combination"));
+
+	  /* Is the data within this dimension contiguous?  It is if the
+	     newly computed stride is the same size as a single element of
+	     this dimension.  */
+	  bool is_dim_contiguous = (new_stride == slice_element_size);
+	  is_all_contiguous &= is_dim_contiguous;
+
+	  if (fortran_array_slicing_debug)
+	    {
+	      debug_printf ("|   '-> Results:\n");
+	      debug_printf ("|       |-> Offset = %s\n", plongest (offset));
+	      debug_printf ("|       |-> Elements = %s\n", plongest (e_count));
+	      debug_printf ("|       |-> Low bound = %s\n", plongest (new_low));
+	      debug_printf ("|       |-> High bound = %s\n",
+			    plongest (new_high));
+	      debug_printf ("|       |-> Byte stride = %s\n",
+			    plongest (new_stride));
+	      debug_printf ("|       |-> Last element = %s\n",
+			    plongest (last_elem));
+	      debug_printf ("|       |-> Remainder = %s\n",
+			    plongest (remainder));
+	      debug_printf ("|       '-> Contiguous = %s\n",
+			    (is_dim_contiguous ? "Yes" : "No"));
+	    }
+
+	  /* Figure out how big (in bytes) an element of this dimension of
+	     the new array slice will be.  */
+	  slice_element_size = std::abs (new_stride * e_count);
+
+	  slice_dims.emplace_back (new_low, new_high, new_stride,
+				   index_type);
+
+	  /* Update the total offset.  */
+	  total_offset += offset;
+	}
+      else
+	{
+	  /* There is a single index for this dimension.  */
+	  LONGEST index
+	    = value_as_long (ops[i]->evaluate_with_coercion (exp, noside));
+
+	  /* Get information about this dimension in the original ARRAY.  */
+	  struct type *target_type = TYPE_TARGET_TYPE (dim_type);
+	  struct type *index_type = dim_type->index_type ();
+	  LONGEST lb = f77_get_lowerbound (dim_type);
+	  LONGEST ub = f77_get_upperbound (dim_type);
+	  LONGEST sd = index_type->bit_stride () / 8;
+	  if (sd == 0)
+	    sd = TYPE_LENGTH (target_type);
+
+	  if (fortran_array_slicing_debug)
+	    {
+	      debug_printf ("|-> Index access\n");
+	      std::string str = type_to_string (dim_type);
+	      debug_printf ("|   |-> Type: %s\n", str.c_str ());
+	      debug_printf ("|   |-> Array:\n");
+	      debug_printf ("|   |   |-> Low bound: %s\n", plongest (lb));
+	      debug_printf ("|   |   |-> High bound: %s\n", plongest (ub));
+	      debug_printf ("|   |   |-> Byte stride: %s\n", plongest (sd));
+	      debug_printf ("|   |   |-> Type size: %s\n",
+			    pulongest (TYPE_LENGTH (dim_type)));
+	      debug_printf ("|   |   '-> Target type size: %s\n",
+			    pulongest (TYPE_LENGTH (target_type)));
+	      debug_printf ("|   '-> Accessing:\n");
+	      debug_printf ("|       '-> Index: %s\n",
+			    plongest (index));
+	    }
+
+	  /* If the array has actual content then check the index is in
+	     bounds.  An array without content (an unbound array) doesn't
+	     have a known upper bound, so don't error check in that
+	     situation.  */
+	  if (index < lb
+	      || (dim_type->index_type ()->bounds ()->high.kind () != PROP_UNDEFINED
+		  && index > ub)
+	      || (VALUE_LVAL (array) != lval_memory
+		  && dim_type->index_type ()->bounds ()->high.kind () == PROP_UNDEFINED))
+	    {
+	      if (type_not_associated (dim_type))
+		error (_("no such vector element (vector not associated)"));
+	      else if (type_not_allocated (dim_type))
+		error (_("no such vector element (vector not allocated)"));
+	      else
+		error (_("no such vector element"));
+	    }
+
+	  /* Calculate using the type stride, not the target type size.  */
+	  LONGEST offset = sd * (index - lb);
+	  total_offset += offset;
+	}
+    }
+
+  /* Build a type that represents the new array slice in the target memory
+     of the original ARRAY, this type makes use of strides to correctly
+     find only those elements that are part of the new slice.  */
+  struct type *array_slice_type = inner_element_type;
+  for (const auto &d : slice_dims)
+    {
+      /* Create the range.  */
+      dynamic_prop p_low, p_high, p_stride;
+
+      p_low.set_const_val (d.low);
+      p_high.set_const_val (d.high);
+      p_stride.set_const_val (d.stride);
+
+      struct type *new_range
+	= create_range_type_with_stride ((struct type *) NULL,
+					 TYPE_TARGET_TYPE (d.index),
+					 &p_low, &p_high, 0, &p_stride,
+					 true);
+      array_slice_type
+	= create_array_type (nullptr, array_slice_type, new_range);
+    }
+
+  if (fortran_array_slicing_debug)
+    {
+      debug_printf ("'-> Final result:\n");
+      debug_printf ("    |-> Type: %s\n",
+		    type_to_string (array_slice_type).c_str ());
+      debug_printf ("    |-> Total offset: %s\n",
+		    plongest (total_offset));
+      debug_printf ("    |-> Base address: %s\n",
+		    core_addr_to_string (value_address (array)));
+      debug_printf ("    '-> Contiguous = %s\n",
+		    (is_all_contiguous ? "Yes" : "No"));
+    }
+
+  /* Should we repack this array slice?  */
+  if (!is_all_contiguous && (repack_array_slices || is_string_p))
+    {
+      /* Build a type for the repacked slice.  */
+      struct type *repacked_array_type = inner_element_type;
+      for (const auto &d : slice_dims)
+	{
+	  /* Create the range.  */
+	  dynamic_prop p_low, p_high, p_stride;
+
+	  p_low.set_const_val (d.low);
+	  p_high.set_const_val (d.high);
+	  p_stride.set_const_val (TYPE_LENGTH (repacked_array_type));
+
+	  struct type *new_range
+	    = create_range_type_with_stride ((struct type *) NULL,
+					     TYPE_TARGET_TYPE (d.index),
+					     &p_low, &p_high, 0, &p_stride,
+					     true);
+	  repacked_array_type
+	    = create_array_type (nullptr, repacked_array_type, new_range);
+	}
+
+      /* Now copy the elements from the original ARRAY into the packed
+	 array value DEST.  */
+      struct value *dest = allocate_value (repacked_array_type);
+      if (value_lazy (array)
+	  || (total_offset + TYPE_LENGTH (array_slice_type)
+	      > TYPE_LENGTH (check_typedef (value_type (array)))))
+	{
+	  fortran_array_walker<fortran_lazy_array_repacker_impl> p
+	    (array_slice_type, value_address (array) + total_offset, dest);
+	  p.walk ();
+	}
+      else
+	{
+	  fortran_array_walker<fortran_array_repacker_impl> p
+	    (array_slice_type, value_address (array) + total_offset,
+	     total_offset, array, dest);
+	  p.walk ();
+	}
+      array = dest;
+    }
+  else
+    {
+      if (VALUE_LVAL (array) == lval_memory)
+	{
+	  /* If the value we're taking a slice from is not yet loaded, or
+	     the requested slice is outside the values content range then
+	     just create a new lazy value pointing at the memory where the
+	     contents we're looking for exist.  */
+	  if (value_lazy (array)
+	      || (total_offset + TYPE_LENGTH (array_slice_type)
+		  > TYPE_LENGTH (check_typedef (value_type (array)))))
+	    array = value_at_lazy (array_slice_type,
+				   value_address (array) + total_offset);
+	  else
+	    array = value_from_contents_and_address (array_slice_type,
+						     (value_contents (array)
+						      + total_offset),
+						     (value_address (array)
+						      + total_offset));
+	}
+      else if (!value_lazy (array))
+	{
+	  const void *valaddr = value_contents (array) + total_offset;
+	  array = allocate_value (array_slice_type);
+	  memcpy (value_contents_raw (array), valaddr, TYPE_LENGTH (array_slice_type));
+	}
+      else
+	error (_("cannot subscript arrays that are not in memory"));
+    }
+
+  return array;
+}
+
+value *
+fortran_undetermined::evaluate (struct type *expect_type,
+				struct expression *exp,
+				enum noside noside)
+{
+  value *callee = std::get<0> (m_storage)->evaluate (nullptr, exp, noside);
+  struct type *type = check_typedef (value_type (callee));
+  enum type_code code = type->code ();
+
+  if (code == TYPE_CODE_PTR)
+    {
+      /* Fortran always passes variable to subroutines as pointer.
+	 So we need to look into its target type to see if it is
+	 array, string or function.  If it is, we need to switch
+	 to the target value the original one points to.  */
+      struct type *target_type = check_typedef (TYPE_TARGET_TYPE (type));
+
+      if (target_type->code () == TYPE_CODE_ARRAY
+	  || target_type->code () == TYPE_CODE_STRING
+	  || target_type->code () == TYPE_CODE_FUNC)
+	{
+	  callee = value_ind (callee);
+	  type = check_typedef (value_type (callee));
+	  code = type->code ();
+	}
+    }
+
+  switch (code)
+    {
+    case TYPE_CODE_ARRAY:
+    case TYPE_CODE_STRING:
+      return value_subarray (callee, exp, noside);
+
+    case TYPE_CODE_PTR:
+    case TYPE_CODE_FUNC:
+    case TYPE_CODE_INTERNAL_FUNCTION:
+      {
+	/* It's a function call.  Allocate arg vector, including
+	   space for the function to be called in argvec[0] and a
+	   termination NULL.  */
+	std::vector<value *> argvec (std::get<1> (m_storage).size ());
+	for (int tem = 0; tem < argvec.size (); tem++)
+	  {
+	    argvec[tem]
+	      = std::get<1> (m_storage)[tem]->evaluate_with_coercion (exp,
+								      noside);
+	    /* Arguments in Fortran are passed by address.  Coerce the
+	       arguments here rather than in value_arg_coerce as
+	       otherwise the call to malloc to place the non-lvalue
+	       parameters in target memory is hit by this Fortran
+	       specific logic.  This results in malloc being called
+	       with a pointer to an integer followed by an attempt to
+	       malloc the arguments to malloc in target memory.
+	       Infinite recursion ensues.  */
+	    if (code == TYPE_CODE_PTR || code == TYPE_CODE_FUNC)
+	      {
+		bool is_artificial
+		  = TYPE_FIELD_ARTIFICIAL (value_type (callee), tem);
+		argvec[tem] = fortran_argument_convert (argvec[tem],
+							is_artificial);
+	      }
+	  }
+	return evaluate_subexp_do_call (exp, noside, callee, argvec,
+					nullptr, expect_type);
+      }
+
+    default:
+      error (_("Cannot perform substring on this type"));
+    }
+}
+
+} /* namespace expr */
+
 /* Special expression lengths for Fortran.  */
 
 static void
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 145/203] Introduce opencl_cast_type_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (143 preceding siblings ...)
  2021-01-01 21:46 ` [PATCH 144/203] Introduce fortran_undetermined Tom Tromey
@ 2021-01-01 21:46 ` Tom Tromey
  2021-01-01 21:46 ` [PATCH 146/203] Implement OpenCL binary operations Tom Tromey
                   ` (58 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:46 UTC (permalink / raw)
  To: gdb-patches

This adds class opencl_cast_type_operation, which implements
UNOP_CAST_TYPE for OpenCL.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* opencl-lang.c (opencl_value_cast): No longer static.
	* c-exp.h (opencl_cast_type_operation): New typedef.
---
 gdb/ChangeLog     | 5 +++++
 gdb/c-exp.h       | 5 +++++
 gdb/opencl-lang.c | 3 ++-
 3 files changed, 12 insertions(+), 1 deletion(-)

diff --git a/gdb/c-exp.h b/gdb/c-exp.h
index 2d224c8c633..68efa62c5a8 100644
--- a/gdb/c-exp.h
+++ b/gdb/c-exp.h
@@ -27,6 +27,8 @@ extern struct value *eval_op_objc_selector (struct type *expect_type,
 					    struct expression *exp,
 					    enum noside noside,
 					    const char *sel);
+extern struct value *opencl_value_cast (struct type *type, struct value *arg);
+
 namespace expr
 {
 
@@ -105,6 +107,9 @@ class objc_msgcall_operation
   { return OP_OBJC_MSGCALL; }
 };
 
+using opencl_cast_type_operation = cxx_cast_operation<UNOP_CAST_TYPE,
+						      opencl_value_cast>;
+
 }/* namespace expr */
 
 #endif /* C_EXP_H */
diff --git a/gdb/opencl-lang.c b/gdb/opencl-lang.c
index b45e47eb506..c31eb51a390 100644
--- a/gdb/opencl-lang.c
+++ b/gdb/opencl-lang.c
@@ -27,6 +27,7 @@
 #include "varobj.h"
 #include "c-lang.h"
 #include "gdbarch.h"
+#include "c-exp.h"
 
 /* Returns the corresponding OpenCL vector type from the given type code,
    the length of the element type, the unsigned flag and the amount of
@@ -581,7 +582,7 @@ vector_relop (struct expression *exp, struct value *val1, struct value *val2,
    behaviour of scalar to vector casting.  As far as possibly we're going
    to try and delegate back to the standard value_cast function. */
 
-static struct value *
+struct value *
 opencl_value_cast (struct type *type, struct value *arg)
 {
   if (type != value_type (arg))
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 146/203] Implement OpenCL binary operations
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (144 preceding siblings ...)
  2021-01-01 21:46 ` [PATCH 145/203] Introduce opencl_cast_type_operation Tom Tromey
@ 2021-01-01 21:46 ` Tom Tromey
  2021-01-01 21:46 ` [PATCH 147/203] Introduce opencl_notequal_operation Tom Tromey
                   ` (57 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:46 UTC (permalink / raw)
  To: gdb-patches

This implements various OpenCL binary operations, adding a new
template class to do so.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* opencl-lang.c (opencl_relop, eval_opencl_assign): No longer
	static.  Change parameters.
	(eval_opencl_assign): No longer static.  Add "op" parameter.
	(evaluate_subexp_opencl): Update.
	* c-exp.h (opencl_binop_operation): New template class.
	(opencl_assign_operation, opencl_equal_operation)
	(opencl_notequal_operation, opencl_less_operation)
	(opencl_gtr_operation, opencl_geq_operation)
	(opencl_leq_operation): New typedefs.
---
 gdb/ChangeLog     | 12 +++++++++++
 gdb/c-exp.h       | 52 +++++++++++++++++++++++++++++++++++++++++++++++
 gdb/opencl-lang.c | 17 ++++++++--------
 3 files changed, 73 insertions(+), 8 deletions(-)

diff --git a/gdb/c-exp.h b/gdb/c-exp.h
index 68efa62c5a8..dc92e7a49a8 100644
--- a/gdb/c-exp.h
+++ b/gdb/c-exp.h
@@ -28,6 +28,16 @@ extern struct value *eval_op_objc_selector (struct type *expect_type,
 					    enum noside noside,
 					    const char *sel);
 extern struct value *opencl_value_cast (struct type *type, struct value *arg);
+extern struct value *eval_opencl_assign (struct type *expect_type,
+					 struct expression *exp,
+					 enum noside noside,
+					 enum exp_opcode op,
+					 struct value *arg1,
+					 struct value *arg2);
+extern struct value *opencl_relop (struct type *expect_type,
+				   struct expression *exp,
+				   enum noside noside, enum exp_opcode op,
+				   struct value *arg1, struct value *arg2);
 
 namespace expr
 {
@@ -110,6 +120,48 @@ class objc_msgcall_operation
 using opencl_cast_type_operation = cxx_cast_operation<UNOP_CAST_TYPE,
 						      opencl_value_cast>;
 
+/* Binary operations, as needed for OpenCL.  */
+template<enum exp_opcode OP, binary_ftype FUNC,
+	 typename BASE = maybe_constant_operation<operation_up, operation_up>>
+class opencl_binop_operation
+  : public BASE
+{
+public:
+
+  using BASE::BASE;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override
+  {
+    value *lhs
+      = std::get<0> (this->m_storage)->evaluate (nullptr, exp, noside);
+    value *rhs
+      = std::get<1> (this->m_storage)->evaluate (value_type (lhs), exp,
+						 noside);
+    return FUNC (expect_type, exp, noside, OP, lhs, rhs);
+  }
+
+  enum exp_opcode opcode () const override
+  { return OP; }
+};
+
+using opencl_assign_operation = opencl_binop_operation<BINOP_ASSIGN,
+						       eval_opencl_assign,
+						       assign_operation>;
+using opencl_equal_operation = opencl_binop_operation<BINOP_EQUAL,
+						      opencl_relop>;
+using opencl_notequal_operation = opencl_binop_operation<BINOP_NOTEQUAL,
+							 opencl_relop>;
+using opencl_less_operation = opencl_binop_operation<BINOP_LESS,
+						     opencl_relop>;
+using opencl_gtr_operation = opencl_binop_operation<BINOP_GTR,
+						    opencl_relop>;
+using opencl_geq_operation = opencl_binop_operation<BINOP_GEQ,
+						    opencl_relop>;
+using opencl_leq_operation = opencl_binop_operation<BINOP_LEQ,
+						    opencl_relop>;
+
 }/* namespace expr */
 
 #endif /* C_EXP_H */
diff --git a/gdb/opencl-lang.c b/gdb/opencl-lang.c
index c31eb51a390..01456055015 100644
--- a/gdb/opencl-lang.c
+++ b/gdb/opencl-lang.c
@@ -631,9 +631,10 @@ opencl_value_cast (struct type *type, struct value *arg)
 
 /* Perform a relational operation on two operands.  */
 
-static struct value *
-opencl_relop (struct expression *exp, struct value *arg1, struct value *arg2,
-	      enum exp_opcode op)
+struct value *
+opencl_relop (struct type *expect_type, struct expression *exp,
+	      enum noside noside, enum exp_opcode op,
+	      struct value *arg1, struct value *arg2)
 {
   struct value *val;
   struct type *type1 = check_typedef (value_type (arg1));
@@ -673,9 +674,9 @@ opencl_relop (struct expression *exp, struct value *arg1, struct value *arg2,
 
 /* A helper function for BINOP_ASSIGN.  */
 
-static struct value *
+struct value *
 eval_opencl_assign (struct type *expect_type, struct expression *exp,
-		    enum noside noside,
+		    enum noside noside, enum exp_opcode op,
 		    struct value *arg1, struct value *arg2)
 {
   if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS)
@@ -712,7 +713,7 @@ evaluate_subexp_opencl (struct type *expect_type, struct expression *exp,
       type1 = value_type (arg1);
       arg2 = evaluate_subexp (type1, exp, pos, noside);
 
-      return eval_opencl_assign (expect_type, exp, noside, arg1, arg2);
+      return eval_opencl_assign (expect_type, exp, noside, op, arg1, arg2);
 
     case UNOP_CAST:
       type1 = exp->elts[*pos + 1].type;
@@ -753,7 +754,7 @@ evaluate_subexp_opencl (struct type *expect_type, struct expression *exp,
 	return value_from_longest (builtin_type (exp->gdbarch)->
 				   builtin_int, 1);
 
-      return opencl_relop (exp, arg1, arg2, op);
+      return opencl_relop (expect_type, exp, noside, op, arg1, arg2);
 
     /* Handle the logical unary operator not(!).  */
     case UNOP_LOGICAL_NOT:
@@ -798,7 +799,7 @@ evaluate_subexp_opencl (struct type *expect_type, struct expression *exp,
 	    {
 	      arg2 = evaluate_subexp (nullptr, exp, pos, noside);
 
-	      return opencl_relop (exp, arg1, arg2, op);
+	      return opencl_relop (nullptr, exp, noside, op, arg1, arg2);
 	    }
 	  else
 	    {
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 147/203] Introduce opencl_notequal_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (145 preceding siblings ...)
  2021-01-01 21:46 ` [PATCH 146/203] Implement OpenCL binary operations Tom Tromey
@ 2021-01-01 21:46 ` Tom Tromey
  2021-01-01 21:46 ` [PATCH 148/203] Introduce opencl_structop_operation Tom Tromey
                   ` (56 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:46 UTC (permalink / raw)
  To: gdb-patches

This adds the opencl_notequal_operation typedef, implementing "!=" for
OpenCL.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* opencl-lang.c (opencl_logical_not): No longer static.  Change
	parameters.
	(evaluate_subexp_opencl): Update.
	* c-exp.h (opencl_notequal_operation): New typedef.
---
 gdb/ChangeLog     | 7 +++++++
 gdb/c-exp.h       | 8 ++++++++
 gdb/opencl-lang.c | 8 +++++---
 3 files changed, 20 insertions(+), 3 deletions(-)

diff --git a/gdb/c-exp.h b/gdb/c-exp.h
index dc92e7a49a8..1afe2d2fbee 100644
--- a/gdb/c-exp.h
+++ b/gdb/c-exp.h
@@ -38,6 +38,11 @@ extern struct value *opencl_relop (struct type *expect_type,
 				   struct expression *exp,
 				   enum noside noside, enum exp_opcode op,
 				   struct value *arg1, struct value *arg2);
+extern struct value *opencl_logical_not (struct type *expect_type,
+					 struct expression *exp,
+					 enum noside noside,
+					 enum exp_opcode op,
+					 struct value *arg);
 
 namespace expr
 {
@@ -162,6 +167,9 @@ using opencl_geq_operation = opencl_binop_operation<BINOP_GEQ,
 using opencl_leq_operation = opencl_binop_operation<BINOP_LEQ,
 						    opencl_relop>;
 
+using opencl_not_operation = unop_operation<UNOP_LOGICAL_NOT,
+					    opencl_logical_not>;
+
 }/* namespace expr */
 
 #endif /* C_EXP_H */
diff --git a/gdb/opencl-lang.c b/gdb/opencl-lang.c
index 01456055015..8ddcd76c589 100644
--- a/gdb/opencl-lang.c
+++ b/gdb/opencl-lang.c
@@ -441,8 +441,10 @@ opencl_component_ref (struct expression *exp, struct value *val,
 
 /* Perform the unary logical not (!) operation.  */
 
-static struct value *
-opencl_logical_not (struct expression *exp, struct value *arg)
+struct value *
+opencl_logical_not (struct type *expect_type, struct expression *exp,
+		    enum noside noside, enum exp_opcode op,
+		    struct value *arg)
 {
   struct type *type = check_typedef (value_type (arg));
   struct type *rettype;
@@ -765,7 +767,7 @@ evaluate_subexp_opencl (struct type *expect_type, struct expression *exp,
 	return value_from_longest (builtin_type (exp->gdbarch)->
 				   builtin_int, 1);
 
-      return opencl_logical_not (exp, arg1);
+      return opencl_logical_not (expect_type, exp, noside, op, arg1);
 
     /* Handle the logical operator and(&&) and or(||).  */
     case BINOP_LOGICAL_AND:
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 148/203] Introduce opencl_structop_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (146 preceding siblings ...)
  2021-01-01 21:46 ` [PATCH 147/203] Introduce opencl_notequal_operation Tom Tromey
@ 2021-01-01 21:46 ` Tom Tromey
  2021-01-01 21:46 ` [PATCH 149/203] Implement OpenCL logical binary operations Tom Tromey
                   ` (55 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:46 UTC (permalink / raw)
  To: gdb-patches

This adds class opencl_structop_operation, which implements
STRUCTOP_STRUCT for OpenCL.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* opencl-lang.c (opencl_structop_operation::evaluate): New
	method.
	* c-exp.h (class opencl_structop_operation): New.
---
 gdb/ChangeLog     |  6 ++++++
 gdb/c-exp.h       | 16 ++++++++++++++++
 gdb/opencl-lang.c | 28 ++++++++++++++++++++++++++++
 3 files changed, 50 insertions(+)

diff --git a/gdb/c-exp.h b/gdb/c-exp.h
index 1afe2d2fbee..58a16d5c0c8 100644
--- a/gdb/c-exp.h
+++ b/gdb/c-exp.h
@@ -170,6 +170,22 @@ using opencl_leq_operation = opencl_binop_operation<BINOP_LEQ,
 using opencl_not_operation = unop_operation<UNOP_LOGICAL_NOT,
 					    opencl_logical_not>;
 
+/* STRUCTOP_STRUCT implementation for OpenCL.  */
+class opencl_structop_operation
+  : public structop_base_operation
+{
+public:
+
+  using structop_base_operation::structop_base_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override;
+
+  enum exp_opcode opcode () const override
+  { return STRUCTOP_STRUCT; }
+};
+
 }/* namespace expr */
 
 #endif /* C_EXP_H */
diff --git a/gdb/opencl-lang.c b/gdb/opencl-lang.c
index 8ddcd76c589..317163966cd 100644
--- a/gdb/opencl-lang.c
+++ b/gdb/opencl-lang.c
@@ -958,6 +958,34 @@ Cannot perform conditional operation on vectors with different sizes"));
   return evaluate_subexp_c (expect_type, exp, pos, noside);
 }
 
+namespace expr
+{
+
+value *
+opencl_structop_operation::evaluate (struct type *expect_type,
+				     struct expression *exp,
+				     enum noside noside)
+{
+  value *arg1 = std::get<0> (m_storage)->evaluate (nullptr, exp, noside);
+  struct type *type1 = check_typedef (value_type (arg1));
+
+  if (type1->code () == TYPE_CODE_ARRAY && type1->is_vector ())
+    return opencl_component_ref (exp, arg1, std::get<1> (m_storage).c_str (),
+				 noside);
+  else
+    {
+      struct value *v = value_struct_elt (&arg1, NULL,
+					  std::get<1> (m_storage).c_str (),
+					  NULL, "structure");
+
+      if (noside == EVAL_AVOID_SIDE_EFFECTS)
+	v = value_zero (value_type (v), VALUE_LVAL (v));
+      return v;
+    }
+}
+
+} /* namespace expr */
+
 const struct exp_descriptor exp_descriptor_opencl =
 {
   print_subexp_standard,
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 149/203] Implement OpenCL logical binary operations
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (147 preceding siblings ...)
  2021-01-01 21:46 ` [PATCH 148/203] Introduce opencl_structop_operation Tom Tromey
@ 2021-01-01 21:46 ` Tom Tromey
  2021-01-01 21:46 ` [PATCH 150/203] Implement OpenCL ternary conditional operator Tom Tromey
                   ` (54 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:46 UTC (permalink / raw)
  To: gdb-patches

This implements "&&" and "||" for OpenCL.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* opencl-lang.c (opencl_logical_binop_operation::evaluate): New
	method.
	* c-exp.h (class opencl_logical_binop_operation): New.
---
 gdb/ChangeLog     |  6 ++++++
 gdb/c-exp.h       | 17 +++++++++++++++++
 gdb/opencl-lang.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 71 insertions(+)

diff --git a/gdb/c-exp.h b/gdb/c-exp.h
index 58a16d5c0c8..f75b4aed952 100644
--- a/gdb/c-exp.h
+++ b/gdb/c-exp.h
@@ -186,6 +186,23 @@ class opencl_structop_operation
   { return STRUCTOP_STRUCT; }
 };
 
+/* This handles the "&&" and "||" operations for OpenCL.  */
+class opencl_logical_binop_operation
+  : public tuple_holding_operation<enum exp_opcode,
+				   operation_up, operation_up>
+{
+public:
+
+  using tuple_holding_operation::tuple_holding_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override;
+
+  enum exp_opcode opcode () const override
+  { return std::get<0> (m_storage); }
+};
+
 }/* namespace expr */
 
 #endif /* C_EXP_H */
diff --git a/gdb/opencl-lang.c b/gdb/opencl-lang.c
index 317163966cd..cca8505cfac 100644
--- a/gdb/opencl-lang.c
+++ b/gdb/opencl-lang.c
@@ -984,6 +984,54 @@ opencl_structop_operation::evaluate (struct type *expect_type,
     }
 }
 
+value *
+opencl_logical_binop_operation::evaluate (struct type *expect_type,
+					  struct expression *exp,
+					  enum noside noside)
+{
+  enum exp_opcode op = std::get<0> (m_storage);
+  value *arg1 = std::get<1> (m_storage)->evaluate (nullptr, exp, noside);
+
+  /* For scalar operations we need to avoid evaluating operands
+     unnecessarily.  However, for vector operations we always need to
+     evaluate both operands.  Unfortunately we only know which of the
+     two cases apply after we know the type of the second operand.
+     Therefore we evaluate it once using EVAL_AVOID_SIDE_EFFECTS.  */
+  value *arg2 = std::get<2> (m_storage)->evaluate (nullptr, exp,
+						   EVAL_AVOID_SIDE_EFFECTS);
+  struct type *type1 = check_typedef (value_type (arg1));
+  struct type *type2 = check_typedef (value_type (arg2));
+
+  if ((type1->code () == TYPE_CODE_ARRAY && type1->is_vector ())
+      || (type2->code () == TYPE_CODE_ARRAY && type2->is_vector ()))
+    {
+      arg2 = std::get<2> (m_storage)->evaluate (nullptr, exp, noside);
+
+      return opencl_relop (nullptr, exp, noside, op, arg1, arg2);
+    }
+  else
+    {
+      /* For scalar built-in types, only evaluate the right
+	 hand operand if the left hand operand compares
+	 unequal(&&)/equal(||) to 0.  */
+      int tmp = value_logical_not (arg1);
+
+      if (op == BINOP_LOGICAL_OR)
+	tmp = !tmp;
+
+      if (!tmp)
+	{
+	  arg2 = std::get<2> (m_storage)->evaluate (nullptr, exp, noside);
+	  tmp = value_logical_not (arg2);
+	  if (op == BINOP_LOGICAL_OR)
+	    tmp = !tmp;
+	}
+
+      type1 = language_bool_type (exp->language_defn, exp->gdbarch);
+      return value_from_longest (type1, tmp);
+    }
+}
+
 } /* namespace expr */
 
 const struct exp_descriptor exp_descriptor_opencl =
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 150/203] Implement OpenCL ternary conditional operator
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (148 preceding siblings ...)
  2021-01-01 21:46 ` [PATCH 149/203] Implement OpenCL logical binary operations Tom Tromey
@ 2021-01-01 21:46 ` Tom Tromey
  2021-01-01 21:46 ` [PATCH 151/203] Split out some Ada type resolution code Tom Tromey
                   ` (53 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:46 UTC (permalink / raw)
  To: gdb-patches

This implements the ?: ternary conditional operator for OpenCL.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* opencl-lang.c (opencl_ternop_cond_operation::evaluate): New
	method.
	* c-exp.h (class opencl_ternop_cond_operation): New.
---
 gdb/ChangeLog     |  6 ++++
 gdb/c-exp.h       | 16 +++++++++
 gdb/opencl-lang.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 107 insertions(+)

diff --git a/gdb/c-exp.h b/gdb/c-exp.h
index f75b4aed952..0ce2bd6eb22 100644
--- a/gdb/c-exp.h
+++ b/gdb/c-exp.h
@@ -203,6 +203,22 @@ class opencl_logical_binop_operation
   { return std::get<0> (m_storage); }
 };
 
+/* The ?: ternary operator for OpenCL.  */
+class opencl_ternop_cond_operation
+  : public tuple_holding_operation<operation_up, operation_up, operation_up>
+{
+public:
+
+  using tuple_holding_operation::tuple_holding_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override;
+
+  enum exp_opcode opcode () const override
+  { return TERNOP_COND; }
+};
+
 }/* namespace expr */
 
 #endif /* C_EXP_H */
diff --git a/gdb/opencl-lang.c b/gdb/opencl-lang.c
index cca8505cfac..c5150953022 100644
--- a/gdb/opencl-lang.c
+++ b/gdb/opencl-lang.c
@@ -1032,6 +1032,91 @@ opencl_logical_binop_operation::evaluate (struct type *expect_type,
     }
 }
 
+value *
+opencl_ternop_cond_operation::evaluate (struct type *expect_type,
+					struct expression *exp,
+					enum noside noside)
+{
+  value *arg1 = std::get<0> (m_storage)->evaluate (nullptr, exp, noside);
+  struct type *type1 = check_typedef (value_type (arg1));
+  if (type1->code () == TYPE_CODE_ARRAY && type1->is_vector ())
+    {
+      struct value *arg2, *arg3, *tmp, *ret;
+      struct type *eltype2, *type2, *type3, *eltype3;
+      int t2_is_vec, t3_is_vec, i;
+      LONGEST lowb1, lowb2, lowb3, highb1, highb2, highb3;
+
+      arg2 = std::get<1> (m_storage)->evaluate (nullptr, exp, noside);
+      arg3 = std::get<2> (m_storage)->evaluate (nullptr, exp, noside);
+      type2 = check_typedef (value_type (arg2));
+      type3 = check_typedef (value_type (arg3));
+      t2_is_vec
+	= type2->code () == TYPE_CODE_ARRAY && type2->is_vector ();
+      t3_is_vec
+	= type3->code () == TYPE_CODE_ARRAY && type3->is_vector ();
+
+      /* Widen the scalar operand to a vector if necessary.  */
+      if (t2_is_vec || !t3_is_vec)
+	{
+	  arg3 = opencl_value_cast (type2, arg3);
+	  type3 = value_type (arg3);
+	}
+      else if (!t2_is_vec || t3_is_vec)
+	{
+	  arg2 = opencl_value_cast (type3, arg2);
+	  type2 = value_type (arg2);
+	}
+      else if (!t2_is_vec || !t3_is_vec)
+	{
+	  /* Throw an error if arg2 or arg3 aren't vectors.  */
+	  error (_("\
+Cannot perform conditional operation on incompatible types"));
+	}
+
+      eltype2 = check_typedef (TYPE_TARGET_TYPE (type2));
+      eltype3 = check_typedef (TYPE_TARGET_TYPE (type3));
+
+      if (!get_array_bounds (type1, &lowb1, &highb1)
+	  || !get_array_bounds (type2, &lowb2, &highb2)
+	  || !get_array_bounds (type3, &lowb3, &highb3))
+	error (_("Could not determine the vector bounds"));
+
+      /* Throw an error if the types of arg2 or arg3 are incompatible.  */
+      if (eltype2->code () != eltype3->code ()
+	  || TYPE_LENGTH (eltype2) != TYPE_LENGTH (eltype3)
+	  || eltype2->is_unsigned () != eltype3->is_unsigned ()
+	  || lowb2 != lowb3 || highb2 != highb3)
+	error (_("\
+Cannot perform operation on vectors with different types"));
+
+      /* Throw an error if the sizes of arg1 and arg2/arg3 differ.  */
+      if (lowb1 != lowb2 || lowb1 != lowb3
+	  || highb1 != highb2 || highb1 != highb3)
+	error (_("\
+Cannot perform conditional operation on vectors with different sizes"));
+
+      ret = allocate_value (type2);
+
+      for (i = 0; i < highb1 - lowb1 + 1; i++)
+	{
+	  tmp = value_logical_not (value_subscript (arg1, i)) ?
+	    value_subscript (arg3, i) : value_subscript (arg2, i);
+	  memcpy (value_contents_writeable (ret) +
+		  i * TYPE_LENGTH (eltype2), value_contents_all (tmp),
+		  TYPE_LENGTH (eltype2));
+	}
+
+      return ret;
+    }
+  else
+    {
+      if (value_logical_not (arg1))
+	return std::get<2> (m_storage)->evaluate (nullptr, exp, noside);
+      else
+	return std::get<1> (m_storage)->evaluate (nullptr, exp, noside);
+    }
+}
+
 } /* namespace expr */
 
 const struct exp_descriptor exp_descriptor_opencl =
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 151/203] Split out some Ada type resolution code
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (149 preceding siblings ...)
  2021-01-01 21:46 ` [PATCH 150/203] Implement OpenCL ternary conditional operator Tom Tromey
@ 2021-01-01 21:46 ` Tom Tromey
  2021-01-03  7:46   ` Joel Brobecker
  2021-01-01 21:46 ` [PATCH 152/203] Introduce ada_binop_addsub_operation Tom Tromey
                   ` (52 subsequent siblings)
  203 siblings, 1 reply; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:46 UTC (permalink / raw)
  To: gdb-patches

This splits some Ada type resolution code out of resolve_subexp into
new functions that can be reused.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* ada-lang.h (ada_find_operator_symbol, ada_resolve_funcall)
	(ada_resolve_variable): Declare.
	* ada-lang.c (ada_find_operator_symbol, ada_resolve_funcall)
	(ada_resolve_variable): New functions.
	(resolve_subexp): Update.
---
 gdb/ChangeLog  |   8 ++
 gdb/ada-lang.c | 266 ++++++++++++++++++++++++++++---------------------
 gdb/ada-lang.h |  18 ++++
 3 files changed, 176 insertions(+), 116 deletions(-)

diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index e2c9de69b65..50b82e6bcf9 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -3452,6 +3452,132 @@ See set/show multiple-symbol."));
   return n_chosen;
 }
 
+/* See ada-lang.h.  */
+
+block_symbol
+ada_find_operator_symbol (enum exp_opcode op, int parse_completion,
+			  int nargs, value *argvec[])
+{
+  if (possible_user_operator_p (op, argvec))
+    {
+      std::vector<struct block_symbol> candidates;
+      int n_candidates = ada_lookup_symbol_list (ada_decoded_op_name (op),
+						 NULL, VAR_DOMAIN,
+						 &candidates);
+      int i = ada_resolve_function (candidates.data (), n_candidates, argvec,
+				    nargs, ada_decoded_op_name (op), NULL,
+				    parse_completion);
+      if (i >= 0)
+	return candidates[i];
+    }
+  return {};
+}
+
+/* See ada-lang.h.  */
+
+block_symbol
+ada_resolve_funcall (struct symbol *sym, const struct block *block,
+		     struct type *context_type,
+		     int parse_completion,
+		     int nargs, value *argvec[],
+		     innermost_block_tracker *tracker)
+{
+  std::vector<struct block_symbol> candidates;
+  int n_candidates = ada_lookup_symbol_list (sym->linkage_name (), block,
+					     VAR_DOMAIN, &candidates);
+
+  int i;
+  if (n_candidates == 1)
+    i = 0;
+  else
+    {
+      i = ada_resolve_function (candidates.data (), n_candidates,
+				argvec, nargs,
+				sym->linkage_name (),
+				context_type, parse_completion);
+      if (i < 0)
+	error (_("Could not find a match for %s"), sym->print_name ());
+    }
+
+  tracker->update (candidates[i]);
+  return candidates[i];
+}
+
+/* See ada-lang.h.  */
+
+block_symbol
+ada_resolve_variable (struct symbol *sym, const struct block *block,
+		      struct type *context_type,
+		      int parse_completion,
+		      int deprocedure_p,
+		      innermost_block_tracker *tracker)
+{
+  std::vector<struct block_symbol> candidates;
+  int n_candidates = ada_lookup_symbol_list (sym->linkage_name (),
+					     block, VAR_DOMAIN,
+					     &candidates);
+
+  if (n_candidates > 1)
+    {
+      /* Types tend to get re-introduced locally, so if there are any
+	 local symbols that are not types, first filter out all
+	 types.  */
+      int j;
+      for (j = 0; j < n_candidates; j += 1)
+	switch (SYMBOL_CLASS (candidates[j].symbol))
+	  {
+	  case LOC_REGISTER:
+	  case LOC_ARG:
+	  case LOC_REF_ARG:
+	  case LOC_REGPARM_ADDR:
+	  case LOC_LOCAL:
+	  case LOC_COMPUTED:
+	    goto FoundNonType;
+	  default:
+	    break;
+	  }
+    FoundNonType:
+      if (j < n_candidates)
+	{
+	  j = 0;
+	  while (j < n_candidates)
+	    {
+	      if (SYMBOL_CLASS (candidates[j].symbol) == LOC_TYPEDEF)
+		{
+		  candidates[j] = candidates[n_candidates - 1];
+		  n_candidates -= 1;
+		}
+	      else
+		j += 1;
+	    }
+	}
+    }
+
+  int i;
+  if (n_candidates == 0)
+    error (_("No definition found for %s"), sym->print_name ());
+  else if (n_candidates == 1)
+    i = 0;
+  else if (deprocedure_p
+	   && !is_nonfunction (candidates.data (), n_candidates))
+    {
+      i = ada_resolve_function (candidates.data (), n_candidates, NULL, 0,
+				sym->linkage_name (),
+				context_type, parse_completion);
+      if (i < 0)
+	error (_("Could not find a match for %s"), sym->print_name ());
+    }
+  else
+    {
+      printf_filtered (_("Multiple matches for %s\n"), sym->print_name ());
+      user_select_syms (candidates.data (), n_candidates, 1);
+      i = 0;
+    }
+
+  tracker->update (candidates[i]);
+  return candidates[i];
+}
+
 /* Resolve the operator of the subexpression beginning at
    position *POS of *EXPP.  "Resolving" consists of replacing
    the symbols that have undefined namespaces in OP_VAR_VALUE nodes
@@ -3640,77 +3766,13 @@ resolve_subexp (expression_up *expp, int *pos, int deprocedure_p,
     case OP_VAR_VALUE:
       if (SYMBOL_DOMAIN (exp->elts[pc + 2].symbol) == UNDEF_DOMAIN)
 	{
-	  std::vector<struct block_symbol> candidates;
-	  int n_candidates;
-
-	  n_candidates =
-	    ada_lookup_symbol_list (exp->elts[pc + 2].symbol->linkage_name (),
-				    exp->elts[pc + 1].block, VAR_DOMAIN,
-				    &candidates);
-
-	  if (n_candidates > 1)
-	    {
-	      /* Types tend to get re-introduced locally, so if there
-		 are any local symbols that are not types, first filter
-		 out all types.  */
-	      int j;
-	      for (j = 0; j < n_candidates; j += 1)
-		switch (SYMBOL_CLASS (candidates[j].symbol))
-		  {
-		  case LOC_REGISTER:
-		  case LOC_ARG:
-		  case LOC_REF_ARG:
-		  case LOC_REGPARM_ADDR:
-		  case LOC_LOCAL:
-		  case LOC_COMPUTED:
-		    goto FoundNonType;
-		  default:
-		    break;
-		  }
-	    FoundNonType:
-	      if (j < n_candidates)
-		{
-		  j = 0;
-		  while (j < n_candidates)
-		    {
-		      if (SYMBOL_CLASS (candidates[j].symbol) == LOC_TYPEDEF)
-			{
-			  candidates[j] = candidates[n_candidates - 1];
-			  n_candidates -= 1;
-			}
-		      else
-			j += 1;
-		    }
-		}
-	    }
-
-	  if (n_candidates == 0)
-	    error (_("No definition found for %s"),
-		   exp->elts[pc + 2].symbol->print_name ());
-	  else if (n_candidates == 1)
-	    i = 0;
-	  else if (deprocedure_p
-		   && !is_nonfunction (candidates.data (), n_candidates))
-	    {
-	      i = ada_resolve_function
-		(candidates.data (), n_candidates, NULL, 0,
-		 exp->elts[pc + 2].symbol->linkage_name (),
-		 context_type, parse_completion);
-	      if (i < 0)
-		error (_("Could not find a match for %s"),
-		       exp->elts[pc + 2].symbol->print_name ());
-	    }
-	  else
-	    {
-	      printf_filtered (_("Multiple matches for %s\n"),
-			       exp->elts[pc + 2].symbol->print_name ());
-	      user_select_syms (candidates.data (), n_candidates, 1);
-	      i = 0;
-	    }
-
-	  exp->elts[pc + 1].block = candidates[i].block;
-	  exp->elts[pc + 2].symbol = candidates[i].symbol;
-	  tracker->update (candidates[i]);
+	  block_symbol resolved
+	    = ada_resolve_variable (exp->elts[pc + 2].symbol,
+				    exp->elts[pc + 1].block,
+				    context_type, parse_completion,
+				    deprocedure_p, tracker);
+	  exp->elts[pc + 1].block = resolved.block;
+	  exp->elts[pc + 2].symbol = resolved.symbol;
 	}
 
       if (deprocedure_p
@@ -3729,31 +3791,14 @@ resolve_subexp (expression_up *expp, int *pos, int deprocedure_p,
 	if (exp->elts[pc + 3].opcode == OP_VAR_VALUE
 	    && SYMBOL_DOMAIN (exp->elts[pc + 5].symbol) == UNDEF_DOMAIN)
 	  {
-	    std::vector<struct block_symbol> candidates;
-	    int n_candidates;
-
-	    n_candidates =
-	      ada_lookup_symbol_list (exp->elts[pc + 5].symbol->linkage_name (),
-				      exp->elts[pc + 4].block, VAR_DOMAIN,
-				      &candidates);
-
-	    if (n_candidates == 1)
-	      i = 0;
-	    else
-	      {
-		i = ada_resolve_function
-		  (candidates.data (), n_candidates,
-		   argvec, nargs,
-		   exp->elts[pc + 5].symbol->linkage_name (),
-		   context_type, parse_completion);
-		if (i < 0)
-		  error (_("Could not find a match for %s"),
-			 exp->elts[pc + 5].symbol->print_name ());
-	      }
-
-	    exp->elts[pc + 4].block = candidates[i].block;
-	    exp->elts[pc + 5].symbol = candidates[i].symbol;
-	    tracker->update (candidates[i]);
+	    block_symbol resolved
+	      = ada_resolve_funcall (exp->elts[pc + 5].symbol,
+				     exp->elts[pc + 4].block,
+				     context_type, parse_completion,
+				     nargs, argvec,
+				     tracker);
+	    exp->elts[pc + 4].block = resolved.block;
+	    exp->elts[pc + 5].symbol = resolved.symbol;
 	  }
       }
       break;
@@ -3778,27 +3823,16 @@ resolve_subexp (expression_up *expp, int *pos, int deprocedure_p,
     case UNOP_PLUS:
     case UNOP_LOGICAL_NOT:
     case UNOP_ABS:
-      if (possible_user_operator_p (op, argvec))
-	{
-	  std::vector<struct block_symbol> candidates;
-	  int n_candidates;
-
-	  n_candidates =
-	    ada_lookup_symbol_list (ada_decoded_op_name (op),
-				    NULL, VAR_DOMAIN,
-				    &candidates);
-
-	  i = ada_resolve_function (candidates.data (), n_candidates, argvec,
-				    nargs, ada_decoded_op_name (op), NULL,
-				    parse_completion);
-	  if (i < 0)
-	    break;
+      {
+	block_symbol found = ada_find_operator_symbol (op, parse_completion,
+						       nargs, argvec);
+	if (found.symbol == nullptr)
+	  break;
 
-	  replace_operator_with_call (expp, pc, nargs, 1,
-				      candidates[i].symbol,
-				      candidates[i].block);
-	  exp = expp->get ();
-	}
+	replace_operator_with_call (expp, pc, nargs, 1,
+				    found.symbol, found.block);
+	exp = expp->get ();
+      }
       break;
 
     case OP_TYPE:
diff --git a/gdb/ada-lang.h b/gdb/ada-lang.h
index dbf45a84928..8333def6280 100644
--- a/gdb/ada-lang.h
+++ b/gdb/ada-lang.h
@@ -386,4 +386,22 @@ extern void print_ada_task_info (struct ui_out *uiout,
 				 const char *taskno_str,
 				 struct inferior *inf);
 
+extern block_symbol ada_find_operator_symbol (enum exp_opcode op,
+					      int parse_completion,
+					      int nargs, value *argvec[]);
+
+extern block_symbol ada_resolve_funcall (struct symbol *sym,
+					 const struct block *block,
+					 struct type *context_type,
+					 int parse_completion,
+					 int nargs, value *argvec[],
+					 innermost_block_tracker *tracker);
+
+extern block_symbol ada_resolve_variable (struct symbol *sym,
+					  const struct block *block,
+					  struct type *context_type,
+					  int parse_completion,
+					  int deprocedure_p,
+					  innermost_block_tracker *tracker);
+
 #endif
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 152/203] Introduce ada_binop_addsub_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (150 preceding siblings ...)
  2021-01-01 21:46 ` [PATCH 151/203] Split out some Ada type resolution code Tom Tromey
@ 2021-01-01 21:46 ` Tom Tromey
  2021-01-01 21:46 ` [PATCH 153/203] Implement Ada multiplicative operators Tom Tromey
                   ` (51 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:46 UTC (permalink / raw)
  To: gdb-patches

This adds class ada_binop_addsub_operation, which implements the Ada +
and - operators.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* ada-lang.c (ada_binop_addsub_operation::evaluate): New method.
	* ada-exp.h (class ada_binop_addsub_operation): New.
---
 gdb/ChangeLog  |  5 +++++
 gdb/ada-exp.h  | 16 ++++++++++++++++
 gdb/ada-lang.c | 37 +++++++++++++++++++++++++++++++++++++
 3 files changed, 58 insertions(+)

diff --git a/gdb/ada-exp.h b/gdb/ada-exp.h
index de69210bd2a..ad69d939489 100644
--- a/gdb/ada-exp.h
+++ b/gdb/ada-exp.h
@@ -134,6 +134,22 @@ class ada_unop_range_operation
   { return UNOP_IN_RANGE; }
 };
 
+/* The Ada + and - operators.  */
+class ada_binop_addsub_operation
+  : public tuple_holding_operation<enum exp_opcode, operation_up, operation_up>
+{
+public:
+
+  using tuple_holding_operation::tuple_holding_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override;
+
+  enum exp_opcode opcode () const override
+  { return std::get<0> (m_storage); }
+};
+
 } /* namespace expr */
 
 #endif /* ADA_EXP_H */
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 50b82e6bcf9..0c36ec4cd2e 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -10637,6 +10637,43 @@ ada_ternop_range_operation::evaluate (struct type *expect_type,
   return eval_ternop_in_range (expect_type, exp, noside, arg0, arg1, arg2);
 }
 
+value *
+ada_binop_addsub_operation::evaluate (struct type *expect_type,
+				      struct expression *exp,
+				      enum noside noside)
+{
+  value *arg1 = std::get<1> (m_storage)->evaluate_with_coercion (exp, noside);
+  value *arg2 = std::get<2> (m_storage)->evaluate_with_coercion (exp, noside);
+
+  auto do_op = [=] (LONGEST x, LONGEST y)
+    {
+      if (std::get<0> (m_storage) == BINOP_ADD)
+	return x + y;
+      return x - y;
+    };
+
+  if (value_type (arg1)->code () == TYPE_CODE_PTR)
+    return (value_from_longest
+	    (value_type (arg1),
+	     do_op (value_as_long (arg1), value_as_long (arg2))));
+  if (value_type (arg2)->code () == TYPE_CODE_PTR)
+    return (value_from_longest
+	    (value_type (arg2),
+	     do_op (value_as_long (arg1), value_as_long (arg2))));
+  if ((ada_is_gnat_encoded_fixed_point_type (value_type (arg1))
+       || ada_is_gnat_encoded_fixed_point_type (value_type (arg2)))
+      && value_type (arg1) != value_type (arg2))
+    error (_("Operands of fixed-point operation must have the same type"));
+  /* Do the work, and cast the result to the type of the first
+     argument.  We cannot cast the result to a reference type, so if
+     ARG1 is a reference type, find its underlying type.  */
+  struct type *type = value_type (arg1);
+  while (type->code () == TYPE_CODE_REF)
+    type = TYPE_TARGET_TYPE (type);
+  binop_promote (exp->language_defn, exp->gdbarch, &arg1, &arg2);
+  return value_cast (type, value_binop (arg1, arg2, std::get<0> (m_storage)));
+}
+
 }
 
 /* Implement the evaluate_exp routine in the exp_descriptor structure
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 153/203] Implement Ada multiplicative operators
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (151 preceding siblings ...)
  2021-01-01 21:46 ` [PATCH 152/203] Introduce ada_binop_addsub_operation Tom Tromey
@ 2021-01-01 21:46 ` Tom Tromey
  2021-01-01 21:46 ` [PATCH 154/203] Implement Ada equality operators Tom Tromey
                   ` (50 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:46 UTC (permalink / raw)
  To: gdb-patches

This implements the Ada multiplicative operators, using an existing
template class.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* ada-lang.c (ada_mult_binop): No longer static.
	* ada-exp.h (ada_binop_mul_operation ada_binop_div_operation)
	(ada_binop_rem_operation, ada_binop_mod_operation): New typedefs.
---
 gdb/ChangeLog  | 6 ++++++
 gdb/ada-exp.h  | 9 +++++++++
 gdb/ada-lang.c | 2 +-
 3 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/gdb/ada-exp.h b/gdb/ada-exp.h
index ad69d939489..da52d5cb299 100644
--- a/gdb/ada-exp.h
+++ b/gdb/ada-exp.h
@@ -42,6 +42,10 @@ extern struct value *ada_unop_in_range (struct type *expect_type,
 					struct expression *exp,
 					enum noside noside, enum exp_opcode op,
 					struct value *arg1, struct type *type);
+extern struct value *ada_mult_binop (struct type *expect_type,
+				     struct expression *exp,
+				     enum noside noside, enum exp_opcode op,
+				     struct value *arg1, struct value *arg2);
 
 namespace expr
 {
@@ -150,6 +154,11 @@ class ada_binop_addsub_operation
   { return std::get<0> (m_storage); }
 };
 
+using ada_binop_mul_operation = binop_operation<BINOP_MUL, ada_mult_binop>;
+using ada_binop_div_operation = binop_operation<BINOP_DIV, ada_mult_binop>;
+using ada_binop_rem_operation = binop_operation<BINOP_REM, ada_mult_binop>;
+using ada_binop_mod_operation = binop_operation<BINOP_MOD, ada_mult_binop>;
+
 } /* namespace expr */
 
 #endif /* ADA_EXP_H */
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 0c36ec4cd2e..6b18282ed82 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -10254,7 +10254,7 @@ ada_abs (struct type *expect_type,
 
 /* A helper function for BINOP_MUL.  */
 
-static value *
+value *
 ada_mult_binop (struct type *expect_type,
 		struct expression *exp,
 		enum noside noside, enum exp_opcode op,
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 154/203] Implement Ada equality operators
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (152 preceding siblings ...)
  2021-01-01 21:46 ` [PATCH 153/203] Implement Ada multiplicative operators Tom Tromey
@ 2021-01-01 21:46 ` Tom Tromey
  2021-01-01 21:46 ` [PATCH 155/203] Introduce ada_bitwise_operation Tom Tromey
                   ` (49 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:46 UTC (permalink / raw)
  To: gdb-patches

This implements the Ada equal and not-equal operators.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* ada-lang.c (ada_equal_binop): No longer static.
	* ada-exp.h (class ada_binop_equal_operation): New.
---
 gdb/ChangeLog  |  5 +++++
 gdb/ada-exp.h  | 27 +++++++++++++++++++++++++++
 gdb/ada-lang.c |  2 +-
 3 files changed, 33 insertions(+), 1 deletion(-)

diff --git a/gdb/ada-exp.h b/gdb/ada-exp.h
index da52d5cb299..3091323c89e 100644
--- a/gdb/ada-exp.h
+++ b/gdb/ada-exp.h
@@ -46,6 +46,10 @@ extern struct value *ada_mult_binop (struct type *expect_type,
 				     struct expression *exp,
 				     enum noside noside, enum exp_opcode op,
 				     struct value *arg1, struct value *arg2);
+extern struct value *ada_equal_binop (struct type *expect_type,
+				      struct expression *exp,
+				      enum noside noside, enum exp_opcode op,
+				      struct value *arg1, struct value *arg2);
 
 namespace expr
 {
@@ -159,6 +163,29 @@ using ada_binop_div_operation = binop_operation<BINOP_DIV, ada_mult_binop>;
 using ada_binop_rem_operation = binop_operation<BINOP_REM, ada_mult_binop>;
 using ada_binop_mod_operation = binop_operation<BINOP_MOD, ada_mult_binop>;
 
+/* Implement the equal and not-equal operations for Ada.  */
+class ada_binop_equal_operation
+  : public tuple_holding_operation<enum exp_opcode, operation_up, operation_up>
+{
+public:
+
+  using tuple_holding_operation::tuple_holding_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override
+  {
+    value *arg1 = std::get<1> (m_storage)->evaluate (nullptr, exp, noside);
+    value *arg2 = std::get<2> (m_storage)->evaluate (value_type (arg1),
+						     exp, noside);
+    return ada_equal_binop (expect_type, exp, noside, std::get<0> (m_storage),
+			    arg1, arg2);
+  }
+
+  enum exp_opcode opcode () const override
+  { return std::get<0> (m_storage); }
+};
+
 } /* namespace expr */
 
 #endif /* ADA_EXP_H */
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 6b18282ed82..7ec73d4a292 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -10279,7 +10279,7 @@ ada_mult_binop (struct type *expect_type,
 
 /* A helper function for BINOP_EQUAL and BINOP_NOTEQUAL.  */
 
-static value *
+value *
 ada_equal_binop (struct type *expect_type,
 		 struct expression *exp,
 		 enum noside noside, enum exp_opcode op,
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 155/203] Introduce ada_bitwise_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (153 preceding siblings ...)
  2021-01-01 21:46 ` [PATCH 154/203] Implement Ada equality operators Tom Tromey
@ 2021-01-01 21:46 ` Tom Tromey
  2021-01-01 21:46 ` [PATCH 156/203] Introduce ada_ternop_slice Tom Tromey
                   ` (48 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:46 UTC (permalink / raw)
  To: gdb-patches

This adds class ada_bitwise_operation, which is used to implement the
Ada bitwise operators.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* ada-exp.h (ada_bitwise_operation): New template class.
	(ada_bitwise_and_operation, ada_bitwise_ior_operation)
	(ada_bitwise_xor_operation): New typedefs.
---
 gdb/ChangeLog |  6 ++++++
 gdb/ada-exp.h | 27 +++++++++++++++++++++++++++
 2 files changed, 33 insertions(+)

diff --git a/gdb/ada-exp.h b/gdb/ada-exp.h
index 3091323c89e..d8f18b9c61f 100644
--- a/gdb/ada-exp.h
+++ b/gdb/ada-exp.h
@@ -186,6 +186,33 @@ class ada_binop_equal_operation
   { return std::get<0> (m_storage); }
 };
 
+/* Bitwise operators for Ada.  */
+template<enum exp_opcode OP>
+class ada_bitwise_operation
+  : public maybe_constant_operation<operation_up, operation_up>
+{
+public:
+
+  using maybe_constant_operation::maybe_constant_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override
+  {
+    value *lhs = std::get<0> (m_storage)->evaluate (nullptr, exp, noside);
+    value *rhs = std::get<1> (m_storage)->evaluate (nullptr, exp, noside);
+    value *result = eval_op_binary (expect_type, exp, noside, OP, lhs, rhs);
+    return value_cast (value_type (lhs), result);
+  }
+
+  enum exp_opcode opcode () const override
+  { return OP; }
+};
+
+using ada_bitwise_and_operation = ada_bitwise_operation<BINOP_BITWISE_AND>;
+using ada_bitwise_ior_operation = ada_bitwise_operation<BINOP_BITWISE_IOR>;
+using ada_bitwise_xor_operation = ada_bitwise_operation<BINOP_BITWISE_XOR>;
+
 } /* namespace expr */
 
 #endif /* ADA_EXP_H */
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 156/203] Introduce ada_ternop_slice
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (154 preceding siblings ...)
  2021-01-01 21:46 ` [PATCH 155/203] Introduce ada_bitwise_operation Tom Tromey
@ 2021-01-01 21:46 ` Tom Tromey
  2021-01-01 21:46 ` [PATCH 157/203] Introduce ada_binop_in_bounds Tom Tromey
                   ` (47 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:46 UTC (permalink / raw)
  To: gdb-patches

This adds class ada_ternop_slice, which implements TERNOP_SLICE for
Ada.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* ada-lang.c (ada_ternop_slice): No longer static.
	* ada-exp.h (class ada_ternop_slice_operation): New.
---
 gdb/ChangeLog  |  5 +++++
 gdb/ada-exp.h  | 27 +++++++++++++++++++++++++++
 gdb/ada-lang.c |  2 +-
 3 files changed, 33 insertions(+), 1 deletion(-)

diff --git a/gdb/ada-exp.h b/gdb/ada-exp.h
index d8f18b9c61f..96e3c407b6f 100644
--- a/gdb/ada-exp.h
+++ b/gdb/ada-exp.h
@@ -50,6 +50,11 @@ extern struct value *ada_equal_binop (struct type *expect_type,
 				      struct expression *exp,
 				      enum noside noside, enum exp_opcode op,
 				      struct value *arg1, struct value *arg2);
+extern struct value *ada_ternop_slice (struct expression *exp,
+				       enum noside noside,
+				       struct value *array,
+				       struct value *low_bound_val,
+				       struct value *high_bound_val);
 
 namespace expr
 {
@@ -213,6 +218,28 @@ using ada_bitwise_and_operation = ada_bitwise_operation<BINOP_BITWISE_AND>;
 using ada_bitwise_ior_operation = ada_bitwise_operation<BINOP_BITWISE_IOR>;
 using ada_bitwise_xor_operation = ada_bitwise_operation<BINOP_BITWISE_XOR>;
 
+/* Ada array- or string-slice operation.  */
+class ada_ternop_slice_operation
+  : public maybe_constant_operation<operation_up, operation_up, operation_up>
+{
+public:
+
+  using maybe_constant_operation::maybe_constant_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override
+  {
+    value *array = std::get<0> (m_storage)->evaluate (nullptr, exp, noside);
+    value *low = std::get<1> (m_storage)->evaluate (nullptr, exp, noside);
+    value *high = std::get<2> (m_storage)->evaluate (nullptr, exp, noside);
+    return ada_ternop_slice (exp, noside, array, low, high);
+  }
+
+  enum exp_opcode opcode () const override
+  { return TERNOP_SLICE; }
+};
+
 } /* namespace expr */
 
 #endif /* ADA_EXP_H */
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 7ec73d4a292..00912a4136d 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -10301,7 +10301,7 @@ ada_equal_binop (struct type *expect_type,
 
 /* A helper function for TERNOP_SLICE.  */
 
-static value *
+value *
 ada_ternop_slice (struct expression *exp,
 		  enum noside noside,
 		  struct value *array, struct value *low_bound_val,
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 157/203] Introduce ada_binop_in_bounds
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (155 preceding siblings ...)
  2021-01-01 21:46 ` [PATCH 156/203] Introduce ada_ternop_slice Tom Tromey
@ 2021-01-01 21:46 ` Tom Tromey
  2021-01-01 21:46 ` [PATCH 158/203] Implement some Ada OP_ATR_ operations Tom Tromey
                   ` (46 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:46 UTC (permalink / raw)
  To: gdb-patches

This adds class ada_binop_in_bounds, which implements BINOP_IN_BOUNDS.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* ada-lang.c (ada_binop_in_bounds): No longer static.
	* ada-exp.h (class ada_binop_in_bounds_operation): New.
---
 gdb/ChangeLog  |  5 +++++
 gdb/ada-exp.h  | 27 +++++++++++++++++++++++++++
 gdb/ada-lang.c |  2 +-
 3 files changed, 33 insertions(+), 1 deletion(-)

diff --git a/gdb/ada-exp.h b/gdb/ada-exp.h
index 96e3c407b6f..4c30734171f 100644
--- a/gdb/ada-exp.h
+++ b/gdb/ada-exp.h
@@ -55,6 +55,11 @@ extern struct value *ada_ternop_slice (struct expression *exp,
 				       struct value *array,
 				       struct value *low_bound_val,
 				       struct value *high_bound_val);
+extern struct value *ada_binop_in_bounds (struct expression *exp,
+					  enum noside noside,
+					  struct value *arg1,
+					  struct value *arg2,
+					  int n);
 
 namespace expr
 {
@@ -240,6 +245,28 @@ class ada_ternop_slice_operation
   { return TERNOP_SLICE; }
 };
 
+/* Implement BINOP_IN_BOUNDS for Ada.  */
+class ada_binop_in_bounds_operation
+  : public maybe_constant_operation<operation_up, operation_up, int>
+{
+public:
+
+  using maybe_constant_operation::maybe_constant_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override
+  {
+    value *arg1 = std::get<0> (m_storage)->evaluate (nullptr, exp, noside);
+    value *arg2 = std::get<1> (m_storage)->evaluate (nullptr, exp, noside);
+    return ada_binop_in_bounds (exp, noside, arg1, arg2,
+				std::get<2> (m_storage));
+  }
+
+  enum exp_opcode opcode () const override
+  { return BINOP_IN_BOUNDS; }
+};
+
 } /* namespace expr */
 
 #endif /* ADA_EXP_H */
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 00912a4136d..8ed4949238c 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -10382,7 +10382,7 @@ ada_ternop_slice (struct expression *exp,
 
 /* A helper function for BINOP_IN_BOUNDS.  */
 
-static value *
+value *
 ada_binop_in_bounds (struct expression *exp, enum noside noside,
 		     struct value *arg1, struct value *arg2, int n)
 {
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 158/203] Implement some Ada OP_ATR_ operations
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (156 preceding siblings ...)
  2021-01-01 21:46 ` [PATCH 157/203] Introduce ada_binop_in_bounds Tom Tromey
@ 2021-01-01 21:46 ` Tom Tromey
  2021-01-01 21:46 ` [PATCH 159/203] Introduce ada_var_value_operation Tom Tromey
                   ` (45 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:46 UTC (permalink / raw)
  To: gdb-patches

This implements a few Ada OP_ATR_ operations.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* ada-lang.c (ada_unop_atr_operation::evaluate): New method.
	* ada-exp.h (class ada_unop_atr_operation): New.
---
 gdb/ChangeLog  |  5 +++++
 gdb/ada-exp.h  | 16 ++++++++++++++++
 gdb/ada-lang.c | 21 +++++++++++++++++++++
 3 files changed, 42 insertions(+)

diff --git a/gdb/ada-exp.h b/gdb/ada-exp.h
index 4c30734171f..e92ae469b63 100644
--- a/gdb/ada-exp.h
+++ b/gdb/ada-exp.h
@@ -267,6 +267,22 @@ class ada_binop_in_bounds_operation
   { return BINOP_IN_BOUNDS; }
 };
 
+/* Implement several unary Ada OP_ATR_* operations.  */
+class ada_unop_atr_operation
+  : public maybe_constant_operation<operation_up, enum exp_opcode, int>
+{
+public:
+
+  using maybe_constant_operation::maybe_constant_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override;
+
+  enum exp_opcode opcode () const override
+  { return std::get<1> (m_storage); }
+};
+
 } /* namespace expr */
 
 #endif /* ADA_EXP_H */
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 8ed4949238c..9887590a782 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -10674,6 +10674,27 @@ ada_binop_addsub_operation::evaluate (struct type *expect_type,
   return value_cast (type, value_binop (arg1, arg2, std::get<0> (m_storage)));
 }
 
+value *
+ada_unop_atr_operation::evaluate (struct type *expect_type,
+				  struct expression *exp,
+				  enum noside noside)
+{
+  struct type *type_arg = nullptr;
+  value *val = nullptr;
+
+  if (std::get<0> (m_storage)->opcode () == OP_TYPE)
+    {
+      value *tem = std::get<0> (m_storage)->evaluate (nullptr, exp,
+						      EVAL_AVOID_SIDE_EFFECTS);
+      type_arg = value_type (tem);
+    }
+  else
+    val = std::get<0> (m_storage)->evaluate (nullptr, exp, noside);
+
+  return ada_unop_atr (exp, noside, std::get<1> (m_storage),
+		       val, type_arg, std::get<2> (m_storage));
+}
+
 }
 
 /* Implement the evaluate_exp routine in the exp_descriptor structure
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 159/203] Introduce ada_var_value_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (157 preceding siblings ...)
  2021-01-01 21:46 ` [PATCH 158/203] Implement some Ada OP_ATR_ operations Tom Tromey
@ 2021-01-01 21:46 ` Tom Tromey
  2021-01-01 21:46 ` [PATCH 160/203] Introduce ada_var_msym_value_operation Tom Tromey
                   ` (44 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:46 UTC (permalink / raw)
  To: gdb-patches

This adds class ada_var_value_operation, which implements OP_VAR_VALUE
for Ada.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* ada-lang.c (ada_var_value_operation::evaluate_for_cast)
	(ada_var_value_operation::evaluate): New methods.
	* ada-exp.h (class ada_var_value_operation): New.
---
 gdb/ChangeLog  |   6 +++
 gdb/ada-exp.h  |  21 ++++++++++
 gdb/ada-lang.c | 112 +++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 139 insertions(+)

diff --git a/gdb/ada-exp.h b/gdb/ada-exp.h
index e92ae469b63..0f2f62f5978 100644
--- a/gdb/ada-exp.h
+++ b/gdb/ada-exp.h
@@ -283,6 +283,27 @@ class ada_unop_atr_operation
   { return std::get<1> (m_storage); }
 };
 
+/* Variant of var_value_operation for Ada.  */
+class ada_var_value_operation
+  : public var_value_operation
+{
+public:
+
+  using var_value_operation::var_value_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override;
+
+  value *evaluate_for_cast (struct type *expect_type,
+			    struct expression *exp,
+			    enum noside noside) override;
+
+protected:
+
+  using operation::do_generate_ax;
+};
+
 } /* namespace expr */
 
 #endif /* ADA_EXP_H */
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 9887590a782..bdd574d033c 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -10695,6 +10695,118 @@ ada_unop_atr_operation::evaluate (struct type *expect_type,
 		       val, type_arg, std::get<2> (m_storage));
 }
 
+value *
+ada_var_value_operation::evaluate_for_cast (struct type *expect_type,
+					    struct expression *exp,
+					    enum noside noside)
+{
+  value *val = evaluate_var_value (noside,
+				   std::get<1> (m_storage),
+				   std::get<0> (m_storage));
+
+  val = ada_value_cast (expect_type, val);
+
+  /* Follow the Ada language semantics that do not allow taking
+     an address of the result of a cast (view conversion in Ada).  */
+  if (VALUE_LVAL (val) == lval_memory)
+    {
+      if (value_lazy (val))
+	value_fetch_lazy (val);
+      VALUE_LVAL (val) = not_lval;
+    }
+  return val;
+}
+
+value *
+ada_var_value_operation::evaluate (struct type *expect_type,
+				   struct expression *exp,
+				   enum noside noside)
+{
+  symbol *sym = std::get<0> (m_storage);
+
+  if (SYMBOL_DOMAIN (sym) == UNDEF_DOMAIN)
+    /* Only encountered when an unresolved symbol occurs in a
+       context other than a function call, in which case, it is
+       invalid.  */
+    error (_("Unexpected unresolved symbol, %s, during evaluation"),
+	   sym->print_name ());
+
+  if (noside == EVAL_AVOID_SIDE_EFFECTS)
+    {
+      struct type *type = static_unwrap_type (SYMBOL_TYPE (sym));
+      /* Check to see if this is a tagged type.  We also need to handle
+	 the case where the type is a reference to a tagged type, but
+	 we have to be careful to exclude pointers to tagged types.
+	 The latter should be shown as usual (as a pointer), whereas
+	 a reference should mostly be transparent to the user.  */
+      if (ada_is_tagged_type (type, 0)
+	  || (type->code () == TYPE_CODE_REF
+	      && ada_is_tagged_type (TYPE_TARGET_TYPE (type), 0)))
+	{
+	  /* Tagged types are a little special in the fact that the real
+	     type is dynamic and can only be determined by inspecting the
+	     object's tag.  This means that we need to get the object's
+	     value first (EVAL_NORMAL) and then extract the actual object
+	     type from its tag.
+
+	     Note that we cannot skip the final step where we extract
+	     the object type from its tag, because the EVAL_NORMAL phase
+	     results in dynamic components being resolved into fixed ones.
+	     This can cause problems when trying to print the type
+	     description of tagged types whose parent has a dynamic size:
+	     We use the type name of the "_parent" component in order
+	     to print the name of the ancestor type in the type description.
+	     If that component had a dynamic size, the resolution into
+	     a fixed type would result in the loss of that type name,
+	     thus preventing us from printing the name of the ancestor
+	     type in the type description.  */
+	  value *arg1 = var_value_operation::evaluate (nullptr, exp,
+						       EVAL_NORMAL);
+
+	  if (type->code () != TYPE_CODE_REF)
+	    {
+	      struct type *actual_type;
+
+	      actual_type = type_from_tag (ada_value_tag (arg1));
+	      if (actual_type == NULL)
+		/* If, for some reason, we were unable to determine
+		   the actual type from the tag, then use the static
+		   approximation that we just computed as a fallback.
+		   This can happen if the debugging information is
+		   incomplete, for instance.  */
+		actual_type = type;
+	      return value_zero (actual_type, not_lval);
+	    }
+	  else
+	    {
+	      /* In the case of a ref, ada_coerce_ref takes care
+		 of determining the actual type.  But the evaluation
+		 should return a ref as it should be valid to ask
+		 for its address; so rebuild a ref after coerce.  */
+	      arg1 = ada_coerce_ref (arg1);
+	      return value_ref (arg1, TYPE_CODE_REF);
+	    }
+	}
+
+      /* Records and unions for which GNAT encodings have been
+	 generated need to be statically fixed as well.
+	 Otherwise, non-static fixing produces a type where
+	 all dynamic properties are removed, which prevents "ptype"
+	 from being able to completely describe the type.
+	 For instance, a case statement in a variant record would be
+	 replaced by the relevant components based on the actual
+	 value of the discriminants.  */
+      if ((type->code () == TYPE_CODE_STRUCT
+	   && dynamic_template_type (type) != NULL)
+	  || (type->code () == TYPE_CODE_UNION
+	      && ada_find_parallel_type (type, "___XVU") != NULL))
+	return value_zero (to_static_fixed_type (type), not_lval);
+    }
+
+  value *arg1 = var_value_operation::evaluate (expect_type, exp, noside);
+  return ada_to_fixed_value (arg1);
+}
+
 }
 
 /* Implement the evaluate_exp routine in the exp_descriptor structure
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 160/203] Introduce ada_var_msym_value_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (158 preceding siblings ...)
  2021-01-01 21:46 ` [PATCH 159/203] Introduce ada_var_value_operation Tom Tromey
@ 2021-01-01 21:46 ` Tom Tromey
  2021-01-01 21:46 ` [PATCH 161/203] Implement Ada min and max operations Tom Tromey
                   ` (43 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:46 UTC (permalink / raw)
  To: gdb-patches

This adds class ada_var_msym_value_operation, which implements
OP_VAR_MSYM_VALUE for Ada.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* ada-lang.c (ada_var_msym_value_operation::evaluate_for_cast):
	New method.
	* ada-exp.h (class ada_var_msym_value_operation): New.
---
 gdb/ChangeLog  |  6 ++++++
 gdb/ada-exp.h  | 17 +++++++++++++++++
 gdb/ada-lang.c | 25 +++++++++++++++++++++++++
 3 files changed, 48 insertions(+)

diff --git a/gdb/ada-exp.h b/gdb/ada-exp.h
index 0f2f62f5978..0fe6ecf7e93 100644
--- a/gdb/ada-exp.h
+++ b/gdb/ada-exp.h
@@ -304,6 +304,23 @@ class ada_var_value_operation
   using operation::do_generate_ax;
 };
 
+/* Variant of var_msym_value_operation for Ada.  */
+class ada_var_msym_value_operation
+  : public var_msym_value_operation
+{
+public:
+
+  using var_msym_value_operation::var_msym_value_operation;
+
+  value *evaluate_for_cast (struct type *expect_type,
+			    struct expression *exp,
+			    enum noside noside) override;
+
+protected:
+
+  using operation::do_generate_ax;
+};
+
 } /* namespace expr */
 
 #endif /* ADA_EXP_H */
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index bdd574d033c..3560eee307a 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -10695,6 +10695,31 @@ ada_unop_atr_operation::evaluate (struct type *expect_type,
 		       val, type_arg, std::get<2> (m_storage));
 }
 
+value *
+ada_var_msym_value_operation::evaluate_for_cast (struct type *expect_type,
+						 struct expression *exp,
+						 enum noside noside)
+{
+  if (noside == EVAL_AVOID_SIDE_EFFECTS)
+    return value_zero (expect_type, not_lval);
+
+  value *val = evaluate_var_msym_value (noside,
+					std::get<1> (m_storage),
+					std::get<0> (m_storage));
+
+  val = ada_value_cast (expect_type, val);
+
+  /* Follow the Ada language semantics that do not allow taking
+     an address of the result of a cast (view conversion in Ada).  */
+  if (VALUE_LVAL (val) == lval_memory)
+    {
+      if (value_lazy (val))
+	value_fetch_lazy (val);
+      VALUE_LVAL (val) = not_lval;
+    }
+  return val;
+}
+
 value *
 ada_var_value_operation::evaluate_for_cast (struct type *expect_type,
 					    struct expression *exp,
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 161/203] Implement Ada min and max operations
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (159 preceding siblings ...)
  2021-01-01 21:46 ` [PATCH 160/203] Introduce ada_var_msym_value_operation Tom Tromey
@ 2021-01-01 21:46 ` Tom Tromey
  2021-01-01 21:46 ` [PATCH 162/203] Refactor value_pos_atr Tom Tromey
                   ` (42 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:46 UTC (permalink / raw)
  To: gdb-patches

This implement the Ada min and max operations using an existing
template class.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* ada-lang.c (ada_binop_minmax): No longer static.
	* ada-exp.h (ada_binop_min_operation, ada_binop_max_operation):
	New typedefs.
---
 gdb/ChangeLog  | 6 ++++++
 gdb/ada-exp.h  | 8 ++++++++
 gdb/ada-lang.c | 2 +-
 3 files changed, 15 insertions(+), 1 deletion(-)

diff --git a/gdb/ada-exp.h b/gdb/ada-exp.h
index 0fe6ecf7e93..f3808935f99 100644
--- a/gdb/ada-exp.h
+++ b/gdb/ada-exp.h
@@ -60,6 +60,11 @@ extern struct value *ada_binop_in_bounds (struct expression *exp,
 					  struct value *arg1,
 					  struct value *arg2,
 					  int n);
+extern struct value *ada_binop_minmax (struct type *expect_type,
+				       struct expression *exp,
+				       enum noside noside, enum exp_opcode op,
+				       struct value *arg1,
+				       struct value *arg2);
 
 namespace expr
 {
@@ -173,6 +178,9 @@ using ada_binop_div_operation = binop_operation<BINOP_DIV, ada_mult_binop>;
 using ada_binop_rem_operation = binop_operation<BINOP_REM, ada_mult_binop>;
 using ada_binop_mod_operation = binop_operation<BINOP_MOD, ada_mult_binop>;
 
+using ada_binop_min_operation = binop_operation<OP_ATR_MIN, ada_binop_minmax>;
+using ada_binop_max_operation = binop_operation<OP_ATR_MAX, ada_binop_minmax>;
+
 /* Implement the equal and not-equal operations for Ada.  */
 class ada_binop_equal_operation
   : public tuple_holding_operation<enum exp_opcode, operation_up, operation_up>
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 3560eee307a..b3278183177 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -10539,7 +10539,7 @@ ada_unop_atr (struct expression *exp, enum noside noside, enum exp_opcode op,
 
 /* A helper function for OP_ATR_MIN and OP_ATR_MAX.  */
 
-static struct value *
+struct value *
 ada_binop_minmax (struct type *expect_type,
 		  struct expression *exp,
 		  enum noside noside, enum exp_opcode op,
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 162/203] Refactor value_pos_atr
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (160 preceding siblings ...)
  2021-01-01 21:46 ` [PATCH 161/203] Implement Ada min and max operations Tom Tromey
@ 2021-01-01 21:46 ` Tom Tromey
  2021-01-01 21:46 ` [PATCH 163/203] Introduce ada_pos_operation Tom Tromey
                   ` (41 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:46 UTC (permalink / raw)
  To: gdb-patches

This refactors value_pos_atr to be directly usable by a new operation
implementation.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* ada-lang.c (ada_pos_atr): Rename from value_pos_atr.  Change
	parameters.
	(ada_evaluate_subexp): Use it.
---
 gdb/ChangeLog  |  6 ++++++
 gdb/ada-lang.c | 16 ++++++++--------
 2 files changed, 14 insertions(+), 8 deletions(-)

diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index b3278183177..4a83e9f57a5 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -191,8 +191,6 @@ static struct value *ada_coerce_ref (struct value *);
 
 static LONGEST pos_atr (struct value *);
 
-static struct value *value_pos_atr (struct type *, struct value *);
-
 static struct value *val_atr (struct type *, LONGEST);
 
 static struct symbol *standard_lookup (const char *, const struct block *,
@@ -8963,8 +8961,14 @@ pos_atr (struct value *arg)
 }
 
 static struct value *
-value_pos_atr (struct type *type, struct value *arg)
+ada_pos_atr (struct type *expect_type,
+	     struct expression *exp,
+	     enum noside noside, enum exp_opcode op,
+	     struct value *arg)
 {
+  struct type *type = builtin_type (exp->gdbarch)->builtin_int;
+  if (noside == EVAL_AVOID_SIDE_EFFECTS)
+    return value_zero (type, not_lval);
   return value_from_longest (type, pos_atr (arg));
 }
 
@@ -11373,11 +11377,7 @@ ada_evaluate_subexp (struct type *expect_type, struct expression *exp,
       arg1 = evaluate_subexp (nullptr, exp, pos, noside);
       if (noside == EVAL_SKIP)
 	goto nosideret;
-      type = builtin_type (exp->gdbarch)->builtin_int;
-      if (noside == EVAL_AVOID_SIDE_EFFECTS)
-	return value_zero (type, not_lval);
-      else
-	return value_pos_atr (type, arg1);
+      return ada_pos_atr (expect_type, exp, noside, op, arg1);
 
     case OP_ATR_SIZE:
       arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 163/203] Introduce ada_pos_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (161 preceding siblings ...)
  2021-01-01 21:46 ` [PATCH 162/203] Refactor value_pos_atr Tom Tromey
@ 2021-01-01 21:46 ` Tom Tromey
  2021-01-01 21:46 ` [PATCH 164/203] Introduce ada_atr_val_operation Tom Tromey
                   ` (40 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:46 UTC (permalink / raw)
  To: gdb-patches

This adds class ada_pos_operation, a new typedef that implements
OP_ATR_POS.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* ada-lang.c (ada_pos_atr): No longer static.
	* ada-exp.h (ada_pos_operation): New typedef.
---
 gdb/ChangeLog  | 5 +++++
 gdb/ada-exp.h  | 5 +++++
 gdb/ada-lang.c | 2 +-
 3 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/gdb/ada-exp.h b/gdb/ada-exp.h
index f3808935f99..07744c1c8ea 100644
--- a/gdb/ada-exp.h
+++ b/gdb/ada-exp.h
@@ -65,6 +65,10 @@ extern struct value *ada_binop_minmax (struct type *expect_type,
 				       enum noside noside, enum exp_opcode op,
 				       struct value *arg1,
 				       struct value *arg2);
+extern struct value *ada_pos_atr (struct type *expect_type,
+				  struct expression *exp,
+				  enum noside noside, enum exp_opcode op,
+				  struct value *arg);
 
 namespace expr
 {
@@ -135,6 +139,7 @@ using ada_neg_operation = unop_operation<UNOP_NEG, ada_unop_neg>;
 using ada_atr_tag_operation = unop_operation<OP_ATR_TAG, ada_atr_tag>;
 using ada_atr_size_operation = unop_operation<OP_ATR_SIZE, ada_atr_size>;
 using ada_abs_operation = unop_operation<UNOP_ABS, ada_abs>;
+using ada_pos_operation = unop_operation<OP_ATR_POS, ada_pos_atr>;
 
 /* The in-range operation, given a type.  */
 class ada_unop_range_operation
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 4a83e9f57a5..2f7eb354e4d 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -8960,7 +8960,7 @@ pos_atr (struct value *arg)
   return *result;
 }
 
-static struct value *
+struct value *
 ada_pos_atr (struct type *expect_type,
 	     struct expression *exp,
 	     enum noside noside, enum exp_opcode op,
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 164/203] Introduce ada_atr_val_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (162 preceding siblings ...)
  2021-01-01 21:46 ` [PATCH 163/203] Introduce ada_pos_operation Tom Tromey
@ 2021-01-01 21:46 ` Tom Tromey
  2021-01-01 21:46 ` [PATCH 165/203] Introduce ada_binop_exp_operation Tom Tromey
                   ` (39 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:46 UTC (permalink / raw)
  To: gdb-patches

This adds class ada_atr_val_operation, which implements OP_ATR_VAL.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* ada-lang.c (ada_val_atr): No longer static.
	(ada_atr_val_operation::evaluate): New method.
	* ada-exp.h (class ada_atr_val_operation): New.
---
 gdb/ChangeLog  |  6 ++++++
 gdb/ada-exp.h  | 19 +++++++++++++++++++
 gdb/ada-lang.c | 11 ++++++++++-
 3 files changed, 35 insertions(+), 1 deletion(-)

diff --git a/gdb/ada-exp.h b/gdb/ada-exp.h
index 07744c1c8ea..c86b0548947 100644
--- a/gdb/ada-exp.h
+++ b/gdb/ada-exp.h
@@ -69,6 +69,9 @@ extern struct value *ada_pos_atr (struct type *expect_type,
 				  struct expression *exp,
 				  enum noside noside, enum exp_opcode op,
 				  struct value *arg);
+extern struct value *ada_val_atr (enum noside noside, struct type *type,
+				  struct value *arg);
+
 
 namespace expr
 {
@@ -334,6 +337,22 @@ class ada_var_msym_value_operation
   using operation::do_generate_ax;
 };
 
+/* Implement the Ada 'val attribute.  */
+class ada_atr_val_operation
+  : public tuple_holding_operation<struct type *, operation_up>
+{
+public:
+
+  using tuple_holding_operation::tuple_holding_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override;
+
+  enum exp_opcode opcode () const override
+  { return OP_ATR_VAL; }
+};
+
 } /* namespace expr */
 
 #endif /* ADA_EXP_H */
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 2f7eb354e4d..eb34121bf17 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -8989,7 +8989,7 @@ val_atr (struct type *type, LONGEST val)
   return value_from_longest (type, val);
 }
 
-static struct value *
+struct value *
 ada_val_atr (enum noside noside, struct type *type, struct value *arg)
 {
   if (noside == EVAL_AVOID_SIDE_EFFECTS)
@@ -10836,6 +10836,15 @@ ada_var_value_operation::evaluate (struct type *expect_type,
   return ada_to_fixed_value (arg1);
 }
 
+value *
+ada_atr_val_operation::evaluate (struct type *expect_type,
+				 struct expression *exp,
+				 enum noside noside)
+{
+  value *arg = std::get<1> (m_storage)->evaluate (nullptr, exp, noside);
+  return ada_val_atr (noside, std::get<0> (m_storage), arg);
+}
+
 }
 
 /* Implement the evaluate_exp routine in the exp_descriptor structure
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 165/203] Introduce ada_binop_exp_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (163 preceding siblings ...)
  2021-01-01 21:46 ` [PATCH 164/203] Introduce ada_atr_val_operation Tom Tromey
@ 2021-01-01 21:46 ` Tom Tromey
  2021-01-01 21:46 ` [PATCH 166/203] Introduce ada_unop_ind_operation Tom Tromey
                   ` (38 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:46 UTC (permalink / raw)
  To: gdb-patches

This adds class ada_binop_exp_operation, which implements BINOP_EXP
for Ada.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* ada-lang.c (ada_binop_exp): No longer static.
	* ada-exp.h (ada_binop_exp_operation): New typedef.
---
 gdb/ChangeLog  | 5 +++++
 gdb/ada-exp.h  | 7 ++++++-
 gdb/ada-lang.c | 2 +-
 3 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/gdb/ada-exp.h b/gdb/ada-exp.h
index c86b0548947..8e908464f1f 100644
--- a/gdb/ada-exp.h
+++ b/gdb/ada-exp.h
@@ -71,7 +71,10 @@ extern struct value *ada_pos_atr (struct type *expect_type,
 				  struct value *arg);
 extern struct value *ada_val_atr (enum noside noside, struct type *type,
 				  struct value *arg);
-
+extern struct value *ada_binop_exp (struct type *expect_type,
+				    struct expression *exp,
+				    enum noside noside, enum exp_opcode op,
+				    struct value *arg1, struct value *arg2);
 
 namespace expr
 {
@@ -189,6 +192,8 @@ using ada_binop_mod_operation = binop_operation<BINOP_MOD, ada_mult_binop>;
 using ada_binop_min_operation = binop_operation<OP_ATR_MIN, ada_binop_minmax>;
 using ada_binop_max_operation = binop_operation<OP_ATR_MAX, ada_binop_minmax>;
 
+using ada_binop_exp_operation = binop_operation<BINOP_EXP, ada_binop_exp>;
+
 /* Implement the equal and not-equal operations for Ada.  */
 class ada_binop_equal_operation
   : public tuple_holding_operation<enum exp_opcode, operation_up, operation_up>
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index eb34121bf17..d621e32ab75 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -10561,7 +10561,7 @@ ada_binop_minmax (struct type *expect_type,
 
 /* A helper function for BINOP_EXP.  */
 
-static struct value *
+struct value *
 ada_binop_exp (struct type *expect_type,
 	       struct expression *exp,
 	       enum noside noside, enum exp_opcode op,
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 166/203] Introduce ada_unop_ind_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (164 preceding siblings ...)
  2021-01-01 21:46 ` [PATCH 165/203] Introduce ada_binop_exp_operation Tom Tromey
@ 2021-01-01 21:46 ` Tom Tromey
  2021-01-01 21:46 ` [PATCH 167/203] Introduce ada_structop_operation Tom Tromey
                   ` (37 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:46 UTC (permalink / raw)
  To: gdb-patches

This adds class ada_unop_ind_operation, which implements UNOP_IND for
Ada.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* ada-lang.c (ada_unop_ind_operation::evaluate): New method.
	* ada-exp.h (class ada_unop_ind_operation): New.
---
 gdb/ChangeLog  |  5 +++
 gdb/ada-exp.h  | 13 ++++++++
 gdb/ada-lang.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 103 insertions(+)

diff --git a/gdb/ada-exp.h b/gdb/ada-exp.h
index 8e908464f1f..c87036e2d19 100644
--- a/gdb/ada-exp.h
+++ b/gdb/ada-exp.h
@@ -358,6 +358,19 @@ class ada_atr_val_operation
   { return OP_ATR_VAL; }
 };
 
+/* The indirection operator for Ada.  */
+class ada_unop_ind_operation
+  : public unop_ind_base_operation
+{
+public:
+
+  using unop_ind_base_operation::unop_ind_base_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override;
+};
+
 } /* namespace expr */
 
 #endif /* ADA_EXP_H */
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index d621e32ab75..6cceecc080a 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -10845,6 +10845,91 @@ ada_atr_val_operation::evaluate (struct type *expect_type,
   return ada_val_atr (noside, std::get<0> (m_storage), arg);
 }
 
+value *
+ada_unop_ind_operation::evaluate (struct type *expect_type,
+				  struct expression *exp,
+				  enum noside noside)
+{
+  value *arg1 = std::get<0> (m_storage)->evaluate (expect_type, exp, noside);
+
+  struct type *type = ada_check_typedef (value_type (arg1));
+  if (noside == EVAL_AVOID_SIDE_EFFECTS)
+    {
+      if (ada_is_array_descriptor_type (type))
+	/* GDB allows dereferencing GNAT array descriptors.  */
+	{
+	  struct type *arrType = ada_type_of_array (arg1, 0);
+
+	  if (arrType == NULL)
+	    error (_("Attempt to dereference null array pointer."));
+	  return value_at_lazy (arrType, 0);
+	}
+      else if (type->code () == TYPE_CODE_PTR
+	       || type->code () == TYPE_CODE_REF
+	       /* In C you can dereference an array to get the 1st elt.  */
+	       || type->code () == TYPE_CODE_ARRAY)
+	{
+	  /* As mentioned in the OP_VAR_VALUE case, tagged types can
+	     only be determined by inspecting the object's tag.
+	     This means that we need to evaluate completely the
+	     expression in order to get its type.  */
+
+	  if ((type->code () == TYPE_CODE_REF
+	       || type->code () == TYPE_CODE_PTR)
+	      && ada_is_tagged_type (TYPE_TARGET_TYPE (type), 0))
+	    {
+	      arg1 = std::get<0> (m_storage)->evaluate (nullptr, exp,
+							EVAL_NORMAL);
+	      type = value_type (ada_value_ind (arg1));
+	    }
+	  else
+	    {
+	      type = to_static_fixed_type
+		(ada_aligned_type
+		 (ada_check_typedef (TYPE_TARGET_TYPE (type))));
+	    }
+	  ada_ensure_varsize_limit (type);
+	  return value_zero (type, lval_memory);
+	}
+      else if (type->code () == TYPE_CODE_INT)
+	{
+	  /* GDB allows dereferencing an int.  */
+	  if (expect_type == NULL)
+	    return value_zero (builtin_type (exp->gdbarch)->builtin_int,
+			       lval_memory);
+	  else
+	    {
+	      expect_type =
+		to_static_fixed_type (ada_aligned_type (expect_type));
+	      return value_zero (expect_type, lval_memory);
+	    }
+	}
+      else
+	error (_("Attempt to take contents of a non-pointer value."));
+    }
+  arg1 = ada_coerce_ref (arg1);     /* FIXME: What is this for??  */
+  type = ada_check_typedef (value_type (arg1));
+
+  if (type->code () == TYPE_CODE_INT)
+    /* GDB allows dereferencing an int.  If we were given
+       the expect_type, then use that as the target type.
+       Otherwise, assume that the target type is an int.  */
+    {
+      if (expect_type != NULL)
+	return ada_value_ind (value_cast (lookup_pointer_type (expect_type),
+					  arg1));
+      else
+	return value_at_lazy (builtin_type (exp->gdbarch)->builtin_int,
+			      (CORE_ADDR) value_as_address (arg1));
+    }
+
+  if (ada_is_array_descriptor_type (type))
+    /* GDB allows dereferencing GNAT array descriptors.  */
+    return ada_coerce_to_simple_array (arg1);
+  else
+    return ada_value_ind (arg1);
+}
+
 }
 
 /* Implement the evaluate_exp routine in the exp_descriptor structure
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 167/203] Introduce ada_structop_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (165 preceding siblings ...)
  2021-01-01 21:46 ` [PATCH 166/203] Introduce ada_unop_ind_operation Tom Tromey
@ 2021-01-01 21:46 ` Tom Tromey
  2021-01-01 21:46 ` [PATCH 168/203] Implement function calls for Ada Tom Tromey
                   ` (36 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:46 UTC (permalink / raw)
  To: gdb-patches

This adds class ada_structop_operation, which implements
STRUCTOP_STRUCT for Ada.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* ada-lang.c (ada_structop_operation::evaluate): New method.
	* ada-exp.h (class ada_structop_operation): New.
---
 gdb/ChangeLog  |  5 +++++
 gdb/ada-exp.h  | 16 ++++++++++++++++
 gdb/ada-lang.c | 42 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 63 insertions(+)

diff --git a/gdb/ada-exp.h b/gdb/ada-exp.h
index c87036e2d19..34b9c1d166d 100644
--- a/gdb/ada-exp.h
+++ b/gdb/ada-exp.h
@@ -371,6 +371,22 @@ class ada_unop_ind_operation
 		   enum noside noside) override;
 };
 
+/* Implement STRUCTOP_STRUCT for Ada.  */
+class ada_structop_operation
+  : public structop_base_operation
+{
+public:
+
+  using structop_base_operation::structop_base_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override;
+
+  enum exp_opcode opcode () const override
+  { return STRUCTOP_STRUCT; }
+};
+
 } /* namespace expr */
 
 #endif /* ADA_EXP_H */
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 6cceecc080a..c197afe7052 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -10930,6 +10930,48 @@ ada_unop_ind_operation::evaluate (struct type *expect_type,
     return ada_value_ind (arg1);
 }
 
+value *
+ada_structop_operation::evaluate (struct type *expect_type,
+				  struct expression *exp,
+				  enum noside noside)
+{
+  value *arg1 = std::get<0> (m_storage)->evaluate (nullptr, exp, noside);
+  const char *str = std::get<1> (m_storage).c_str ();
+  if (noside == EVAL_AVOID_SIDE_EFFECTS)
+    {
+      struct type *type;
+      struct type *type1 = value_type (arg1);
+
+      if (ada_is_tagged_type (type1, 1))
+	{
+	  type = ada_lookup_struct_elt_type (type1, str, 1, 1);
+
+	  /* If the field is not found, check if it exists in the
+	     extension of this object's type. This means that we
+	     need to evaluate completely the expression.  */
+
+	  if (type == NULL)
+	    {
+	      arg1 = std::get<0> (m_storage)->evaluate (nullptr, exp,
+							EVAL_NORMAL);
+	      arg1 = ada_value_struct_elt (arg1, str, 0);
+	      arg1 = unwrap_value (arg1);
+	      type = value_type (ada_to_fixed_value (arg1));
+	    }
+	}
+      else
+	type = ada_lookup_struct_elt_type (type1, str, 1, 0);
+
+      return value_zero (ada_aligned_type (type), lval_memory);
+    }
+  else
+    {
+      arg1 = ada_value_struct_elt (arg1, str, 0);
+      arg1 = unwrap_value (arg1);
+      return ada_to_fixed_value (arg1);
+    }
+}
+
 }
 
 /* Implement the evaluate_exp routine in the exp_descriptor structure
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 168/203] Implement function calls for Ada
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (166 preceding siblings ...)
  2021-01-01 21:46 ` [PATCH 167/203] Introduce ada_structop_operation Tom Tromey
@ 2021-01-01 21:46 ` Tom Tromey
  2021-01-01 21:46 ` [PATCH 169/203] Implement Ada resolution Tom Tromey
                   ` (35 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:46 UTC (permalink / raw)
  To: gdb-patches

This implements function calls for Ada.  This takes a different
approach than that used for other languages, primarily because Ada
requires special treatment generally.  The "ordinary" special case for
just the callee didn't really apply neatly here; there's only one case
in Ada needing special callee treatment.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* ada-lang.c (ada_funcall_operation::evaluate): New method.
	* ada-exp.h (class ada_var_msym_value_operation) <get_symbol>: New
	method.
	(class ada_funcall_operation): New.
---
 gdb/ChangeLog  |   7 +++
 gdb/ada-exp.h  |  19 +++++++
 gdb/ada-lang.c | 142 +++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 168 insertions(+)

diff --git a/gdb/ada-exp.h b/gdb/ada-exp.h
index 34b9c1d166d..287ed5cc62c 100644
--- a/gdb/ada-exp.h
+++ b/gdb/ada-exp.h
@@ -320,6 +320,9 @@ class ada_var_value_operation
 			    struct expression *exp,
 			    enum noside noside) override;
 
+  symbol *get_symbol () const
+  { return std::get<0> (m_storage); }
+
 protected:
 
   using operation::do_generate_ax;
@@ -387,6 +390,22 @@ class ada_structop_operation
   { return STRUCTOP_STRUCT; }
 };
 
+/* Function calls for Ada.  */
+class ada_funcall_operation
+  : public tuple_holding_operation<operation_up, std::vector<operation_up>>
+{
+public:
+
+  using tuple_holding_operation::tuple_holding_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override;
+
+  enum exp_opcode opcode () const override
+  { return OP_FUNCALL; }
+};
+
 } /* namespace expr */
 
 #endif /* ADA_EXP_H */
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index c197afe7052..18f250b5a34 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -10972,6 +10972,148 @@ ada_structop_operation::evaluate (struct type *expect_type,
     }
 }
 
+value *
+ada_funcall_operation::evaluate (struct type *expect_type,
+				 struct expression *exp,
+				 enum noside noside)
+{
+  const std::vector<operation_up> &args_up = std::get<1> (m_storage);
+  int nargs = args_up.size ();
+  std::vector<value *> argvec (nargs);
+  operation_up &callee_op = std::get<0> (m_storage);
+
+  ada_var_value_operation *avv
+    = dynamic_cast<ada_var_value_operation *> (callee_op.get ());
+  if (avv != nullptr
+      && SYMBOL_DOMAIN (avv->get_symbol ()) == UNDEF_DOMAIN)
+    error (_("Unexpected unresolved symbol, %s, during evaluation"),
+	   avv->get_symbol ()->print_name ());
+
+  value *callee = callee_op->evaluate (nullptr, exp, noside);
+  for (int i = 0; i < args_up.size (); ++i)
+    argvec[i] = args_up[i]->evaluate (nullptr, exp, noside);
+
+  if (ada_is_constrained_packed_array_type
+      (desc_base_type (value_type (callee))))
+    callee = ada_coerce_to_simple_array (callee);
+  else if (value_type (callee)->code () == TYPE_CODE_ARRAY
+	   && TYPE_FIELD_BITSIZE (value_type (callee), 0) != 0)
+    /* This is a packed array that has already been fixed, and
+       therefore already coerced to a simple array.  Nothing further
+       to do.  */
+    ;
+  else if (value_type (callee)->code () == TYPE_CODE_REF)
+    {
+      /* Make sure we dereference references so that all the code below
+	 feels like it's really handling the referenced value.  Wrapping
+	 types (for alignment) may be there, so make sure we strip them as
+	 well.  */
+      callee = ada_to_fixed_value (coerce_ref (callee));
+    }
+  else if (value_type (callee)->code () == TYPE_CODE_ARRAY
+	   && VALUE_LVAL (callee) == lval_memory)
+    callee = value_addr (callee);
+
+  struct type *type = ada_check_typedef (value_type (callee));
+
+  /* Ada allows us to implicitly dereference arrays when subscripting
+     them.  So, if this is an array typedef (encoding use for array
+     access types encoded as fat pointers), strip it now.  */
+  if (type->code () == TYPE_CODE_TYPEDEF)
+    type = ada_typedef_target_type (type);
+
+  if (type->code () == TYPE_CODE_PTR)
+    {
+      switch (ada_check_typedef (TYPE_TARGET_TYPE (type))->code ())
+	{
+	case TYPE_CODE_FUNC:
+	  type = ada_check_typedef (TYPE_TARGET_TYPE (type));
+	  break;
+	case TYPE_CODE_ARRAY:
+	  break;
+	case TYPE_CODE_STRUCT:
+	  if (noside != EVAL_AVOID_SIDE_EFFECTS)
+	    callee = ada_value_ind (callee);
+	  type = ada_check_typedef (TYPE_TARGET_TYPE (type));
+	  break;
+	default:
+	  error (_("cannot subscript or call something of type `%s'"),
+		 ada_type_name (value_type (callee)));
+	  break;
+	}
+    }
+
+  switch (type->code ())
+    {
+    case TYPE_CODE_FUNC:
+      if (noside == EVAL_AVOID_SIDE_EFFECTS)
+	{
+	  if (TYPE_TARGET_TYPE (type) == NULL)
+	    error_call_unknown_return_type (NULL);
+	  return allocate_value (TYPE_TARGET_TYPE (type));
+	}
+      return call_function_by_hand (callee, NULL, argvec);
+    case TYPE_CODE_INTERNAL_FUNCTION:
+      if (noside == EVAL_AVOID_SIDE_EFFECTS)
+	/* We don't know anything about what the internal
+	   function might return, but we have to return
+	   something.  */
+	return value_zero (builtin_type (exp->gdbarch)->builtin_int,
+			   not_lval);
+      else
+	return call_internal_function (exp->gdbarch, exp->language_defn,
+				       callee, nargs,
+				       argvec.data ());
+
+    case TYPE_CODE_STRUCT:
+      {
+	int arity;
+
+	arity = ada_array_arity (type);
+	type = ada_array_element_type (type, nargs);
+	if (type == NULL)
+	  error (_("cannot subscript or call a record"));
+	if (arity != nargs)
+	  error (_("wrong number of subscripts; expecting %d"), arity);
+	if (noside == EVAL_AVOID_SIDE_EFFECTS)
+	  return value_zero (ada_aligned_type (type), lval_memory);
+	return
+	  unwrap_value (ada_value_subscript
+			(callee, nargs, argvec.data ()));
+      }
+    case TYPE_CODE_ARRAY:
+      if (noside == EVAL_AVOID_SIDE_EFFECTS)
+	{
+	  type = ada_array_element_type (type, nargs);
+	  if (type == NULL)
+	    error (_("element type of array unknown"));
+	  else
+	    return value_zero (ada_aligned_type (type), lval_memory);
+	}
+      return
+	unwrap_value (ada_value_subscript
+		      (ada_coerce_to_simple_array (callee),
+		       nargs, argvec.data ()));
+    case TYPE_CODE_PTR:     /* Pointer to array */
+      if (noside == EVAL_AVOID_SIDE_EFFECTS)
+	{
+	  type = to_fixed_array_type (TYPE_TARGET_TYPE (type), NULL, 1);
+	  type = ada_array_element_type (type, nargs);
+	  if (type == NULL)
+	    error (_("element type of array unknown"));
+	  else
+	    return value_zero (ada_aligned_type (type), lval_memory);
+	}
+      return
+	unwrap_value (ada_value_ptr_subscript (callee, nargs,
+					       argvec.data ()));
+
+    default:
+      error (_("Attempt to index or call something other than an "
+	       "array or function"));
+    }
+}
+
 }
 
 /* Implement the evaluate_exp routine in the exp_descriptor structure
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 169/203] Implement Ada resolution
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (167 preceding siblings ...)
  2021-01-01 21:46 ` [PATCH 168/203] Implement function calls for Ada Tom Tromey
@ 2021-01-01 21:46 ` Tom Tromey
  2021-01-03  7:57   ` Joel Brobecker
  2021-01-01 21:46 ` [PATCH 170/203] Implement Ada assignment Tom Tromey
                   ` (34 subsequent siblings)
  203 siblings, 1 reply; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:46 UTC (permalink / raw)
  To: gdb-patches

Ada has a parser post-pass that implements "resolution".  This process
replaces some opcodes with function calls.  For example, a "+"
operation might be replaced with a call to the appropriate overloaded
function.

This differs from the approach taken for the same problem in C++.
However, in this series I chose not to try to make changes outside of
rewrite the expression data structure.  So, resolution remains.

The new approach to resolution is to introduce an interface class,
that some concrete operations implement.  Then, the Ada code will use
this to resolve the expression tree.  Because new-style expressions
are built as ordinary objects, and don't require rewriting the data
structure in place, in the new code this processing will be done in
the parser.  By the end of the series, some special cases in this area
that exist only for Ada will be removed.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* ada-lang.c (ada_var_value_operation::resolve)
	(ada_funcall_operation::resolve): New methods.
	* ada-exp.h (struct ada_resolvable): New.
	(class ada_var_value_operation): Derive from ada_resolvable.
	<get_block, resolve>: New methods.
	(class ada_funcall_operation): Derive from ada_resolvable.
	<resolve>: New method.
---
 gdb/ChangeLog  | 10 ++++++++
 gdb/ada-exp.h  | 38 ++++++++++++++++++++++++++++--
 gdb/ada-lang.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 109 insertions(+), 2 deletions(-)

diff --git a/gdb/ada-exp.h b/gdb/ada-exp.h
index 287ed5cc62c..2c5696cab76 100644
--- a/gdb/ada-exp.h
+++ b/gdb/ada-exp.h
@@ -304,9 +304,27 @@ class ada_unop_atr_operation
   { return std::get<1> (m_storage); }
 };
 
+/* The base class for Ada type resolution.  Ada operations that want
+   to participate in resolution implement this interface.  */
+struct ada_resolvable
+{
+  /* Resolve this object.  EXP is the expression being resolved.
+     DEPROCEDURE_P is true if de-proceduring is desired.
+     PARSE_COMPLETION and TRACKER are passed in from the parser
+     context.  CONTEXT_TYPE is the expected type of the expression, or
+     nullptr if none is known.  This method should return true if the
+     operation should be replaced by a function call with this object
+     as the callee.  */
+  virtual bool resolve (struct expression *exp,
+			bool deprocedure_p,
+			bool parse_completion,
+			innermost_block_tracker *tracker,
+			struct type *context_type) = 0;
+};
+
 /* Variant of var_value_operation for Ada.  */
 class ada_var_value_operation
-  : public var_value_operation
+  : public var_value_operation, public ada_resolvable
 {
 public:
 
@@ -323,6 +341,15 @@ class ada_var_value_operation
   symbol *get_symbol () const
   { return std::get<0> (m_storage); }
 
+  const block *get_block () const
+  { return std::get<1> (m_storage); }
+
+  bool resolve (struct expression *exp,
+		bool deprocedure_p,
+		bool parse_completion,
+		innermost_block_tracker *tracker,
+		struct type *context_type) override;
+
 protected:
 
   using operation::do_generate_ax;
@@ -392,7 +419,8 @@ class ada_structop_operation
 
 /* Function calls for Ada.  */
 class ada_funcall_operation
-  : public tuple_holding_operation<operation_up, std::vector<operation_up>>
+  : public tuple_holding_operation<operation_up, std::vector<operation_up>>,
+    public ada_resolvable
 {
 public:
 
@@ -402,6 +430,12 @@ class ada_funcall_operation
 		   struct expression *exp,
 		   enum noside noside) override;
 
+  bool resolve (struct expression *exp,
+		bool deprocedure_p,
+		bool parse_completion,
+		innermost_block_tracker *tracker,
+		struct type *context_type) override;
+
   enum exp_opcode opcode () const override
   { return OP_FUNCALL; }
 };
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 18f250b5a34..fa323331047 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -10836,6 +10836,31 @@ ada_var_value_operation::evaluate (struct type *expect_type,
   return ada_to_fixed_value (arg1);
 }
 
+bool
+ada_var_value_operation::resolve (struct expression *exp,
+				  bool deprocedure_p,
+				  bool parse_completion,
+				  innermost_block_tracker *tracker,
+				  struct type *context_type)
+{
+  symbol *sym = std::get<0> (m_storage);
+  if (SYMBOL_DOMAIN (sym) == UNDEF_DOMAIN)
+    {
+      block_symbol resolved
+	= ada_resolve_variable (sym, std::get<1> (m_storage),
+				context_type, parse_completion,
+				deprocedure_p, tracker);
+      std::get<0> (m_storage) = resolved.symbol;
+      std::get<1> (m_storage) = resolved.block;
+    }
+
+  if (deprocedure_p
+      && SYMBOL_TYPE (std::get<0> (m_storage))->code () == TYPE_CODE_FUNC)
+    return true;
+
+  return false;
+}
+
 value *
 ada_atr_val_operation::evaluate (struct type *expect_type,
 				 struct expression *exp,
@@ -11114,6 +11139,44 @@ ada_funcall_operation::evaluate (struct type *expect_type,
     }
 }
 
+bool
+ada_funcall_operation::resolve (struct expression *exp,
+				bool deprocedure_p,
+				bool parse_completion,
+				innermost_block_tracker *tracker,
+				struct type *context_type)
+{
+  operation_up &callee_op = std::get<0> (m_storage);
+
+  ada_var_value_operation *avv
+    = dynamic_cast<ada_var_value_operation *> (callee_op.get ());
+  if (avv == nullptr)
+    return false;
+
+  symbol *sym = avv->get_symbol ();
+  if (SYMBOL_DOMAIN (sym) != UNDEF_DOMAIN)
+    return false;
+
+  const std::vector<operation_up> &args_up = std::get<1> (m_storage);
+  int nargs = args_up.size ();
+  std::vector<value *> argvec (nargs);
+
+  for (int i = 0; i < args_up.size (); ++i)
+    argvec[i] = args_up[i]->evaluate (nullptr, exp, EVAL_AVOID_SIDE_EFFECTS);
+
+  const block *block = avv->get_block ();
+  block_symbol resolved
+    = ada_resolve_funcall (sym, block,
+			   context_type, parse_completion,
+			   nargs, argvec.data (),
+			   tracker);
+
+  std::get<0> (m_storage)
+    = make_operation<ada_var_value_operation> (resolved.symbol,
+					       resolved.block);
+  return false;
+}
+
 }
 
 /* Implement the evaluate_exp routine in the exp_descriptor structure
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 170/203] Implement Ada assignment
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (168 preceding siblings ...)
  2021-01-01 21:46 ` [PATCH 169/203] Implement Ada resolution Tom Tromey
@ 2021-01-01 21:46 ` Tom Tromey
  2021-01-01 21:46 ` [PATCH 171/203] Remove use of op_string Tom Tromey
                   ` (33 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:46 UTC (permalink / raw)
  To: gdb-patches

Assignment is the most complicated Ada expression, because
implementing aggregate assignment involves several specialized
opcodes.

This patch does this implementation by introducing new abstract
classes that are used to represent the various parts of aggregate
assignment.  This makes the code somewhat cleaner, and, by avoiding
the over-use of 'operation' subclasses, avoids the need for dissection
using dynamic_cast (though a few are still needed here).

I believe this patch fixes a latent bug in the handling of
aggregate_assign_from_choices.  That code does:

      if (op == OP_DISCRETE_RANGE)
	{
	  choice_pos += 1;
	  lower = value_as_long (ada_evaluate_subexp (NULL, exp, pos,
						      EVAL_NORMAL));
	  upper = value_as_long (ada_evaluate_subexp (NULL, exp, pos,
						      EVAL_NORMAL));
	}

However, I think 'choice_pos' should be used in the calls, rather than
'pos'.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* expprint.c (dump_for_expression): New overload.
	* expop.h (check_objfile, dump_for_expression): Declare new
	overloads.
	* ada-lang.c (check_objfile): New overload.
	(assign_component, ada_aggregate_component::uses_objfile)
	(ada_aggregate_component::dump, ada_aggregate_component::assign)
	(ada_aggregate_component::assign_aggregate)
	(ada_positional_component::uses_objfile)
	(ada_positional_component::dump, ada_positional_component::assign)
	(ada_discrete_range_association::uses_objfile)
	(ada_discrete_range_association::dump)
	(ada_discrete_range_association::assign)
	(ada_name_association::uses_objfile, ada_name_association::dump)
	(ada_name_association::assign)
	(ada_choices_component::uses_objfile, ada_choices_component::dump)
	(ada_choices_component::assign)
	(ada_others_component::uses_objfile, ada_others_component::dump)
	(ada_others_component::assign, ada_assign_operation::evaluate):
	New methods.
	* ada-exp.h (ada_string_operation) <get_name>: New method.
	(class ada_assign_operation): New.
	(class ada_component): New.
	(ada_component_up): New typedef.
	(class ada_aggregate_operation, class ada_aggregate_component)
	(class ada_positional_component, class ada_others_component)
	(class ada_association): New.
	(ada_association_up): New typedef.
	(class ada_choices_component)
	(class ada_discrete_range_association)
	(class ada_name_association): New.
---
 gdb/ChangeLog  |  33 +++++
 gdb/ada-exp.h  | 279 +++++++++++++++++++++++++++++++++++++++
 gdb/ada-lang.c | 344 +++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/expop.h    |   7 +
 gdb/expprint.c |   8 ++
 5 files changed, 671 insertions(+)

diff --git a/gdb/ada-exp.h b/gdb/ada-exp.h
index 2c5696cab76..7dfc64e2ec7 100644
--- a/gdb/ada-exp.h
+++ b/gdb/ada-exp.h
@@ -104,6 +104,12 @@ class ada_string_operation
 
   using string_operation::string_operation;
 
+  /* Return the underlying string.  */
+  const char *get_name () const
+  {
+    return std::get<0> (m_storage).c_str ();
+  }
+
   value *evaluate (struct type *expect_type,
 		   struct expression *exp,
 		   enum noside noside) override;
@@ -440,6 +446,279 @@ class ada_funcall_operation
   { return OP_FUNCALL; }
 };
 
+/* An Ada assignment operation.  */
+class ada_assign_operation
+  : public assign_operation
+{
+public:
+
+  using assign_operation::assign_operation;
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override;
+
+  enum exp_opcode opcode () const override
+  { return BINOP_ASSIGN; }
+};
+
+/* This abstract class represents a single component in an Ada
+   aggregate assignment.  */
+class ada_component
+{
+public:
+
+  /* Assign to LHS, which is part of CONTAINER.  EXP is the expression
+     being evaluated.  INDICES, LOW, and HIGH indicate which
+     sub-components have already been assigned; INDICES should be
+     updated by this call.  */
+  virtual void assign (struct value *container,
+		       struct value *lhs, struct expression *exp,
+		       std::vector<LONGEST> &indices,
+		       LONGEST low, LONGEST high) = 0;
+
+  /* Same as operation::uses_objfile.  */
+  virtual bool uses_objfile (struct objfile *objfile) = 0;
+
+  /* Same as operation::dump.  */
+  virtual void dump (ui_file *stream, int depth) = 0;
+
+  virtual ~ada_component () = default;
+
+protected:
+
+  ada_component () = default;
+  DISABLE_COPY_AND_ASSIGN (ada_component);
+};
+
+/* Unique pointer specialization for Ada assignment components.  */
+typedef std::unique_ptr<ada_component> ada_component_up;
+
+/* An operation that holds a single component.  */
+class ada_aggregate_operation
+  : public tuple_holding_operation<ada_component_up>
+{
+public:
+
+  using tuple_holding_operation::tuple_holding_operation;
+
+  /* Assuming that LHS represents an lvalue having a record or array
+     type, evaluate an assignment of this aggregate's value to LHS.
+     CONTAINER is an lvalue containing LHS (possibly LHS itself).
+     Does not modify the inferior's memory, nor does it modify the
+     contents of LHS (unless == CONTAINER).  */
+
+  void assign_aggregate (struct value *container,
+			 struct value *lhs,
+			 struct expression *exp);
+
+  value *evaluate (struct type *expect_type,
+		   struct expression *exp,
+		   enum noside noside) override
+  {
+    error (_("Aggregates only allowed on the right of an assignment"));
+  }
+
+  enum exp_opcode opcode () const override
+  { return OP_AGGREGATE; }
+};
+
+/* A component holding a vector of other components to assign.  */
+class ada_aggregate_component : public ada_component
+{
+public:
+
+  explicit ada_aggregate_component (std::vector<ada_component_up> &&components)
+    : m_components (std::move (components))
+  {
+  }
+
+  void assign (struct value *container,
+	       struct value *lhs, struct expression *exp,
+	       std::vector<LONGEST> &indices,
+	       LONGEST low, LONGEST high) override;
+
+  bool uses_objfile (struct objfile *objfile) override;
+
+  void dump (ui_file *stream, int depth) override;
+
+private:
+
+  std::vector<ada_component_up> m_components;
+};
+
+/* A component that assigns according to a provided index (which is
+   relative to the "low" value).  */
+class ada_positional_component : public ada_component
+{
+public:
+
+  ada_positional_component (int index, operation_up &&op)
+    : m_index (index),
+      m_op (std::move (op))
+  {
+  }
+
+  void assign (struct value *container,
+	       struct value *lhs, struct expression *exp,
+	       std::vector<LONGEST> &indices,
+	       LONGEST low, LONGEST high) override;
+
+  bool uses_objfile (struct objfile *objfile) override;
+
+  void dump (ui_file *stream, int depth) override;
+
+private:
+
+  int m_index;
+  operation_up m_op;
+};
+
+/* A component which handles an "others" clause.  */
+class ada_others_component : public ada_component
+{
+public:
+
+  explicit ada_others_component (operation_up &&op)
+    : m_op (std::move (op))
+  {
+  }
+
+  void assign (struct value *container,
+	       struct value *lhs, struct expression *exp,
+	       std::vector<LONGEST> &indices,
+	       LONGEST low, LONGEST high) override;
+
+  bool uses_objfile (struct objfile *objfile) override;
+
+  void dump (ui_file *stream, int depth) override;
+
+private:
+
+  operation_up m_op;
+};
+
+/* An interface that represents an association that is used in
+   aggregate assignment.  */
+class ada_association
+{
+public:
+
+  /* Like ada_component::assign, but takes an operation as a
+     parameter.  The operation is evaluated and then assigned into LHS
+     according to the rules of the concrete implementation.  */
+  virtual void assign (struct value *container,
+		       struct value *lhs,
+		       struct expression *exp,
+		       std::vector<LONGEST> &indices,
+		       LONGEST low, LONGEST high,
+		       operation_up &op) = 0;
+
+  /* Same as operation::uses_objfile.  */
+  virtual bool uses_objfile (struct objfile *objfile) = 0;
+
+  /* Same as operation::dump.  */
+  virtual void dump (ui_file *stream, int depth) = 0;
+
+  virtual ~ada_association () = default;
+
+protected:
+
+  ada_association () = default;
+  DISABLE_COPY_AND_ASSIGN (ada_association);
+};
+
+/* Unique pointer specialization for Ada assignment associations.  */
+typedef std::unique_ptr<ada_association> ada_association_up;
+
+/* A component that holds a vector of associations and an operation.
+   The operation is re-evaluated for each choice.  */
+class ada_choices_component : public ada_component
+{
+public:
+
+  explicit ada_choices_component (operation_up &&op)
+    : m_op (std::move (op))
+  {
+  }
+
+  /* Set the vector of associations.  This is done separately from the
+     constructor because it was simpler for the implementation of the
+     parser.  */
+  void set_associations (std::vector<ada_association_up> &&assoc)
+  {
+    m_assocs = std::move (assoc);
+  }
+
+  void assign (struct value *container,
+	       struct value *lhs, struct expression *exp,
+	       std::vector<LONGEST> &indices,
+	       LONGEST low, LONGEST high) override;
+
+  bool uses_objfile (struct objfile *objfile) override;
+
+  void dump (ui_file *stream, int depth) override;
+
+private:
+
+  std::vector<ada_association_up> m_assocs;
+  operation_up m_op;
+};
+
+/* An association that uses a discrete range.  */
+class ada_discrete_range_association : public ada_association
+{
+public:
+
+  ada_discrete_range_association (operation_up &&low, operation_up &&high)
+    : m_low (std::move (low)),
+      m_high (std::move (high))
+  {
+  }
+
+  void assign (struct value *container,
+	       struct value *lhs, struct expression *exp,
+	       std::vector<LONGEST> &indices,
+	       LONGEST low, LONGEST high,
+	       operation_up &op) override;
+
+  bool uses_objfile (struct objfile *objfile) override;
+
+  void dump (ui_file *stream, int depth) override;
+
+private:
+
+  operation_up m_low;
+  operation_up m_high;
+};
+
+/* An association that uses a name.  The name may be an expression
+   that evaluates to an integer (for arrays), or an Ada string or
+   variable value operation.  */
+class ada_name_association : public ada_association
+{
+public:
+
+  explicit ada_name_association (operation_up val)
+    : m_val (std::move (val))
+  {
+  }
+
+  void assign (struct value *container,
+	       struct value *lhs, struct expression *exp,
+	       std::vector<LONGEST> &indices,
+	       LONGEST low, LONGEST high,
+	       operation_up &op) override;
+
+  bool uses_objfile (struct objfile *objfile) override;
+
+  void dump (ui_file *stream, int depth) override;
+
+private:
+
+  operation_up m_val;
+};
+
 } /* namespace expr */
 
 #endif /* ADA_EXP_H */
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index fa323331047..f3f8642cf9d 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -9763,6 +9763,350 @@ aggregate_assign_others (struct value *container,
   ada_evaluate_subexp (NULL, exp, pos, EVAL_SKIP);
 }
 
+namespace expr
+{
+
+bool
+check_objfile (const std::unique_ptr<ada_component> &comp,
+	       struct objfile *objfile)
+{
+  return comp->uses_objfile (objfile);
+}
+
+/* Assign the result of evaluating ARG starting at *POS to the INDEXth
+   component of LHS (a simple array or a record).  Does not modify the
+   inferior's memory, nor does it modify LHS (unless LHS ==
+   CONTAINER).  */
+
+static void
+assign_component (struct value *container, struct value *lhs, LONGEST index,
+		  struct expression *exp, operation_up &arg)
+{
+  scoped_value_mark mark;
+
+  struct value *elt;
+  struct type *lhs_type = check_typedef (value_type (lhs));
+
+  if (lhs_type->code () == TYPE_CODE_ARRAY)
+    {
+      struct type *index_type = builtin_type (exp->gdbarch)->builtin_int;
+      struct value *index_val = value_from_longest (index_type, index);
+
+      elt = unwrap_value (ada_value_subscript (lhs, 1, &index_val));
+    }
+  else
+    {
+      elt = ada_index_struct_field (index, lhs, 0, value_type (lhs));
+      elt = ada_to_fixed_value (elt);
+    }
+
+  ada_aggregate_operation *ag_op
+    = dynamic_cast<ada_aggregate_operation *> (arg.get ());
+  if (ag_op != nullptr)
+    ag_op->assign_aggregate (container, elt, exp);
+  else
+    value_assign_to_component (container, elt,
+			       arg->evaluate (nullptr, exp,
+					      EVAL_NORMAL));
+}
+
+bool
+ada_aggregate_component::uses_objfile (struct objfile *objfile)
+{
+  for (const auto &item : m_components)
+    if (item->uses_objfile (objfile))
+      return true;
+  return false;
+}
+
+void
+ada_aggregate_component::dump (ui_file *stream, int depth)
+{
+  fprintf_filtered (stream, _("%*sAggregate\n"), depth, "");
+  for (const auto &item : m_components)
+    item->dump (stream, depth + 1);
+}
+
+void
+ada_aggregate_component::assign (struct value *container,
+				 struct value *lhs, struct expression *exp,
+				 std::vector<LONGEST> &indices,
+				 LONGEST low, LONGEST high)
+{
+  for (auto &item : m_components)
+    item->assign (container, lhs, exp, indices, low, high);
+}
+
+void
+ada_aggregate_operation::assign_aggregate (struct value *container,
+					   struct value *lhs,
+					   struct expression *exp)
+{
+  struct type *lhs_type;
+  LONGEST low_index, high_index;
+
+  container = ada_coerce_ref (container);
+  if (ada_is_direct_array_type (value_type (container)))
+    container = ada_coerce_to_simple_array (container);
+  lhs = ada_coerce_ref (lhs);
+  if (!deprecated_value_modifiable (lhs))
+    error (_("Left operand of assignment is not a modifiable lvalue."));
+
+  lhs_type = check_typedef (value_type (lhs));
+  if (ada_is_direct_array_type (lhs_type))
+    {
+      lhs = ada_coerce_to_simple_array (lhs);
+      lhs_type = check_typedef (value_type (lhs));
+      low_index = lhs_type->bounds ()->low.const_val ();
+      high_index = lhs_type->bounds ()->high.const_val ();
+    }
+  else if (lhs_type->code () == TYPE_CODE_STRUCT)
+    {
+      low_index = 0;
+      high_index = num_visible_fields (lhs_type) - 1;
+    }
+  else
+    error (_("Left-hand side must be array or record."));
+
+  std::vector<LONGEST> indices (4);
+  indices[0] = indices[1] = low_index - 1;
+  indices[2] = indices[3] = high_index + 1;
+
+  std::get<0> (m_storage)->assign (container, lhs, exp, indices,
+				   low_index, high_index);
+}
+
+bool
+ada_positional_component::uses_objfile (struct objfile *objfile)
+{
+  return m_op->uses_objfile (objfile);
+}
+
+void
+ada_positional_component::dump (ui_file *stream, int depth)
+{
+  fprintf_filtered (stream, _("%*sPositional, index = %d\n"),
+		    depth, "", m_index);
+  m_op->dump (stream, depth + 1);
+}
+
+/* Assign into the component of LHS indexed by the OP_POSITIONAL
+   construct, given that the positions are relative to lower bound
+   LOW, where HIGH is the upper bound.  Record the position in
+   INDICES.  CONTAINER is as for assign_aggregate.  */
+void
+ada_positional_component::assign (struct value *container,
+				  struct value *lhs, struct expression *exp,
+				  std::vector<LONGEST> &indices,
+				  LONGEST low, LONGEST high)
+{
+  LONGEST ind = m_index + low;
+
+  if (ind - 1 == high)
+    warning (_("Extra components in aggregate ignored."));
+  if (ind <= high)
+    {
+      add_component_interval (ind, ind, indices);
+      assign_component (container, lhs, ind, exp, m_op);
+    }
+}
+
+bool
+ada_discrete_range_association::uses_objfile (struct objfile *objfile)
+{
+  return m_low->uses_objfile (objfile) || m_high->uses_objfile (objfile);
+}
+
+void
+ada_discrete_range_association::dump (ui_file *stream, int depth)
+{
+  fprintf_filtered (stream, _("%*sDiscrete range:\n"), depth, "");
+  m_low->dump (stream, depth + 1);
+  m_high->dump (stream, depth + 1);
+}
+
+void
+ada_discrete_range_association::assign (struct value *container,
+					struct value *lhs,
+					struct expression *exp,
+					std::vector<LONGEST> &indices,
+					LONGEST low, LONGEST high,
+					operation_up &op)
+{
+  LONGEST lower = value_as_long (m_low->evaluate (nullptr, exp, EVAL_NORMAL));
+  LONGEST upper = value_as_long (m_high->evaluate (nullptr, exp, EVAL_NORMAL));
+
+  if (lower <= upper && (lower < low || upper > high))
+    error (_("Index in component association out of bounds."));
+
+  add_component_interval (lower, upper, indices);
+  while (lower <= upper)
+    {
+      assign_component (container, lhs, lower, exp, op);
+      lower += 1;
+    }
+}
+
+bool
+ada_name_association::uses_objfile (struct objfile *objfile)
+{
+  return m_val->uses_objfile (objfile);
+}
+
+void
+ada_name_association::dump (ui_file *stream, int depth)
+{
+  fprintf_filtered (stream, _("%*sName:\n"), depth, "");
+  m_val->dump (stream, depth + 1);
+}
+
+void
+ada_name_association::assign (struct value *container,
+			      struct value *lhs,
+			      struct expression *exp,
+			      std::vector<LONGEST> &indices,
+			      LONGEST low, LONGEST high,
+			      operation_up &op)
+{
+  int index;
+
+  if (ada_is_direct_array_type (value_type (lhs)))
+    index = longest_to_int (value_as_long (m_val->evaluate (nullptr, exp,
+							    EVAL_NORMAL)));
+  else
+    {
+      ada_string_operation *strop
+	= dynamic_cast<ada_string_operation *> (m_val.get ());
+
+      const char *name;
+      if (strop != nullptr)
+	name = strop->get_name ();
+      else
+	{
+	  ada_var_value_operation *vvo
+	    = dynamic_cast<ada_var_value_operation *> (m_val.get ());
+	  if (vvo != nullptr)
+	    error (_("Invalid record component association."));
+	  name = vvo->get_symbol ()->natural_name ();
+	}
+
+      index = 0;
+      if (! find_struct_field (name, value_type (lhs), 0,
+			       NULL, NULL, NULL, NULL, &index))
+	error (_("Unknown component name: %s."), name);
+    }
+
+  add_component_interval (index, index, indices);
+  assign_component (container, lhs, index, exp, op);
+}
+
+bool
+ada_choices_component::uses_objfile (struct objfile *objfile)
+{
+  if (m_op->uses_objfile (objfile))
+    return true;
+  for (const auto &item : m_assocs)
+    if (item->uses_objfile (objfile))
+      return true;
+  return false;
+}
+
+void
+ada_choices_component::dump (ui_file *stream, int depth)
+{
+  fprintf_filtered (stream, _("%*sChoices:\n"), depth, "");
+  m_op->dump (stream, depth + 1);
+  for (const auto &item : m_assocs)
+    item->dump (stream, depth + 1);
+}
+
+/* Assign into the components of LHS indexed by the OP_CHOICES
+   construct at *POS, updating *POS past the construct, given that
+   the allowable indices are LOW..HIGH.  Record the indices assigned
+   to in INDICES.  CONTAINER is as for assign_aggregate.  */
+void
+ada_choices_component::assign (struct value *container,
+			       struct value *lhs, struct expression *exp,
+			       std::vector<LONGEST> &indices,
+			       LONGEST low, LONGEST high)
+{
+  for (auto &item : m_assocs)
+    item->assign (container, lhs, exp, indices, low, high, m_op);
+}
+
+bool
+ada_others_component::uses_objfile (struct objfile *objfile)
+{
+  return m_op->uses_objfile (objfile);
+}
+
+void
+ada_others_component::dump (ui_file *stream, int depth)
+{
+  fprintf_filtered (stream, _("%*sOthers:\n"), depth, "");
+  m_op->dump (stream, depth + 1);
+}
+
+/* Assign the value of the expression in the OP_OTHERS construct in
+   EXP at *POS into the components of LHS indexed from LOW .. HIGH that
+   have not been previously assigned.  The index intervals already assigned
+   are in INDICES.  CONTAINER is as for assign_aggregate.  */
+void
+ada_others_component::assign (struct value *container,
+			      struct value *lhs, struct expression *exp,
+			      std::vector<LONGEST> &indices,
+			      LONGEST low, LONGEST high)
+{
+  int num_indices = indices.size ();
+  for (int i = 0; i < num_indices - 2; i += 2)
+    {
+      for (LONGEST ind = indices[i + 1] + 1; ind < indices[i + 2]; ind += 1)
+	assign_component (container, lhs, ind, exp, m_op);
+    }
+}
+
+struct value *
+ada_assign_operation::evaluate (struct type *expect_type,
+				struct expression *exp,
+				enum noside noside)
+{
+  value *arg1 = std::get<0> (m_storage)->evaluate (nullptr, exp, noside);
+
+  ada_aggregate_operation *ag_op
+    = dynamic_cast<ada_aggregate_operation *> (std::get<1> (m_storage).get ());
+  if (ag_op != nullptr)
+    {
+      if (noside != EVAL_NORMAL)
+	return arg1;
+
+      ag_op->assign_aggregate (arg1, arg1, exp);
+      return ada_value_assign (arg1, arg1);
+    }
+  /* Force the evaluation of the rhs ARG2 to the type of the lhs ARG1,
+     except if the lhs of our assignment is a convenience variable.
+     In the case of assigning to a convenience variable, the lhs
+     should be exactly the result of the evaluation of the rhs.  */
+  struct type *type = value_type (arg1);
+  if (VALUE_LVAL (arg1) == lval_internalvar)
+    type = NULL;
+  value *arg2 = std::get<1> (m_storage)->evaluate (type, exp, noside);
+  if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS)
+    return arg1;
+  if (VALUE_LVAL (arg1) == lval_internalvar)
+    {
+      /* Nothing.  */
+    }
+  else if (ada_is_gnat_encoded_fixed_point_type (value_type (arg1)))
+    arg2 = cast_to_gnat_encoded_fixed_point_type (value_type (arg1), arg2);
+  else if (ada_is_gnat_encoded_fixed_point_type (value_type (arg2)))
+    error (_("Fixed-point values must be assigned to fixed-point variables"));
+  else
+    arg2 = coerce_for_assign (value_type (arg1), arg2);
+  return ada_value_assign (arg1, arg2);
+}
+
+} /* namespace expr */
+
 /* Add the interval [LOW .. HIGH] to the sorted set of intervals
    [ INDICES[0] .. INDICES[1] ],...  The resulting intervals do not
    overlap.  */
diff --git a/gdb/expop.h b/gdb/expop.h
index de4b876de39..f433dd3d08f 100644
--- a/gdb/expop.h
+++ b/gdb/expop.h
@@ -206,6 +206,8 @@ extern struct value *eval_binop_assign_modify (struct type *expect_type,
 namespace expr
 {
 
+class ada_component;
+
 /* The check_objfile overloads are used to check whether a particular
    component of some operation references an objfile.  The passed-in
    objfile will never be a debug objfile.  */
@@ -305,6 +307,9 @@ check_objfile (const std::pair<S, T> &item, struct objfile *objfile)
 	  || check_objfile (item.second, objfile));
 }
 
+extern bool check_objfile (const std::unique_ptr<ada_component> &comp,
+			   struct objfile *objfile);
+
 static inline void
 dump_for_expression (struct ui_file *stream, int depth,
 		     const operation_up &op)
@@ -336,6 +341,8 @@ extern void dump_for_expression (struct ui_file *stream, int depth,
 				 enum range_flag flags);
 extern void dump_for_expression (struct ui_file *stream, int depth,
 				 objfile *objf);
+extern void dump_for_expression (struct ui_file *stream, int depth,
+				 const std::unique_ptr<ada_component> &comp);
 
 template<typename T>
 void
diff --git a/gdb/expprint.c b/gdb/expprint.c
index 0f4c8602f1c..ac954d2980d 100644
--- a/gdb/expprint.c
+++ b/gdb/expprint.c
@@ -32,6 +32,7 @@
 #include "cli/cli-style.h"
 #include "c-lang.h"
 #include "expop.h"
+#include "ada-exp.h"
 
 #include <ctype.h>
 
@@ -1276,6 +1277,13 @@ dump_for_expression (struct ui_file *stream, int depth,
   fprintf_filtered (stream, "\n");
 }
 
+void
+dump_for_expression (struct ui_file *stream, int depth,
+		     const std::unique_ptr<ada_component> &comp)
+{
+  comp->dump (stream, depth);
+}
+
 void
 float_const_operation::dump (struct ui_file *stream, int depth) const
 {
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 171/203] Remove use of op_string
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (169 preceding siblings ...)
  2021-01-01 21:46 ` [PATCH 170/203] Implement Ada assignment Tom Tromey
@ 2021-01-01 21:46 ` Tom Tromey
  2021-01-01 21:46 ` [PATCH 172/203] Add an expr::operation_up to struct expression Tom Tromey
                   ` (32 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:46 UTC (permalink / raw)
  To: gdb-patches

After switching to the new expression implementation, there will no
need for op_string.  Before deleting it, the one call outside of the
expression-printing code must be removed.  That is what this patch
does.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* ada-lang.c (ada_value_binop): Do not use op_string.
---
 gdb/ChangeLog  |  4 ++++
 gdb/ada-lang.c | 15 ++++++++++++++-
 2 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index f3f8642cf9d..657ef37dca7 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -9450,7 +9450,20 @@ ada_value_binop (struct value *arg1, struct value *arg2, enum exp_opcode op)
 
   v2 = value_as_long (arg2);
   if (v2 == 0)
-    error (_("second operand of %s must not be zero."), op_string (op));
+    {
+      const char *name;
+      if (op == BINOP_MOD)
+	name = "mod";
+      else if (op == BINOP_DIV)
+	name = "/";
+      else
+	{
+	  gdb_assert (op == BINOP_REM);
+	  name = "rem";
+	}
+
+      error (_("second operand of %s must not be zero."), name);
+    }
 
   if (type1->is_unsigned () || op == BINOP_MOD)
     return value_binop (arg1, arg2, op);
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 172/203] Add an expr::operation_up to struct expression
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (170 preceding siblings ...)
  2021-01-01 21:46 ` [PATCH 171/203] Remove use of op_string Tom Tromey
@ 2021-01-01 21:46 ` Tom Tromey
  2021-01-01 21:46 ` [PATCH 173/203] Add completion for operations Tom Tromey
                   ` (31 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:46 UTC (permalink / raw)
  To: gdb-patches

This adds an expr::operation_up to struct expression, and then
modifies various parts of GDB to use this member when it is non-null.
The list of such spots was a bit surprising to me, and found only
after writing most of the code and then noticing what no longer
compiled.

In a few spots, new accessor methods are added to operation
subclasses, so that code that dissects an expression will work with
the new scheme.

After this change, code that constructs an expression can be switched
to the new form without breaking.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* value.h (fetch_subexp_value): Add "op" parameter.
	* value.c (init_if_undefined_command): Update.
	* tracepoint.c (validate_actionline, encode_actions_1): Update.
	* stap-probe.c (stap_probe::compile_to_ax): Update.
	* printcmd.c (set_command): Update.
	* ppc-linux-nat.c (ppc_linux_nat_target::check_condition):
	Update.
	* parser-defs.h (struct expr_builder) <set_operation>: New
	method.
	* parse.c (parse_exp_in_context, exp_uses_objfile): Update.
	* expression.h (struct expression) <first_opcode>: Update.
	<op>: New member.
	* expprint.c (dump_raw_expression, dump_prefix_expression):
	Update.
	* expop.h (class var_value_operation) <get_symbol>: New method.
	(class register_operation) <get_name>: New method.
	(class equal_operation): No longer a typedef, now a subclass.
	(class unop_memval_operation) <get_type>: New method.
	(class assign_operation) <get_lhs>: New method.
	(class unop_cast_operation) <get_type>: New method.
	* eval.c (evaluate_expression, evaluate_type)
	(evaluate_subexpression_type): Update.
	(fetch_subexp_value): Add "op" parameter.
	(parse_and_eval_type): Update.
	* dtrace-probe.c (dtrace_probe::compile_to_ax): Update.
	* breakpoint.c (update_watchpoint, watchpoint_check)
	(watchpoint_exp_is_const, watch_command_1): Update.
	* ax-gdb.c (gen_trace_for_expr, gen_eval_for_expr, gen_printf):
	Update.
---
 gdb/ChangeLog       | 32 ++++++++++++++++++
 gdb/ax-gdb.c        | 19 ++++++++---
 gdb/breakpoint.c    | 13 ++++---
 gdb/dtrace-probe.c  |  9 +++--
 gdb/eval.c          | 26 ++++++++++++--
 gdb/expop.h         | 49 ++++++++++++++++++++++++++-
 gdb/expprint.c      | 16 +++++++++
 gdb/expression.h    |  5 ++-
 gdb/parse.c         | 12 +++++--
 gdb/parser-defs.h   |  7 ++++
 gdb/ppc-linux-nat.c | 20 +++++++++--
 gdb/printcmd.c      | 10 ++++--
 gdb/stap-probe.c    |  5 ++-
 gdb/tracepoint.c    | 82 ++++++++++++++++++++++++++++++++++-----------
 gdb/value.c         | 28 +++++++++++++---
 gdb/value.h         |  2 ++
 16 files changed, 287 insertions(+), 48 deletions(-)

diff --git a/gdb/ax-gdb.c b/gdb/ax-gdb.c
index 8ec3dd7cc3d..d2f50bbec7b 100644
--- a/gdb/ax-gdb.c
+++ b/gdb/ax-gdb.c
@@ -3064,7 +3064,10 @@ gen_trace_for_expr (CORE_ADDR scope, struct expression *expr,
   ax->tracing = 1;
   ax->trace_string = trace_string;
   value.optimized_out = 0;
-  gen_expr (expr, &pc, ax.get (), &value);
+  if (expr->op != nullptr)
+    expr->op->generate_ax (expr, ax.get (), &value);
+  else
+    gen_expr (expr, &pc, ax.get (), &value);
 
   /* Make sure we record the final object, and get rid of it.  */
   gen_traced_pop (ax.get (), &value);
@@ -3092,7 +3095,10 @@ gen_eval_for_expr (CORE_ADDR scope, struct expression *expr)
   pc = expr->elts;
   ax->tracing = 0;
   value.optimized_out = 0;
-  gen_expr (expr, &pc, ax.get (), &value);
+  if (expr->op != nullptr)
+    expr->op->generate_ax (expr, ax.get (), &value);
+  else
+    gen_expr (expr, &pc, ax.get (), &value);
 
   require_rvalue (ax.get (), &value);
 
@@ -3145,9 +3151,14 @@ gen_printf (CORE_ADDR scope, struct gdbarch *gdbarch,
      for simplicity of collecting them on the target side.  */
   for (tem = nargs - 1; tem >= 0; --tem)
     {
-      pc = exprs[tem]->elts;
       value.optimized_out = 0;
-      gen_expr (exprs[tem], &pc, ax.get (), &value);
+      if (exprs[tem]->op != nullptr)
+	exprs[tem]->op->generate_ax (exprs[tem], ax.get (), &value);
+      else
+	{
+	  pc = exprs[tem]->elts;
+	  gen_expr (exprs[tem], &pc, ax.get (), &value);
+	}
       require_rvalue (ax.get (), &value);
     }
 
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 69e452993f1..1f7716c29f4 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -1903,7 +1903,8 @@ update_watchpoint (struct watchpoint *b, int reparse)
       struct value *v, *result;
       struct program_space *frame_pspace;
 
-      fetch_subexp_value (b->exp.get (), &pc, &v, &result, &val_chain, false);
+      fetch_subexp_value (b->exp.get (), &pc, b->exp->op.get (), &v, &result,
+			  &val_chain, false);
 
       /* Avoid setting b->val if it's already set.  The meaning of
 	 b->val is 'the last value' user saw, and we should update
@@ -4955,7 +4956,8 @@ watchpoint_check (bpstat bs)
 	return WP_VALUE_CHANGED;
 
       mark = value_mark ();
-      fetch_subexp_value (b->exp.get (), &pc, &new_val, NULL, NULL, false);
+      fetch_subexp_value (b->exp.get (), &pc, b->exp->op.get (), &new_val,
+			  NULL, NULL, false);
 
       if (b->val_bitsize != 0)
 	new_val = extract_bitfield_from_watchpoint_value (b, new_val);
@@ -10056,6 +10058,9 @@ break_range_command (const char *arg, int from_tty)
 static bool
 watchpoint_exp_is_const (const struct expression *exp)
 {
+  if (exp->op != nullptr)
+    return exp->op->constant_p ();
+
   int i = exp->nelts;
 
   while (i > 0)
@@ -10776,8 +10781,8 @@ watch_command_1 (const char *arg, int accessflag, int from_tty,
   exp_valid_block = tracker.block ();
   struct value *mark = value_mark ();
   struct value *val_as_value = nullptr;
-  fetch_subexp_value (exp.get (), &pc, &val_as_value, &result, NULL,
-		      just_location);
+  fetch_subexp_value (exp.get (), &pc, exp->op.get (), &val_as_value, &result,
+		      NULL, just_location);
 
   if (val_as_value != NULL && just_location)
     {
diff --git a/gdb/dtrace-probe.c b/gdb/dtrace-probe.c
index 6c01f87de64..f4b6becbf61 100644
--- a/gdb/dtrace-probe.c
+++ b/gdb/dtrace-probe.c
@@ -730,8 +730,13 @@ dtrace_probe::compile_to_ax (struct agent_expr *expr, struct axs_value *value,
 
   arg = this->get_arg_by_number (n, expr->gdbarch);
 
-  pc = arg->expr->elts;
-  gen_expr (arg->expr.get (), &pc, expr, value);
+  if (arg->expr->op != nullptr)
+    arg->expr->op->generate_ax (arg->expr.get (), expr, value);
+  else
+    {
+      pc = arg->expr->elts;
+      gen_expr (arg->expr.get (), &pc, expr, value);
+    }
 
   require_rvalue (expr, value);
   value->type = arg->type;
diff --git a/gdb/eval.c b/gdb/eval.c
index ff3c58cd4a8..bb4e59fe17f 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -130,6 +130,9 @@ evaluate_expression (struct expression *exp, struct type *expect_type)
 {
   int pc = 0;
 
+  if (exp->op != nullptr)
+    return exp->op->evaluate (expect_type, exp, EVAL_NORMAL);
+
   return evaluate_subexp (expect_type, exp, &pc, EVAL_NORMAL);
 }
 
@@ -141,6 +144,9 @@ evaluate_type (struct expression *exp)
 {
   int pc = 0;
 
+  if (exp->op != nullptr)
+    return exp->op->evaluate (nullptr, exp, EVAL_AVOID_SIDE_EFFECTS);
+
   return evaluate_subexp (nullptr, exp, &pc, EVAL_AVOID_SIDE_EFFECTS);
 }
 
@@ -150,6 +156,8 @@ evaluate_type (struct expression *exp)
 struct value *
 evaluate_subexpression_type (struct expression *exp, int subexp)
 {
+  if (exp->op != nullptr)
+    return exp->op->evaluate (nullptr, exp, EVAL_AVOID_SIDE_EFFECTS);
   return evaluate_subexp (nullptr, exp, &subexp, EVAL_AVOID_SIDE_EFFECTS);
 }
 
@@ -176,8 +184,9 @@ evaluate_subexpression_type (struct expression *exp, int subexp)
    values will be left on the value chain.  */
 
 void
-fetch_subexp_value (struct expression *exp, int *pc, struct value **valp,
-		    struct value **resultp,
+fetch_subexp_value (struct expression *exp, int *pc,
+		    expr::operation *op,
+		    struct value **valp, struct value **resultp,
 		    std::vector<value_ref_ptr> *val_chain,
 		    bool preserve_errors)
 {
@@ -195,7 +204,10 @@ fetch_subexp_value (struct expression *exp, int *pc, struct value **valp,
 
   try
     {
-      result = evaluate_subexp (nullptr, exp, pc, EVAL_NORMAL);
+      if (op == nullptr)
+	result = evaluate_subexp (nullptr, exp, pc, EVAL_NORMAL);
+      else
+	result = op->evaluate (nullptr, exp, EVAL_NORMAL);
     }
   catch (const gdb_exception &ex)
     {
@@ -4463,5 +4475,13 @@ parse_and_eval_type (const char *p, int length)
   expression_up expr = parse_expression (tmp);
   if (expr->first_opcode () != UNOP_CAST)
     error (_("Internal error in eval_type."));
+
+  if (expr->op != nullptr)
+    {
+      expr::unop_cast_operation *op
+	= dynamic_cast<expr::unop_cast_operation *> (expr->op.get ());
+      return op->get_type ();
+    }
+
   return expr->elts[1].type;
 }
diff --git a/gdb/expop.h b/gdb/expop.h
index f433dd3d08f..7449ef60562 100644
--- a/gdb/expop.h
+++ b/gdb/expop.h
@@ -659,6 +659,12 @@ class var_value_operation
 	    || SYMBOL_CLASS (sym) == LOC_LABEL);
   }
 
+  /* Return the symbol referenced by this object.  */
+  symbol *get_symbol () const
+  {
+    return std::get<0> (m_storage);
+  }
+
 protected:
 
   void do_generate_ax (struct expression *exp,
@@ -811,6 +817,12 @@ class register_operation
   enum exp_opcode opcode () const override
   { return OP_REGISTER; }
 
+  /* Return the name of the register.  */
+  const char *get_name () const
+  {
+    return std::get<0> (m_storage).c_str ();
+  }
+
 protected:
 
   void do_generate_ax (struct expression *exp,
@@ -1317,7 +1329,24 @@ class comparison_operation
   }
 };
 
-using equal_operation = comparison_operation<BINOP_EQUAL, eval_op_equal>;
+class equal_operation
+  : public comparison_operation<BINOP_EQUAL, eval_op_equal>
+{
+public:
+
+  using comparison_operation::comparison_operation;
+
+  operation *get_lhs () const
+  {
+    return std::get<0> (m_storage).get ();
+  }
+
+  operation *get_rhs () const
+  {
+    return std::get<1> (m_storage).get ();
+  }
+};
+
 using notequal_operation
      = comparison_operation<BINOP_NOTEQUAL, eval_op_notequal>;
 using less_operation = comparison_operation<BINOP_LESS, eval_op_less>;
@@ -1741,6 +1770,12 @@ class unop_memval_operation
   enum exp_opcode opcode () const override
   { return UNOP_MEMVAL; }
 
+  /* Return the type referenced by this object.  */
+  struct type *get_type () const
+  {
+    return std::get<1> (m_storage);
+  }
+
 protected:
 
   void do_generate_ax (struct expression *exp,
@@ -1866,6 +1901,12 @@ class assign_operation
   enum exp_opcode opcode () const override
   { return BINOP_ASSIGN; }
 
+  /* Return the left-hand-side of the assignment.  */
+  operation *get_lhs () const
+  {
+    return std::get<0> (m_storage).get ();
+  }
+
 protected:
 
   void do_generate_ax (struct expression *exp,
@@ -1924,6 +1965,12 @@ class unop_cast_operation
   enum exp_opcode opcode () const override
   { return UNOP_CAST; }
 
+  /* Return the type referenced by this object.  */
+  struct type *get_type () const
+  {
+    return std::get<1> (m_storage);
+  }
+
 protected:
 
   void do_generate_ax (struct expression *exp,
diff --git a/gdb/expprint.c b/gdb/expprint.c
index ac954d2980d..1a6634a7b7f 100644
--- a/gdb/expprint.c
+++ b/gdb/expprint.c
@@ -725,6 +725,9 @@ dump_raw_expression (struct expression *exp, struct ui_file *stream,
   char *eltscan;
   int eltsize;
 
+  if (exp->op != nullptr)
+    return;
+
   fprintf_filtered (stream, "Dump of expression @ ");
   gdb_print_host_address (exp, stream);
   if (note)
@@ -1143,9 +1146,22 @@ dump_prefix_expression (struct expression *exp, struct ui_file *stream)
 {
   int elt;
 
+  if (exp->op != nullptr)
+    {
+      exp->op->dump (stream, 0);
+      return;
+    }
+
   fprintf_filtered (stream, "Dump of expression @ ");
   gdb_print_host_address (exp, stream);
   fputs_filtered (", after conversion to prefix form:\nExpression: `", stream);
+
+  if (exp->op != nullptr)
+    {
+      exp->op->dump (stream, 0);
+      return;
+    }
+
   print_expression (exp, stream);
   fprintf_filtered (stream, "'\n\tLanguage %s, %d elements, %ld bytes each.\n",
 		    exp->language_defn->name (), exp->nelts,
diff --git a/gdb/expression.h b/gdb/expression.h
index a850f64d160..f9b7855346e 100644
--- a/gdb/expression.h
+++ b/gdb/expression.h
@@ -225,13 +225,16 @@ struct expression
      expression.  */
   enum exp_opcode first_opcode () const
   {
-      return elts[0].opcode;
+    if (op != nullptr)
+      return op->opcode ();
+    return elts[0].opcode;
   }
 
   /* Language it was entered in.  */
   const struct language_defn *language_defn;
   /* Architecture it was parsed in.  */
   struct gdbarch *gdbarch;
+  expr::operation_up op;
   int nelts = 0;
   union exp_element *elts;
 };
diff --git a/gdb/parse.c b/gdb/parse.c
index 4eccb1ac489..4c8eb14549b 100644
--- a/gdb/parse.c
+++ b/gdb/parse.c
@@ -50,6 +50,7 @@
 #include "user-regs.h"
 #include <algorithm>
 #include "gdbsupport/gdb_optional.h"
+#include "c-exp.h"
 
 /* Standard set of definitions for printing, dumping, prefixifying,
  * and evaluating expressions.  */
@@ -1152,7 +1153,8 @@ parse_exp_in_context (const char **stringptr, CORE_ADDR pc,
       /* If parsing for completion, allow this to succeed; but if no
 	 expression elements have been written, then there's nothing
 	 to do, so fail.  */
-      if (! ps.parse_completion || ps.expout_ptr == 0)
+      if (! ps.parse_completion
+	  || (ps.expout->op == nullptr && ps.expout_ptr == 0))
 	throw;
     }
 
@@ -1167,8 +1169,9 @@ parse_exp_in_context (const char **stringptr, CORE_ADDR pc,
     dump_raw_expression (result.get (), gdb_stdlog,
 			 "before conversion to prefix form");
 
-  subexp = prefixify_expression (result.get (),
-				 ps.m_completion_state.expout_last_struct);
+  if (result->op == nullptr)
+    subexp = prefixify_expression (result.get (),
+				   ps.m_completion_state.expout_last_struct);
   if (out_subexp)
     *out_subexp = subexp;
 
@@ -1433,6 +1436,9 @@ exp_uses_objfile (struct expression *exp, struct objfile *objfile)
 {
   gdb_assert (objfile->separate_debug_objfile_backlink == NULL);
 
+  if (exp->op != nullptr)
+    return exp->op->uses_objfile (objfile);
+
   return exp_iterate (exp, exp_uses_objfile_iter, objfile);
 }
 
diff --git a/gdb/parser-defs.h b/gdb/parser-defs.h
index 07207945487..9f1925d463a 100644
--- a/gdb/parser-defs.h
+++ b/gdb/parser-defs.h
@@ -63,6 +63,13 @@ struct expr_builder
     return expout->language_defn;
   }
 
+  /* Set the root operation of the expression that is currently being
+     built.  */
+  void set_operation (expr::operation_up &&op)
+  {
+    expout->op = std::move (op);
+  }
+
   /* The size of the expression above.  */
 
   size_t expout_size;
diff --git a/gdb/ppc-linux-nat.c b/gdb/ppc-linux-nat.c
index 4da15f9a663..72f0283e4af 100644
--- a/gdb/ppc-linux-nat.c
+++ b/gdb/ppc-linux-nat.c
@@ -54,6 +54,7 @@
 #include "arch/ppc-linux-tdesc.h"
 #include "nat/ppc-linux.h"
 #include "linux-tdep.h"
+#include "expop.h"
 
 /* Similarly for the hardware watchpoint support.  These requests are used
    when the PowerPC HWDEBUG ptrace interface is not available.  */
@@ -2491,16 +2492,29 @@ ppc_linux_nat_target::check_condition (CORE_ADDR watch_addr,
   struct value *left_val, *right_val;
   std::vector<value_ref_ptr> left_chain, right_chain;
 
-  if (cond->elts[0].opcode != BINOP_EQUAL)
+  if (cond->first_opcode () != BINOP_EQUAL)
     return 0;
 
-  fetch_subexp_value (cond, &pc, &left_val, NULL, &left_chain, false);
+  expr::operation *lhs = nullptr;
+  expr::operation *rhs = nullptr;
+  if (cond->op != nullptr)
+    {
+      expr::equal_operation *eqop
+	= dynamic_cast<expr::equal_operation *> (cond->op.get ());
+      if (eqop != nullptr)
+	{
+	  lhs = eqop->get_lhs ();
+	  rhs = eqop->get_rhs ();
+	}
+    }
+
+  fetch_subexp_value (cond, &pc, lhs, &left_val, NULL, &left_chain, false);
   num_accesses_left = num_memory_accesses (left_chain);
 
   if (left_val == NULL || num_accesses_left < 0)
     return 0;
 
-  fetch_subexp_value (cond, &pc, &right_val, NULL, &right_chain, false);
+  fetch_subexp_value (cond, &pc, rhs, &right_val, NULL, &right_chain, false);
   num_accesses_right = num_memory_accesses (right_chain);
 
   if (right_val == NULL || num_accesses_right < 0)
diff --git a/gdb/printcmd.c b/gdb/printcmd.c
index a1c9af1acae..5b399489c70 100644
--- a/gdb/printcmd.c
+++ b/gdb/printcmd.c
@@ -1373,8 +1373,14 @@ set_command (const char *exp, int from_tty)
 {
   expression_up expr = parse_expression (exp);
 
-  if (expr->nelts >= 1)
-    switch (expr->elts[0].opcode)
+  enum exp_opcode opcode = OP_NULL;
+  if (expr->op != nullptr)
+    opcode = expr->op->opcode ();
+  else if (expr->nelts >= 1)
+    opcode = expr->elts[0].opcode;
+
+  if (opcode != OP_NULL)
+    switch (opcode)
       {
       case UNOP_PREINCREMENT:
       case UNOP_POSTINCREMENT:
diff --git a/gdb/stap-probe.c b/gdb/stap-probe.c
index 42f34475651..6ee025744aa 100644
--- a/gdb/stap-probe.c
+++ b/gdb/stap-probe.c
@@ -1404,7 +1404,10 @@ stap_probe::compile_to_ax (struct agent_expr *expr, struct axs_value *value,
   arg = this->get_arg_by_number (n, expr->gdbarch);
 
   pc = arg->aexpr->elts;
-  gen_expr (arg->aexpr.get (), &pc, expr, value);
+  if (arg->aexpr->op != nullptr)
+    arg->aexpr->op->generate_ax (arg->aexpr.get (), expr, value);
+  else
+    gen_expr (arg->aexpr.get (), &pc, expr, value);
 
   require_rvalue (expr, value);
   value->type = arg->atype;
diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c
index a355f63c22e..ec46446c8bf 100644
--- a/gdb/tracepoint.c
+++ b/gdb/tracepoint.c
@@ -57,6 +57,7 @@
 #include "location.h"
 #include <algorithm>
 #include "cli/cli-style.h"
+#include "expop.h"
 
 #include <unistd.h>
 
@@ -689,19 +690,29 @@ validate_actionline (const char *line, struct breakpoint *b)
 
 	      if (exp->first_opcode () == OP_VAR_VALUE)
 		{
-		  if (SYMBOL_CLASS (exp->elts[2].symbol) == LOC_CONST)
+		  symbol *sym;
+		  if (exp->op != nullptr)
+		    {
+		      expr::var_value_operation *vvop
+			= (dynamic_cast<expr::var_value_operation *>
+			   (exp->op.get ()));
+		      sym = vvop->get_symbol ();
+		    }
+		  else
+		    sym = exp->elts[2].symbol;
+
+		  if (SYMBOL_CLASS (sym) == LOC_CONST)
 		    {
 		      error (_("constant `%s' (value %s) "
 			       "will not be collected."),
-			     exp->elts[2].symbol->print_name (),
-			     plongest (SYMBOL_VALUE (exp->elts[2].symbol)));
+			     sym->print_name (),
+			     plongest (SYMBOL_VALUE (sym)));
 		    }
-		  else if (SYMBOL_CLASS (exp->elts[2].symbol)
-			   == LOC_OPTIMIZED_OUT)
+		  else if (SYMBOL_CLASS (sym) == LOC_OPTIMIZED_OUT)
 		    {
 		      error (_("`%s' is optimized away "
 			       "and cannot be collected."),
-			     exp->elts[2].symbol->print_name ());
+			     sym->print_name ());
 		    }
 		}
 
@@ -1384,7 +1395,16 @@ encode_actions_1 (struct command_line *action,
 		    {
 		    case OP_REGISTER:
 		      {
-			const char *name = &exp->elts[2].string;
+			const char *name;
+			if (exp->op != nullptr)
+			  {
+			    expr::register_operation *regop
+			      = (dynamic_cast<expr::register_operation *>
+				 (exp->op.get ()));
+			    name = regop->get_name ();
+			  }
+			else
+			  name = &exp->elts[2].string;
 
 			i = user_reg_map_name_to_regnum (target_gdbarch (),
 							 name, strlen (name));
@@ -1400,25 +1420,47 @@ encode_actions_1 (struct command_line *action,
 		      }
 
 		    case UNOP_MEMVAL:
-		      /* Safe because we know it's a simple expression.  */
-		      tempval = evaluate_expression (exp.get ());
-		      addr = value_address (tempval);
-		      /* Initialize the TYPE_LENGTH if it is a typedef.  */
-		      check_typedef (exp->elts[1].type);
-		      collect->add_memrange (target_gdbarch (),
-					     memrange_absolute, addr,
-					     TYPE_LENGTH (exp->elts[1].type),
-					     tloc->address);
-		      collect->append_exp (std::string (exp_start,
-							action_exp));
+		      {
+			/* Safe because we know it's a simple expression.  */
+			tempval = evaluate_expression (exp.get ());
+			addr = value_address (tempval);
+			struct type *type;
+			if (exp->op != nullptr)
+			  {
+			    expr::unop_memval_operation *memop
+			      = (dynamic_cast<expr::unop_memval_operation *>
+				 (exp->op.get ()));
+			    type = memop->get_type ();
+			  }
+			else
+			  type = exp->elts[1].type;
+			/* Initialize the TYPE_LENGTH if it is a typedef.  */
+			check_typedef (type);
+			collect->add_memrange (target_gdbarch (),
+					       memrange_absolute, addr,
+					       TYPE_LENGTH (type),
+					       tloc->address);
+			collect->append_exp (std::string (exp_start,
+							  action_exp));
+		      }
 		      break;
 
 		    case OP_VAR_VALUE:
 		      {
-			struct symbol *sym = exp->elts[2].symbol;
+			struct symbol *sym;
+
+			if (exp->op != nullptr)
+			  {
+			    expr::var_value_operation *vvo
+			      = (dynamic_cast<expr::var_value_operation *>
+				 (exp->op.get ()));
+			    sym = vvo->get_symbol ();
+			  }
+			else
+			  sym = exp->elts[2].symbol;
 			const char *name = sym->natural_name ();
 
-			collect->collect_symbol (exp->elts[2].symbol,
+			collect->collect_symbol (sym,
 						 target_gdbarch (),
 						 frame_reg,
 						 frame_offset,
diff --git a/gdb/value.c b/gdb/value.c
index a20ae5af4f0..806c5449052 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -44,6 +44,7 @@
 #include "gdbsupport/selftest.h"
 #include "gdbsupport/array-view.h"
 #include "cli/cli-style.h"
+#include "expop.h"
 
 /* Definition of a user function.  */
 struct internal_function
@@ -1973,7 +1974,7 @@ static struct internalvar *internalvars;
 static void
 init_if_undefined_command (const char* args, int from_tty)
 {
-  struct internalvar* intvar;
+  struct internalvar *intvar = nullptr;
 
   /* Parse the expression - this is taken from set_command().  */
   expression_up expr = parse_expression (args);
@@ -1981,15 +1982,34 @@ init_if_undefined_command (const char* args, int from_tty)
   /* Validate the expression.
      Was the expression an assignment?
      Or even an expression at all?  */
-  if (expr->nelts == 0 || expr->first_opcode () != BINOP_ASSIGN)
+  if ((expr->nelts == 0 && expr->op == nullptr)
+      || expr->first_opcode () != BINOP_ASSIGN)
     error (_("Init-if-undefined requires an assignment expression."));
 
   /* Extract the variable from the parsed expression.
      In the case of an assign the lvalue will be in elts[1] and elts[2].  */
-  if (expr->elts[1].opcode != OP_INTERNALVAR)
+  if (expr->op == nullptr)
+    {
+      if (expr->elts[1].opcode == OP_INTERNALVAR)
+	intvar = expr->elts[2].internalvar;
+    }
+  else
+    {
+      expr::assign_operation *assign
+	= dynamic_cast<expr::assign_operation *> (expr->op.get ());
+      if (assign != nullptr)
+	{
+	  expr::operation *lhs = assign->get_lhs ();
+	  expr::internalvar_operation *ivarop
+	    = dynamic_cast<expr::internalvar_operation *> (lhs);
+	  if (ivarop != nullptr)
+	    intvar = ivarop->get_internalvar ();
+	}
+    }
+
+  if (intvar == nullptr)
     error (_("The first parameter to init-if-undefined "
 	     "should be a GDB variable."));
-  intvar = expr->elts[2].internalvar;
 
   /* Only evaluate the expression if the lvalue is void.
      This may still fail if the expression is invalid.  */
diff --git a/gdb/value.h b/gdb/value.h
index 7bf5654ae43..7075a08d653 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -932,7 +932,9 @@ extern value *evaluate_var_msym_value (enum noside noside,
 
 extern value *eval_skip_value (expression *exp);
 
+namespace expr { class operation; };
 extern void fetch_subexp_value (struct expression *exp, int *pc,
+				expr::operation *op,
 				struct value **valp, struct value **resultp,
 				std::vector<value_ref_ptr> *val_chain,
 				bool preserve_errors);
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 173/203] Add completion for operations
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (171 preceding siblings ...)
  2021-01-01 21:46 ` [PATCH 172/203] Add an expr::operation_up to struct expression Tom Tromey
@ 2021-01-01 21:46 ` Tom Tromey
  2021-01-01 21:46 ` [PATCH 174/203] Add operation-related methods to parser_state Tom Tromey
                   ` (30 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:46 UTC (permalink / raw)
  To: gdb-patches

This patch adds the necessary support for field name completion for
expressions using class operation.

This patch takes an approach similar to what is done today.  It might
be good, in the future, to change completion to be a method on the
base class, to enable context-sensitive completion in more areas.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* parser-defs.h (struct expr_completion_state) <expout_last_op>:
	New member.
	(struct parser_state) <mark_struct_expression>: New method.
	* parse.c (parser_state::mark_struct_expression): Update assert.
	(parser_state::mark_struct_expression): New method.
	(parser_state::mark_completion_tag): Update assert.
	(parse_expression_for_completion): Handle expout_last_op.
---
 gdb/ChangeLog     | 10 ++++++++++
 gdb/parse.c       | 26 ++++++++++++++++++++++++--
 gdb/parser-defs.h | 10 ++++++++++
 3 files changed, 44 insertions(+), 2 deletions(-)

diff --git a/gdb/parse.c b/gdb/parse.c
index 4c8eb14549b..24258eb2c27 100644
--- a/gdb/parse.c
+++ b/gdb/parse.c
@@ -507,10 +507,23 @@ parser_state::mark_struct_expression ()
 {
   gdb_assert (parse_completion
 	      && (m_completion_state.expout_tag_completion_type
-		  == TYPE_CODE_UNDEF));
+		  == TYPE_CODE_UNDEF)
+	      && m_completion_state.expout_last_op == nullptr);
   m_completion_state.expout_last_struct = expout_ptr;
 }
 
+/* See parser-defs.h.  */
+
+void
+parser_state::mark_struct_expression (expr::structop_base_operation *op)
+{
+  gdb_assert (parse_completion
+	      && (m_completion_state.expout_tag_completion_type
+		  == TYPE_CODE_UNDEF)
+	      && m_completion_state.expout_last_struct == -1);
+  m_completion_state.expout_last_op = op;
+}
+
 /* Indicate that the current parser invocation is completing a tag.
    TAG is the type code of the tag, and PTR and LENGTH represent the
    start of the tag name.  */
@@ -523,7 +536,8 @@ parser_state::mark_completion_tag (enum type_code tag, const char *ptr,
 	      && (m_completion_state.expout_tag_completion_type
 		  == TYPE_CODE_UNDEF)
 	      && m_completion_state.expout_completion_name == NULL
-	      && m_completion_state.expout_last_struct == -1);
+	      && m_completion_state.expout_last_struct == -1
+	      && m_completion_state.expout_last_op == nullptr);
   gdb_assert (tag == TYPE_CODE_UNION
 	      || tag == TYPE_CODE_STRUCT
 	      || tag == TYPE_CODE_ENUM);
@@ -1251,6 +1265,14 @@ parse_expression_for_completion (const char *string,
       return NULL;
     }
 
+  if (cstate.expout_last_op != nullptr)
+    {
+      expr::structop_base_operation *op = cstate.expout_last_op;
+      const std::string &fld = op->get_string ();
+      *name = make_unique_xstrdup (fld.c_str ());
+      return value_type (op->evaluate_lhs (exp.get ()));
+    }
+
   if (cstate.expout_last_struct == -1)
     return NULL;
 
diff --git a/gdb/parser-defs.h b/gdb/parser-defs.h
index 9f1925d463a..f4cce3dfb91 100644
--- a/gdb/parser-defs.h
+++ b/gdb/parser-defs.h
@@ -93,6 +93,11 @@ struct expr_completion_state
      field name.  It is -1 if no dereference operation was found.  */
   int expout_last_struct = -1;
 
+  /* The last struct expression directly before a '.' or '->'.  This
+     is set when parsing and is only used when completing a field
+     name.  It is nullptr if no dereference operation was found.  */
+  expr::structop_base_operation *expout_last_op = nullptr;
+
   /* If we are completing a tagged type name, this will be nonzero.  */
   enum type_code expout_tag_completion_type = TYPE_CODE_UNDEF;
 
@@ -156,6 +161,11 @@ struct parser_state : public expr_builder
 
   void mark_struct_expression ();
 
+  /* Mark the given operation as the starting location of a structure
+     expression.  This is used when completing on field names.  */
+
+  void mark_struct_expression (expr::structop_base_operation *op);
+
   /* Indicate that the current parser invocation is completing a tag.
      TAG is the type code of the tag, and PTR and LENGTH represent the
      start of the tag name.  */
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 174/203] Add operation-related methods to parser_state
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (172 preceding siblings ...)
  2021-01-01 21:46 ` [PATCH 173/203] Add completion for operations Tom Tromey
@ 2021-01-01 21:46 ` Tom Tromey
  2021-01-01 21:46 ` [PATCH 175/203] Convert dtrace probes to use operations Tom Tromey
                   ` (29 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:46 UTC (permalink / raw)
  To: gdb-patches

This adds several operation-related methods to parser_state.  These
methods make it more convenient to change the parsers to be
operation-based.

Because byacc has poor support for C++, a stack of operations is added
to parser_state.  A parser can push operations, then later pop them
for combination into new operations.  This approach avoids the memory
leaks that would result if raw pointers were used in the parsers, at
the cost of parser productions not being type-safe (they can't
indicate that they return an operation).

This also introduces analogs of some write_exp functions, like
write_exp_string_vector, write_dollar_variable, and
write_exp_symbol_reference.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* parser-defs.h (struct parser_state) <push, push_new,
	push_c_string, push_symbol, push_dollar, pop, pop_vector, wrap,
	wrap2>: New methods.
	<m_operations>: New member.
	* parse.c (parser_state::push_c_string)
	(parser_state::push_symbol, parser_state::push_dollar): New
	methods.
---
 gdb/ChangeLog     |  10 ++++
 gdb/parse.c       | 124 ++++++++++++++++++++++++++++++++++++++++++++++
 gdb/parser-defs.h |  64 ++++++++++++++++++++++++
 3 files changed, 198 insertions(+)

diff --git a/gdb/parse.c b/gdb/parse.c
index 24258eb2c27..28ac43f0d16 100644
--- a/gdb/parse.c
+++ b/gdb/parse.c
@@ -545,6 +545,130 @@ parser_state::mark_completion_tag (enum type_code tag, const char *ptr,
   m_completion_state.expout_completion_name.reset (xstrndup (ptr, length));
 }
 
+/* See parser-defs.h.  */
+
+void
+parser_state::push_c_string (int kind, struct stoken_vector *vec)
+{
+  std::vector<std::string> data (vec->len);
+  for (int i = 0; i < vec->len; ++i)
+    data[i] = std::string (vec->tokens[i].ptr, vec->tokens[i].length);
+
+  push_new<expr::c_string_operation> ((enum c_string_type_values) kind,
+				      std::move (data));
+}
+
+/* See parser-defs.h.  */
+
+void
+parser_state::push_symbol (const char *name, struct symbol *sym)
+{
+  if (sym != nullptr)
+    push_new<expr::var_value_operation> (sym, nullptr);
+  else
+    {
+      struct bound_minimal_symbol msymbol = lookup_bound_minimal_symbol (name);
+      if (msymbol.minsym != NULL)
+	push_new<expr::var_msym_value_operation> (msymbol.minsym,
+						  msymbol.objfile);
+      else if (!have_full_symbols () && !have_partial_symbols ())
+	error (_("No symbol table is loaded.  Use the \"file\" command."));
+      else
+	error (_("No symbol \"%s\" in current context."),
+	       name);
+    }
+}
+
+/* See parser-defs.h.  */
+
+void
+parser_state::push_dollar (struct stoken str)
+{
+  struct block_symbol sym;
+  struct bound_minimal_symbol msym;
+  struct internalvar *isym = NULL;
+  std::string copy;
+
+  /* Handle the tokens $digits; also $ (short for $0) and $$ (short for $$1)
+     and $$digits (equivalent to $<-digits> if you could type that).  */
+
+  int negate = 0;
+  int i = 1;
+  /* Double dollar means negate the number and add -1 as well.
+     Thus $$ alone means -1.  */
+  if (str.length >= 2 && str.ptr[1] == '$')
+    {
+      negate = 1;
+      i = 2;
+    }
+  if (i == str.length)
+    {
+      /* Just dollars (one or two).  */
+      i = -negate;
+      goto handle_last;
+    }
+  /* Is the rest of the token digits?  */
+  for (; i < str.length; i++)
+    if (!(str.ptr[i] >= '0' && str.ptr[i] <= '9'))
+      break;
+  if (i == str.length)
+    {
+      i = atoi (str.ptr + 1 + negate);
+      if (negate)
+	i = -i;
+      goto handle_last;
+    }
+
+  /* Handle tokens that refer to machine registers:
+     $ followed by a register name.  */
+  i = user_reg_map_name_to_regnum (gdbarch (),
+				   str.ptr + 1, str.length - 1);
+  if (i >= 0)
+    goto handle_register;
+
+  /* Any names starting with $ are probably debugger internal variables.  */
+
+  copy = copy_name (str);
+  isym = lookup_only_internalvar (copy.c_str () + 1);
+  if (isym)
+    {
+      push_new<expr::internalvar_operation> (isym);
+      return;
+    }
+
+  /* On some systems, such as HP-UX and hppa-linux, certain system routines 
+     have names beginning with $ or $$.  Check for those, first.  */
+
+  sym = lookup_symbol (copy.c_str (), NULL, VAR_DOMAIN, NULL);
+  if (sym.symbol)
+    {
+      push_new<expr::var_value_operation> (sym.symbol, sym.block);
+      return;
+    }
+  msym = lookup_bound_minimal_symbol (copy.c_str ());
+  if (msym.minsym)
+    {
+      push_new<expr::var_msym_value_operation> (msym.minsym, msym.objfile);
+      return;
+    }
+
+  /* Any other names are assumed to be debugger internal variables.  */
+
+  push_new<expr::internalvar_operation>
+    (create_internalvar (copy.c_str () + 1));
+  return;
+handle_last:
+  push_new<expr::last_operation> (i);
+  return;
+handle_register:
+  str.length--;
+  str.ptr++;
+  push_new<expr::register_operation> (copy_name (str));
+  block_tracker->update (expression_context_block,
+			 INNERMOST_BLOCK_FOR_REGISTERS);
+  return;
+}
+
 \f
 /* Recognize tokens that start with '$'.  These include:
 
diff --git a/gdb/parser-defs.h b/gdb/parser-defs.h
index f4cce3dfb91..8ddbac2c134 100644
--- a/gdb/parser-defs.h
+++ b/gdb/parser-defs.h
@@ -25,6 +25,7 @@
 
 #include "expression.h"
 #include "symtab.h"
+#include "expop.h"
 
 struct block;
 struct language_defn;
@@ -172,6 +173,66 @@ struct parser_state : public expr_builder
 
   void mark_completion_tag (enum type_code tag, const char *ptr, int length);
 
+  /* Push an operation on the stack.  */
+  void push (expr::operation_up &&op)
+  {
+    m_operations.push_back (std::move (op));
+  }
+
+  /* Create a new operation and push it on the stack.  */
+  template<typename T, typename... Arg>
+  void push_new (Arg... args)
+  {
+    m_operations.emplace_back (new T (std::forward<Arg> (args)...));
+  }
+
+  /* Push a new C string operation.  */
+  void push_c_string (int, struct stoken_vector *vec);
+
+  /* Push a symbol reference.  If SYM is nullptr, look for a minimal
+     symbol.  */
+  void push_symbol (const char *name, struct symbol *sym);
+
+  /* Push a reference to $mumble.  This may result in a convenience
+     variable, a history reference, or a register.  */
+  void push_dollar (struct stoken str);
+
+  /* Pop an operation from the stack.  */
+  expr::operation_up pop ()
+  {
+    expr::operation_up result = std::move (m_operations.back ());
+    m_operations.pop_back ();
+    return result;
+  }
+
+  /* Pop N elements from the stack and return a vector.  */
+  std::vector<expr::operation_up> pop_vector (int n)
+  {
+    std::vector<expr::operation_up> result (n);
+    for (int i = 1; i <= n; ++i)
+      result[n - i] = pop ();
+    return result;
+  }
+
+  /* A helper that pops an operation, wraps it in some other
+     operation, and pushes it again.  */
+  template<typename T>
+  void wrap ()
+  {
+    using namespace expr;
+    operation_up v = ::expr::make_operation<T> (pop ());
+    push (std::move (v));
+  }
+
+  /* A helper that pops two operations, wraps them in some other
+     operation, and pushes the result.  */
+  template<typename T>
+  void wrap2 ()
+  {
+    expr::operation_up rhs = pop ();
+    expr::operation_up lhs = pop ();
+    push (expr::make_operation<T> (std::move (lhs), std::move (rhs)));
+  }
 
   /* If this is nonzero, this block is used as the lexical context for
      symbol names.  */
@@ -220,6 +281,9 @@ struct parser_state : public expr_builder
      arguments contain other function calls.  */
 
   std::vector<int> m_funcall_chain;
+
+  /* Stack of operations.  */
+  std::vector<expr::operation_up> m_operations;
 };
 
 /* When parsing expressions we track the innermost block that was
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 175/203] Convert dtrace probes to use operations
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (173 preceding siblings ...)
  2021-01-01 21:46 ` [PATCH 174/203] Add operation-related methods to parser_state Tom Tromey
@ 2021-01-01 21:46 ` Tom Tromey
  2021-01-01 21:46 ` [PATCH 176/203] Convert stap probes to create operations Tom Tromey
                   ` (28 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:46 UTC (permalink / raw)
  To: gdb-patches

This changes dtrace to use the new operation type.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* gdbarch.sh (dtrace_parse_probe_argument): Change return type.
	* gdbarch.h: Rebuild.
	* gdbarch.c: Rebuild.
	* dtrace-probe.c (dtrace_probe::build_arg_exprs): Update.
	* amd64-linux-tdep.c (amd64_dtrace_parse_probe_argument): Change
	return type.
	(amd64_dtrace_parse_probe_argument): Update.
---
 gdb/ChangeLog          | 10 ++++++++++
 gdb/amd64-linux-tdep.c | 39 ++++++++++++++-------------------------
 gdb/dtrace-probe.c     | 13 ++++++-------
 gdb/gdbarch.c          |  6 +++---
 gdb/gdbarch.h          |  4 ++--
 gdb/gdbarch.sh         |  2 +-
 6 files changed, 36 insertions(+), 38 deletions(-)

diff --git a/gdb/amd64-linux-tdep.c b/gdb/amd64-linux-tdep.c
index f65ac4e4357..709c839cefa 100644
--- a/gdb/amd64-linux-tdep.c
+++ b/gdb/amd64-linux-tdep.c
@@ -41,6 +41,7 @@
 #include "glibc-tdep.h"
 #include "arch/amd64.h"
 #include "target-descriptions.h"
+#include "expop.h"
 
 /* The syscall's XML filename for i386.  */
 #define XML_SYSCALL_FILENAME_AMD64 "syscalls/amd64-linux.xml"
@@ -1733,17 +1734,16 @@ amd64_dtrace_disable_probe (struct gdbarch *gdbarch, CORE_ADDR addr)
 /* Implementation of `gdbarch_dtrace_parse_probe_argument', as defined
    in gdbarch.h.  */
 
-static void
+static expr::operation_up
 amd64_dtrace_parse_probe_argument (struct gdbarch *gdbarch,
-				   struct expr_builder *builder,
 				   int narg)
 {
-  struct stoken str;
-
   /* DTrace probe arguments can be found on the ABI-defined places for
      regular arguments at the current PC.  The probe abstraction
      currently supports up to 12 arguments for probes.  */
 
+  using namespace expr;
+
   if (narg < 6)
     {
       static const int arg_reg_map[6] =
@@ -1757,12 +1757,7 @@ amd64_dtrace_parse_probe_argument (struct gdbarch *gdbarch,
 	};
       int regno = arg_reg_map[narg];
       const char *regname = user_reg_map_regnum_to_name (gdbarch, regno);
-
-      write_exp_elt_opcode (builder, OP_REGISTER);
-      str.ptr = regname;
-      str.length = strlen (regname);
-      write_exp_string (builder, str);
-      write_exp_elt_opcode (builder, OP_REGISTER);
+      return make_operation<register_operation> (regname);
     }
   else
     {
@@ -1770,27 +1765,21 @@ amd64_dtrace_parse_probe_argument (struct gdbarch *gdbarch,
       const char *regname = user_reg_map_regnum_to_name (gdbarch, AMD64_RSP_REGNUM);
 
       /* Displacement.  */
-      write_exp_elt_opcode (builder, OP_LONG);
-      write_exp_elt_type (builder, builtin_type (gdbarch)->builtin_long);
-      write_exp_elt_longcst (builder, narg - 6);
-      write_exp_elt_opcode (builder, OP_LONG);
+      struct type *long_type = builtin_type (gdbarch)->builtin_long;
+      operation_up disp	= make_operation<long_const_operation> (long_type,
+								narg - 6);
 
       /* Register: SP.  */
-      write_exp_elt_opcode (builder, OP_REGISTER);
-      str.ptr = regname;
-      str.length = strlen (regname);
-      write_exp_string (builder, str);
-      write_exp_elt_opcode (builder, OP_REGISTER);
+      operation_up reg = make_operation<register_operation> (regname);
 
-      write_exp_elt_opcode (builder, BINOP_ADD);
+      operation_up add = make_operation<add_operation> (std::move (disp),
+							std::move (reg));
 
       /* Cast to long. */
-      write_exp_elt_opcode (builder, UNOP_CAST);
-      write_exp_elt_type (builder,
-			  lookup_pointer_type (builtin_type (gdbarch)->builtin_long));
-      write_exp_elt_opcode (builder, UNOP_CAST);
+      operation_up cast = make_operation<unop_cast_operation> (std::move (add),
+							       long_type);
 
-      write_exp_elt_opcode (builder, UNOP_IND);
+      return make_operation<unop_ind_operation> (std::move (cast));
     }
 }
 
diff --git a/gdb/dtrace-probe.c b/gdb/dtrace-probe.c
index f4b6becbf61..3fa02ddaebe 100644
--- a/gdb/dtrace-probe.c
+++ b/gdb/dtrace-probe.c
@@ -32,6 +32,7 @@
 #include "language.h"
 #include "parser-defs.h"
 #include "inferior.h"
+#include "expop.h"
 
 /* The type of the ELF sections where we will find the DOF programs
    with information about probes.  */
@@ -629,20 +630,18 @@ dtrace_probe::build_arg_exprs (struct gdbarch *gdbarch)
 
       /* The argument value, which is ABI dependent and casted to
 	 `long int'.  */
-      gdbarch_dtrace_parse_probe_argument (gdbarch, &builder, argc);
+      expr::operation_up op = gdbarch_dtrace_parse_probe_argument (gdbarch,
+								   argc);
 
       /* Casting to the expected type, but only if the type was
 	 recognized at probe load time.  Otherwise the argument will
 	 be evaluated as the long integer passed to the probe.  */
       if (arg.type != NULL)
-	{
-	  write_exp_elt_opcode (&builder, UNOP_CAST);
-	  write_exp_elt_type (&builder, arg.type);
-	  write_exp_elt_opcode (&builder, UNOP_CAST);
-	}
+	op = expr::make_operation<expr::unop_cast_operation> (std::move (op),
+							      arg.type);
 
+      builder.set_operation (std::move (op));
       arg.expr = builder.release ();
-      prefixify_expression (arg.expr.get ());
       ++argc;
     }
 }
diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c
index 4bdf4068504..af95aa01cbd 100644
--- a/gdb/gdbarch.c
+++ b/gdb/gdbarch.c
@@ -4637,14 +4637,14 @@ gdbarch_dtrace_parse_probe_argument_p (struct gdbarch *gdbarch)
   return gdbarch->dtrace_parse_probe_argument != NULL;
 }
 
-void
-gdbarch_dtrace_parse_probe_argument (struct gdbarch *gdbarch, struct expr_builder *builder, int narg)
+expr::operation_up
+gdbarch_dtrace_parse_probe_argument (struct gdbarch *gdbarch, int narg)
 {
   gdb_assert (gdbarch != NULL);
   gdb_assert (gdbarch->dtrace_parse_probe_argument != NULL);
   if (gdbarch_debug >= 2)
     fprintf_unfiltered (gdb_stdlog, "gdbarch_dtrace_parse_probe_argument called\n");
-  gdbarch->dtrace_parse_probe_argument (gdbarch, builder, narg);
+  return gdbarch->dtrace_parse_probe_argument (gdbarch, narg);
 }
 
 void
diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h
index 2fef567c06f..3b9d8da4f61 100644
--- a/gdb/gdbarch.h
+++ b/gdb/gdbarch.h
@@ -1386,8 +1386,8 @@ extern void set_gdbarch_stap_adjust_register (struct gdbarch *gdbarch, gdbarch_s
 
 extern bool gdbarch_dtrace_parse_probe_argument_p (struct gdbarch *gdbarch);
 
-typedef void (gdbarch_dtrace_parse_probe_argument_ftype) (struct gdbarch *gdbarch, struct expr_builder *builder, int narg);
-extern void gdbarch_dtrace_parse_probe_argument (struct gdbarch *gdbarch, struct expr_builder *builder, int narg);
+typedef expr::operation_up (gdbarch_dtrace_parse_probe_argument_ftype) (struct gdbarch *gdbarch, int narg);
+extern expr::operation_up gdbarch_dtrace_parse_probe_argument (struct gdbarch *gdbarch, int narg);
 extern void set_gdbarch_dtrace_parse_probe_argument (struct gdbarch *gdbarch, gdbarch_dtrace_parse_probe_argument_ftype *dtrace_parse_probe_argument);
 
 /* True if the given ADDR does not contain the instruction sequence
diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh
index e7c96159241..d68d3b7a425 100755
--- a/gdb/gdbarch.sh
+++ b/gdb/gdbarch.sh
@@ -1025,7 +1025,7 @@ M;std::string;stap_adjust_register;struct stap_parse_info *p, const std::string
 
 # The expression to compute the NARTGth+1 argument to a DTrace USDT probe.
 # NARG must be >= 0.
-M;void;dtrace_parse_probe_argument;struct expr_builder *builder, int narg;builder, narg
+M;expr::operation_up;dtrace_parse_probe_argument;int narg;narg
 
 # True if the given ADDR does not contain the instruction sequence
 # corresponding to a disabled DTrace is-enabled probe.
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 176/203] Convert stap probes to create operations
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (174 preceding siblings ...)
  2021-01-01 21:46 ` [PATCH 175/203] Convert dtrace probes to use operations Tom Tromey
@ 2021-01-01 21:46 ` Tom Tromey
  2021-01-01 21:46 ` [PATCH 177/203] Convert rust-exp.y to use operations Tom Tromey
                   ` (27 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:46 UTC (permalink / raw)
  To: gdb-patches

This changes the stap probe code to create operations, rather than
exp_elements.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* stap-probe.c (binop_maker_ftype): New typedef.
	(stap_maker_map): New global.
	(stap_make_binop): New function.
	(stap_parse_register_operand): Return operation_up.
	(stap_parse_single_operand, stap_parse_argument_conditionally)
	(stap_parse_argument_1): Likewise.
	(stap_parse_argument): Create operations.
	(stap_probe::parse_arguments): Update.
	(_initialize_stap_probe): Initialize stap_maker_map.
	* ppc-linux-tdep.c (ppc_stap_parse_special_token): Change return
	type.
	* i386-tdep.h (i386_stap_parse_special_token): Change return
	type.
	* i386-tdep.c (i386_stap_parse_special_token_triplet)
	(i386_stap_parse_special_token_three_arg_disp)
	(i386_stap_parse_special_token): Change return type.
	* gdbarch.sh (stap_parse_special_token): Change return type.
	* gdbarch.c: Rebuild.
	* gdbarch.h: Rebuild.
	* arm-linux-tdep.c (arm_stap_parse_special_token): Change return
	type.
	* aarch64-linux-tdep.c (aarch64_stap_parse_special_token): Change
	return type.
---
 gdb/ChangeLog            |  26 +++++
 gdb/aarch64-linux-tdep.c |  58 +++++------
 gdb/arm-linux-tdep.c     |  45 ++++----
 gdb/gdbarch.c            |   2 +-
 gdb/gdbarch.h            |   4 +-
 gdb/gdbarch.sh           |   2 +-
 gdb/i386-tdep.c          | 214 +++++++++++++++------------------------
 gdb/i386-tdep.h          |   5 +-
 gdb/ppc-linux-tdep.c     |  24 ++---
 gdb/stap-probe.c         | 185 +++++++++++++++++++--------------
 10 files changed, 275 insertions(+), 290 deletions(-)

diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
index 4c2caf8e05b..75ce4a06139 100644
--- a/gdb/aarch64-linux-tdep.c
+++ b/gdb/aarch64-linux-tdep.c
@@ -31,6 +31,7 @@
 #include "tramp-frame.h"
 #include "trad-frame.h"
 #include "target/target.h"
+#include "expop.h"
 
 #include "regcache.h"
 #include "regset.h"
@@ -753,7 +754,7 @@ aarch64_stap_is_single_operand (struct gdbarch *gdbarch, const char *s)
    It returns one if the special token has been parsed successfully,
    or zero if the current token is not considered special.  */
 
-static int
+static expr::operation_up
 aarch64_stap_parse_special_token (struct gdbarch *gdbarch,
 				  struct stap_parse_info *p)
 {
@@ -764,11 +765,9 @@ aarch64_stap_parse_special_token (struct gdbarch *gdbarch,
       char *endp;
       /* Used to save the register name.  */
       const char *start;
-      char *regname;
       int len;
       int got_minus = 0;
       long displacement;
-      struct stoken str;
 
       ++tmp;
       start = tmp;
@@ -778,17 +777,14 @@ aarch64_stap_parse_special_token (struct gdbarch *gdbarch,
 	++tmp;
 
       if (*tmp != ',')
-	return 0;
+	return {};
 
       len = tmp - start;
-      regname = (char *) alloca (len + 2);
-
-      strncpy (regname, start, len);
-      regname[len] = '\0';
+      std::string regname (start, len);
 
-      if (user_reg_map_name_to_regnum (gdbarch, regname, len) == -1)
+      if (user_reg_map_name_to_regnum (gdbarch, regname.c_str (), len) == -1)
 	error (_("Invalid register name `%s' on expression `%s'."),
-	       regname, p->saved_arg);
+	       regname.c_str (), p->saved_arg);
 
       ++tmp;
       tmp = skip_spaces (tmp);
@@ -806,45 +802,39 @@ aarch64_stap_parse_special_token (struct gdbarch *gdbarch,
 	++tmp;
 
       if (!isdigit (*tmp))
-	return 0;
+	return {};
 
       displacement = strtol (tmp, &endp, 10);
       tmp = endp;
 
       /* Skipping last `]'.  */
       if (*tmp++ != ']')
-	return 0;
+	return {};
+      p->arg = tmp;
+
+      using namespace expr;
 
       /* The displacement.  */
-      write_exp_elt_opcode (&p->pstate, OP_LONG);
-      write_exp_elt_type (&p->pstate, builtin_type (gdbarch)->builtin_long);
-      write_exp_elt_longcst (&p->pstate, displacement);
-      write_exp_elt_opcode (&p->pstate, OP_LONG);
+      struct type *long_type = builtin_type (gdbarch)->builtin_long;
       if (got_minus)
-	write_exp_elt_opcode (&p->pstate, UNOP_NEG);
+	displacement = -displacement;
+      operation_up disp = make_operation<long_const_operation> (long_type,
+								displacement);
 
       /* The register name.  */
-      write_exp_elt_opcode (&p->pstate, OP_REGISTER);
-      str.ptr = regname;
-      str.length = len;
-      write_exp_string (&p->pstate, str);
-      write_exp_elt_opcode (&p->pstate, OP_REGISTER);
+      operation_up reg
+	= make_operation<register_operation> (std::move (regname));
 
-      write_exp_elt_opcode (&p->pstate, BINOP_ADD);
+      operation_up sum
+	= make_operation<add_operation> (std::move (reg), std::move (disp));
 
       /* Casting to the expected type.  */
-      write_exp_elt_opcode (&p->pstate, UNOP_CAST);
-      write_exp_elt_type (&p->pstate, lookup_pointer_type (p->arg_type));
-      write_exp_elt_opcode (&p->pstate, UNOP_CAST);
-
-      write_exp_elt_opcode (&p->pstate, UNOP_IND);
-
-      p->arg = tmp;
+      struct type *arg_ptr_type = lookup_pointer_type (p->arg_type);
+      sum = make_operation<unop_cast_operation> (std::move (sum),
+						 arg_ptr_type);
+      return make_operation<unop_ind_operation> (std::move (sum));
     }
-  else
-    return 0;
-
-  return 1;
+  return {};
 }
 
 /* AArch64 process record-replay constructs: syscall, signal etc.  */
diff --git a/gdb/arm-linux-tdep.c b/gdb/arm-linux-tdep.c
index ada7f113746..5522cfe7946 100644
--- a/gdb/arm-linux-tdep.c
+++ b/gdb/arm-linux-tdep.c
@@ -32,6 +32,7 @@
 #include "breakpoint.h"
 #include "auxv.h"
 #include "xml-syscall.h"
+#include "expop.h"
 
 #include "aarch32-tdep.h"
 #include "arch/arm.h"
@@ -1146,7 +1147,7 @@ arm_stap_is_single_operand (struct gdbarch *gdbarch, const char *s)
    It returns one if the special token has been parsed successfully,
    or zero if the current token is not considered special.  */
 
-static int
+static expr::operation_up
 arm_stap_parse_special_token (struct gdbarch *gdbarch,
 			      struct stap_parse_info *p)
 {
@@ -1161,7 +1162,6 @@ arm_stap_parse_special_token (struct gdbarch *gdbarch,
       int len, offset;
       int got_minus = 0;
       long displacement;
-      struct stoken str;
 
       ++tmp;
       start = tmp;
@@ -1171,7 +1171,7 @@ arm_stap_parse_special_token (struct gdbarch *gdbarch,
 	++tmp;
 
       if (*tmp != ',')
-	return 0;
+	return {};
 
       len = tmp - start;
       regname = (char *) alloca (len + 2);
@@ -1212,38 +1212,33 @@ arm_stap_parse_special_token (struct gdbarch *gdbarch,
 
       /* Skipping last `]'.  */
       if (*tmp++ != ']')
-	return 0;
+	return {};
+      p->arg = tmp;
+
+      using namespace expr;
 
       /* The displacement.  */
-      write_exp_elt_opcode (&p->pstate, OP_LONG);
-      write_exp_elt_type (&p->pstate, builtin_type (gdbarch)->builtin_long);
-      write_exp_elt_longcst (&p->pstate, displacement);
-      write_exp_elt_opcode (&p->pstate, OP_LONG);
+      struct type *long_type = builtin_type (gdbarch)->builtin_long;
       if (got_minus)
-	write_exp_elt_opcode (&p->pstate, UNOP_NEG);
+	displacement = -displacement;
+      operation_up disp = make_operation<long_const_operation> (long_type,
+								displacement);
 
       /* The register name.  */
-      write_exp_elt_opcode (&p->pstate, OP_REGISTER);
-      str.ptr = regname;
-      str.length = len;
-      write_exp_string (&p->pstate, str);
-      write_exp_elt_opcode (&p->pstate, OP_REGISTER);
+      operation_up reg
+	= make_operation<register_operation> (regname);
 
-      write_exp_elt_opcode (&p->pstate, BINOP_ADD);
+      operation_up sum
+	= make_operation<add_operation> (std::move (reg), std::move (disp));
 
       /* Casting to the expected type.  */
-      write_exp_elt_opcode (&p->pstate, UNOP_CAST);
-      write_exp_elt_type (&p->pstate, lookup_pointer_type (p->arg_type));
-      write_exp_elt_opcode (&p->pstate, UNOP_CAST);
-
-      write_exp_elt_opcode (&p->pstate, UNOP_IND);
-
-      p->arg = tmp;
+      struct type *arg_ptr_type = lookup_pointer_type (p->arg_type);
+      sum = make_operation<unop_cast_operation> (std::move (sum),
+						 arg_ptr_type);
+      return make_operation<unop_ind_operation> (std::move (sum));
     }
-  else
-    return 0;
 
-  return 1;
+  return {};
 }
 
 /* ARM process record-replay constructs: syscall, signal etc.  */
diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c
index af95aa01cbd..10fd9639645 100644
--- a/gdb/gdbarch.c
+++ b/gdb/gdbarch.c
@@ -4589,7 +4589,7 @@ gdbarch_stap_parse_special_token_p (struct gdbarch *gdbarch)
   return gdbarch->stap_parse_special_token != NULL;
 }
 
-int
+expr::operation_up
 gdbarch_stap_parse_special_token (struct gdbarch *gdbarch, struct stap_parse_info *p)
 {
   gdb_assert (gdbarch != NULL);
diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h
index 3b9d8da4f61..342c29c5980 100644
--- a/gdb/gdbarch.h
+++ b/gdb/gdbarch.h
@@ -1346,8 +1346,8 @@ extern void set_gdbarch_stap_is_single_operand (struct gdbarch *gdbarch, gdbarch
 
 extern bool gdbarch_stap_parse_special_token_p (struct gdbarch *gdbarch);
 
-typedef int (gdbarch_stap_parse_special_token_ftype) (struct gdbarch *gdbarch, struct stap_parse_info *p);
-extern int gdbarch_stap_parse_special_token (struct gdbarch *gdbarch, struct stap_parse_info *p);
+typedef expr::operation_up (gdbarch_stap_parse_special_token_ftype) (struct gdbarch *gdbarch, struct stap_parse_info *p);
+extern expr::operation_up gdbarch_stap_parse_special_token (struct gdbarch *gdbarch, struct stap_parse_info *p);
 extern void set_gdbarch_stap_parse_special_token (struct gdbarch *gdbarch, gdbarch_stap_parse_special_token_ftype *stap_parse_special_token);
 
 /* Perform arch-dependent adjustments to a register name.
diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh
index d68d3b7a425..84b645e9915 100755
--- a/gdb/gdbarch.sh
+++ b/gdb/gdbarch.sh
@@ -994,7 +994,7 @@ M;int;stap_is_single_operand;const char *s;s
 # if the token was not recognized as a special token (in this case, returning
 # zero means that the special parser is deferring the parsing to the generic
 # parser), and should advance the buffer pointer (p->arg).
-M;int;stap_parse_special_token;struct stap_parse_info *p;p
+M;expr::operation_up;stap_parse_special_token;struct stap_parse_info *p;p
 
 # Perform arch-dependent adjustments to a register name.
 #
diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c
index 1a3017224ae..a23c3d54167 100644
--- a/gdb/i386-tdep.c
+++ b/gdb/i386-tdep.c
@@ -48,6 +48,7 @@
 #include "i387-tdep.h"
 #include "gdbsupport/x86-xstate.h"
 #include "x86-tdep.h"
+#include "expop.h"
 
 #include "record.h"
 #include "record-full.h"
@@ -4067,7 +4068,7 @@ i386_stap_is_single_operand (struct gdbarch *gdbarch, const char *s)
    Return true if the operand was parsed successfully, false
    otherwise.  */
 
-static bool
+static expr::operation_up
 i386_stap_parse_special_token_triplet (struct gdbarch *gdbarch,
 				       struct stap_parse_info *p)
 {
@@ -4079,9 +4080,7 @@ i386_stap_parse_special_token_triplet (struct gdbarch *gdbarch,
       int i;
       long displacements[3];
       const char *start;
-      char *regname;
       int len;
-      struct stoken str;
       char *endp;
 
       got_minus[0] = false;
@@ -4094,7 +4093,7 @@ i386_stap_parse_special_token_triplet (struct gdbarch *gdbarch,
 	}
 
       if (!isdigit ((unsigned char) *s))
-	return false;
+	return {};
 
       displacements[0] = strtol (s, &endp, 10);
       s = endp;
@@ -4102,7 +4101,7 @@ i386_stap_parse_special_token_triplet (struct gdbarch *gdbarch,
       if (*s != '+' && *s != '-')
 	{
 	  /* We are not dealing with a triplet.  */
-	  return false;
+	  return {};
 	}
 
       got_minus[1] = false;
@@ -4115,7 +4114,7 @@ i386_stap_parse_special_token_triplet (struct gdbarch *gdbarch,
 	}
 
       if (!isdigit ((unsigned char) *s))
-	return false;
+	return {};
 
       displacements[1] = strtol (s, &endp, 10);
       s = endp;
@@ -4123,7 +4122,7 @@ i386_stap_parse_special_token_triplet (struct gdbarch *gdbarch,
       if (*s != '+' && *s != '-')
 	{
 	  /* We are not dealing with a triplet.  */
-	  return false;
+	  return {};
 	}
 
       got_minus[2] = false;
@@ -4136,13 +4135,13 @@ i386_stap_parse_special_token_triplet (struct gdbarch *gdbarch,
 	}
 
       if (!isdigit ((unsigned char) *s))
-	return false;
+	return {};
 
       displacements[2] = strtol (s, &endp, 10);
       s = endp;
 
       if (*s != '(' || s[1] != '%')
-	return false;
+	return {};
 
       s += 2;
       start = s;
@@ -4151,57 +4150,46 @@ i386_stap_parse_special_token_triplet (struct gdbarch *gdbarch,
 	++s;
 
       if (*s++ != ')')
-	return false;
+	return {};
 
       len = s - start - 1;
-      regname = (char *) alloca (len + 1);
-
-      strncpy (regname, start, len);
-      regname[len] = '\0';
+      std::string regname (start, len);
 
-      if (user_reg_map_name_to_regnum (gdbarch, regname, len) == -1)
+      if (user_reg_map_name_to_regnum (gdbarch, regname.c_str (), len) == -1)
 	error (_("Invalid register name `%s' on expression `%s'."),
-	       regname, p->saved_arg);
+	       regname.c_str (), p->saved_arg);
 
+      LONGEST value = 0;
       for (i = 0; i < 3; i++)
 	{
-	  write_exp_elt_opcode (&p->pstate, OP_LONG);
-	  write_exp_elt_type
-	    (&p->pstate, builtin_type (gdbarch)->builtin_long);
-	  write_exp_elt_longcst (&p->pstate, displacements[i]);
-	  write_exp_elt_opcode (&p->pstate, OP_LONG);
+	  LONGEST this_val = displacements[i];
 	  if (got_minus[i])
-	    write_exp_elt_opcode (&p->pstate, UNOP_NEG);
+	    this_val = -this_val;
+	  value += this_val;
 	}
 
-      write_exp_elt_opcode (&p->pstate, OP_REGISTER);
-      str.ptr = regname;
-      str.length = len;
-      write_exp_string (&p->pstate, str);
-      write_exp_elt_opcode (&p->pstate, OP_REGISTER);
-
-      write_exp_elt_opcode (&p->pstate, UNOP_CAST);
-      write_exp_elt_type (&p->pstate,
-			  builtin_type (gdbarch)->builtin_data_ptr);
-      write_exp_elt_opcode (&p->pstate, UNOP_CAST);
-
-      write_exp_elt_opcode (&p->pstate, BINOP_ADD);
-      write_exp_elt_opcode (&p->pstate, BINOP_ADD);
-      write_exp_elt_opcode (&p->pstate, BINOP_ADD);
+      p->arg = s;
 
-      write_exp_elt_opcode (&p->pstate, UNOP_CAST);
-      write_exp_elt_type (&p->pstate,
-			  lookup_pointer_type (p->arg_type));
-      write_exp_elt_opcode (&p->pstate, UNOP_CAST);
+      using namespace expr;
 
-      write_exp_elt_opcode (&p->pstate, UNOP_IND);
+      struct type *long_type = builtin_type (gdbarch)->builtin_long;
+      operation_up offset
+	= make_operation<long_const_operation> (long_type, value);
 
-      p->arg = s;
+      operation_up reg
+	= make_operation<register_operation> (std::move (regname));
+      struct type *void_ptr = builtin_type (gdbarch)->builtin_data_ptr;
+      reg = make_operation<unop_cast_operation> (std::move (reg), void_ptr);
 
-      return true;
+      operation_up sum
+	= make_operation<add_operation> (std::move (reg), std::move (offset));
+      struct type *arg_ptr_type = lookup_pointer_type (p->arg_type);
+      sum = make_operation<unop_cast_operation> (std::move (sum),
+						 arg_ptr_type);
+      return make_operation<unop_ind_operation> (std::move (sum));
     }
 
-  return false;
+  return {};
 }
 
 /* Helper function for i386_stap_parse_special_token.
@@ -4213,7 +4201,7 @@ i386_stap_parse_special_token_triplet (struct gdbarch *gdbarch,
    Return true if the operand was parsed successfully, false
    otherwise.  */
 
-static bool
+static expr::operation_up
 i386_stap_parse_special_token_three_arg_disp (struct gdbarch *gdbarch,
 					      struct stap_parse_info *p)
 {
@@ -4226,11 +4214,8 @@ i386_stap_parse_special_token_three_arg_disp (struct gdbarch *gdbarch,
       bool size_minus = false;
       long size = 0;
       const char *start;
-      char *base;
       int len_base;
-      char *index;
       int len_index;
-      struct stoken base_token, index_token;
 
       if (*s == '+')
 	++s;
@@ -4241,7 +4226,7 @@ i386_stap_parse_special_token_three_arg_disp (struct gdbarch *gdbarch,
 	}
 
       if (offset_minus && !isdigit (*s))
-	return false;
+	return {};
 
       if (isdigit (*s))
 	{
@@ -4252,7 +4237,7 @@ i386_stap_parse_special_token_three_arg_disp (struct gdbarch *gdbarch,
 	}
 
       if (*s != '(' || s[1] != '%')
-	return false;
+	return {};
 
       s += 2;
       start = s;
@@ -4261,16 +4246,14 @@ i386_stap_parse_special_token_three_arg_disp (struct gdbarch *gdbarch,
 	++s;
 
       if (*s != ',' || s[1] != '%')
-	return false;
+	return {};
 
       len_base = s - start;
-      base = (char *) alloca (len_base + 1);
-      strncpy (base, start, len_base);
-      base[len_base] = '\0';
+      std::string base (start, len_base);
 
-      if (user_reg_map_name_to_regnum (gdbarch, base, len_base) == -1)
+      if (user_reg_map_name_to_regnum (gdbarch, base.c_str (), len_base) == -1)
 	error (_("Invalid register name `%s' on expression `%s'."),
-	       base, p->saved_arg);
+	       base.c_str (), p->saved_arg);
 
       s += 2;
       start = s;
@@ -4279,16 +4262,15 @@ i386_stap_parse_special_token_three_arg_disp (struct gdbarch *gdbarch,
 	++s;
 
       len_index = s - start;
-      index = (char *) alloca (len_index + 1);
-      strncpy (index, start, len_index);
-      index[len_index] = '\0';
+      std::string index (start, len_index);
 
-      if (user_reg_map_name_to_regnum (gdbarch, index, len_index) == -1)
+      if (user_reg_map_name_to_regnum (gdbarch, index.c_str (),
+				       len_index) == -1)
 	error (_("Invalid register name `%s' on expression `%s'."),
-	       index, p->saved_arg);
+	       index.c_str (), p->saved_arg);
 
       if (*s != ',' && *s != ')')
-	return false;
+	return {};
 
       if (*s == ',')
 	{
@@ -4307,85 +4289,60 @@ i386_stap_parse_special_token_three_arg_disp (struct gdbarch *gdbarch,
 	  s = endp;
 
 	  if (*s != ')')
-	    return false;
+	    return {};
 	}
 
       ++s;
+      p->arg = s;
 
-      if (offset)
+      using namespace expr;
+
+      struct type *long_type = builtin_type (gdbarch)->builtin_long;
+      operation_up reg = make_operation<register_operation> (std::move (base));
+
+      if (offset != 0)
 	{
-	  write_exp_elt_opcode (&p->pstate, OP_LONG);
-	  write_exp_elt_type (&p->pstate,
-			      builtin_type (gdbarch)->builtin_long);
-	  write_exp_elt_longcst (&p->pstate, offset);
-	  write_exp_elt_opcode (&p->pstate, OP_LONG);
 	  if (offset_minus)
-	    write_exp_elt_opcode (&p->pstate, UNOP_NEG);
+	    offset = -offset;
+	  operation_up value
+	    = make_operation<long_const_operation> (long_type, offset);
+	  reg = make_operation<add_operation> (std::move (reg),
+					       std::move (value));
 	}
 
-      write_exp_elt_opcode (&p->pstate, OP_REGISTER);
-      base_token.ptr = base;
-      base_token.length = len_base;
-      write_exp_string (&p->pstate, base_token);
-      write_exp_elt_opcode (&p->pstate, OP_REGISTER);
-
-      if (offset)
-	write_exp_elt_opcode (&p->pstate, BINOP_ADD);
-
-      write_exp_elt_opcode (&p->pstate, OP_REGISTER);
-      index_token.ptr = index;
-      index_token.length = len_index;
-      write_exp_string (&p->pstate, index_token);
-      write_exp_elt_opcode (&p->pstate, OP_REGISTER);
+      operation_up ind_reg
+	= make_operation<register_operation> (std::move (index));
 
-      if (size)
+      if (size != 0)
 	{
-	  write_exp_elt_opcode (&p->pstate, OP_LONG);
-	  write_exp_elt_type (&p->pstate,
-			      builtin_type (gdbarch)->builtin_long);
-	  write_exp_elt_longcst (&p->pstate, size);
-	  write_exp_elt_opcode (&p->pstate, OP_LONG);
 	  if (size_minus)
-	    write_exp_elt_opcode (&p->pstate, UNOP_NEG);
-	  write_exp_elt_opcode (&p->pstate, BINOP_MUL);
+	    size = -size;
+	  operation_up value
+	    = make_operation<long_const_operation> (long_type, size);
+	  ind_reg = make_operation<mul_operation> (std::move (ind_reg),
+						   std::move (value));
 	}
 
-      write_exp_elt_opcode (&p->pstate, BINOP_ADD);
-
-      write_exp_elt_opcode (&p->pstate, UNOP_CAST);
-      write_exp_elt_type (&p->pstate,
-			  lookup_pointer_type (p->arg_type));
-      write_exp_elt_opcode (&p->pstate, UNOP_CAST);
-
-      write_exp_elt_opcode (&p->pstate, UNOP_IND);
-
-      p->arg = s;
+      operation_up sum
+	= make_operation<add_operation> (std::move (reg),
+					 std::move (ind_reg));
 
-      return true;
+      struct type *arg_ptr_type = lookup_pointer_type (p->arg_type);
+      sum = make_operation<unop_cast_operation> (std::move (sum),
+						 arg_ptr_type);
+      return make_operation<unop_ind_operation> (std::move (sum));
     }
 
-  return false;
+  return {};
 }
 
 /* Implementation of `gdbarch_stap_parse_special_token', as defined in
    gdbarch.h.  */
 
-int
+expr::operation_up
 i386_stap_parse_special_token (struct gdbarch *gdbarch,
 			       struct stap_parse_info *p)
 {
-  /* In order to parse special tokens, we use a state-machine that go
-     through every known token and try to get a match.  */
-  enum
-    {
-      TRIPLET,
-      THREE_ARG_DISPLACEMENT,
-      DONE
-    };
-  int current_state;
-
-  current_state = TRIPLET;
-
   /* The special tokens to be parsed here are:
 
      - `register base + (register index * size) + offset', as represented
@@ -4394,26 +4351,13 @@ i386_stap_parse_special_token (struct gdbarch *gdbarch,
      - Operands of the form `-8+3+1(%rbp)', which must be interpreted as
      `*(-8 + 3 - 1 + (void *) $eax)'.  */
 
-  while (current_state != DONE)
-    {
-      switch (current_state)
-	{
-	case TRIPLET:
-	  if (i386_stap_parse_special_token_triplet (gdbarch, p))
-	    return 1;
-	  break;
+  expr::operation_up result
+    = i386_stap_parse_special_token_triplet (gdbarch, p);
 
-	case THREE_ARG_DISPLACEMENT:
-	  if (i386_stap_parse_special_token_three_arg_disp (gdbarch, p))
-	    return 1;
-	  break;
-	}
+  if (result == nullptr)
+    result = i386_stap_parse_special_token_three_arg_disp (gdbarch, p);
 
-      /* Advancing to the next state.  */
-      ++current_state;
-    }
-
-  return 0;
+  return result;
 }
 
 /* Implementation of 'gdbarch_stap_adjust_register', as defined in
diff --git a/gdb/i386-tdep.h b/gdb/i386-tdep.h
index fe0e1185674..ee7655e9861 100644
--- a/gdb/i386-tdep.h
+++ b/gdb/i386-tdep.h
@@ -22,6 +22,7 @@
 
 #include "gdbarch.h"
 #include "infrun.h"
+#include "expression.h"
 
 struct frame_info;
 struct gdbarch;
@@ -485,7 +486,7 @@ extern int i386bsd_sc_reg_offset[];
 extern int i386_stap_is_single_operand (struct gdbarch *gdbarch,
 					const char *s);
 
-extern int i386_stap_parse_special_token (struct gdbarch *gdbarch,
-					  struct stap_parse_info *p);
+extern expr::operation_up i386_stap_parse_special_token
+     (struct gdbarch *gdbarch, struct stap_parse_info *p);
 
 #endif /* i386-tdep.h */
diff --git a/gdb/ppc-linux-tdep.c b/gdb/ppc-linux-tdep.c
index 467d696374c..1e94922f25a 100644
--- a/gdb/ppc-linux-tdep.c
+++ b/gdb/ppc-linux-tdep.c
@@ -52,6 +52,7 @@
 #include "linux-record.h"
 #include "record-full.h"
 #include "infrun.h"
+#include "expop.h"
 
 #include "stap-probe.h"
 #include "ax.h"
@@ -1674,7 +1675,7 @@ ppc_stap_is_single_operand (struct gdbarch *gdbarch, const char *s)
 /* Implementation of `gdbarch_stap_parse_special_token', as defined in
    gdbarch.h.  */
 
-static int
+static expr::operation_up
 ppc_stap_parse_special_token (struct gdbarch *gdbarch,
 			      struct stap_parse_info *p)
 {
@@ -1686,7 +1687,6 @@ ppc_stap_parse_special_token (struct gdbarch *gdbarch,
       const char *s = p->arg;
       char *regname;
       int len;
-      struct stoken str;
 
       while (isdigit (*s))
 	++s;
@@ -1695,7 +1695,7 @@ ppc_stap_parse_special_token (struct gdbarch *gdbarch,
 	{
 	  /* It is a register displacement indeed.  Returning 0 means we are
 	     deferring the treatment of this case to the generic parser.  */
-	  return 0;
+	  return {};
 	}
 
       len = s - p->arg;
@@ -1710,22 +1710,14 @@ ppc_stap_parse_special_token (struct gdbarch *gdbarch,
 	error (_("Invalid register name `%s' on expression `%s'."),
 	       regname, p->saved_arg);
 
-      write_exp_elt_opcode (&p->pstate, OP_REGISTER);
-      str.ptr = regname;
-      str.length = len;
-      write_exp_string (&p->pstate, str);
-      write_exp_elt_opcode (&p->pstate, OP_REGISTER);
-
       p->arg = s;
-    }
-  else
-    {
-      /* All the other tokens should be handled correctly by the generic
-	 parser.  */
-      return 0;
+
+      return expr::make_operation<expr::register_operation> (regname);
     }
 
-  return 1;
+  /* All the other tokens should be handled correctly by the generic
+     parser.  */
+  return {};
 }
 
 /* Initialize linux_record_tdep if not initialized yet.
diff --git a/gdb/stap-probe.c b/gdb/stap-probe.c
index 6ee025744aa..51f04b9e40b 100644
--- a/gdb/stap-probe.c
+++ b/gdb/stap-probe.c
@@ -36,6 +36,8 @@
 #include "parser-defs.h"
 #include "language.h"
 #include "elf-bfd.h"
+#include "expop.h"
+#include <unordered_map>
 
 #include <ctype.h>
 
@@ -261,10 +263,13 @@ enum stap_operand_prec
   STAP_OPERAND_PREC_MUL
 };
 
-static void stap_parse_argument_1 (struct stap_parse_info *p, bool has_lhs,
-				   enum stap_operand_prec prec);
+static expr::operation_up stap_parse_argument_1 (struct stap_parse_info *p,
+						 expr::operation_up &&lhs,
+						 enum stap_operand_prec prec)
+  ATTRIBUTE_UNUSED_RESULT;
 
-static void stap_parse_argument_conditionally (struct stap_parse_info *p);
+static expr::operation_up stap_parse_argument_conditionally
+     (struct stap_parse_info *p) ATTRIBUTE_UNUSED_RESULT;
 
 /* Returns true if *S is an operator, false otherwise.  */
 
@@ -421,6 +426,22 @@ stap_get_opcode (const char **s)
   return op;
 }
 
+typedef expr::operation_up binop_maker_ftype (expr::operation_up &&,
+					      expr::operation_up &&);
+/* Map from an expression opcode to a function that can create a
+   binary operation of that type.  */
+static std::unordered_map<exp_opcode, binop_maker_ftype *> stap_maker_map;
+
+/* Helper function to create a binary operation.  */
+static expr::operation_up
+stap_make_binop (enum exp_opcode opcode, expr::operation_up &&lhs,
+		 expr::operation_up &&rhs)
+{
+  auto iter = stap_maker_map.find (opcode);
+  gdb_assert (iter != stap_maker_map.end ());
+  return iter->second (std::move (lhs), std::move (rhs));
+}
+
 /* Given the bitness of the argument, represented by B, return the
    corresponding `struct type *', or throw an error if B is
    unknown.  */
@@ -670,19 +691,16 @@ stap_check_register_indirection_suffix (struct gdbarch *gdbarch, const char *s,
    language (e.g., `15' is the 15th general-purpose register), but inside
    GDB they have a prefix (the letter `r') appended.  */
 
-static void
+static expr::operation_up
 stap_parse_register_operand (struct stap_parse_info *p)
 {
   /* Simple flag to indicate whether we have seen a minus signal before
      certain number.  */
   bool got_minus = false;
-  /* Flags to indicate whether this register access is being displaced and/or
+  /* Flag to indicate whether this register access is being
      indirected.  */
-  bool disp_p = false;
   bool indirect_p = false;
   struct gdbarch *gdbarch = p->gdbarch;
-  /* Needed to generate the register name as a part of an expression.  */
-  struct stoken str;
   /* Variables used to extract the register name from the probe's
      argument.  */
   const char *start;
@@ -693,6 +711,8 @@ stap_parse_register_operand (struct stap_parse_info *p)
   const char *reg_suffix;
   const char *reg_ind_suffix;
 
+  using namespace expr;
+
   /* Checking for a displacement argument.  */
   if (*p->arg == '+')
     {
@@ -706,23 +726,21 @@ stap_parse_register_operand (struct stap_parse_info *p)
       ++p->arg;
     }
 
+  struct type *long_type = builtin_type (gdbarch)->builtin_long;
+  operation_up disp_op;
   if (isdigit (*p->arg))
     {
       /* The value of the displacement.  */
       long displacement;
       char *endp;
 
-      disp_p = true;
       displacement = strtol (p->arg, &endp, 10);
       p->arg = endp;
 
       /* Generating the expression for the displacement.  */
-      write_exp_elt_opcode (&p->pstate, OP_LONG);
-      write_exp_elt_type (&p->pstate, builtin_type (gdbarch)->builtin_long);
-      write_exp_elt_longcst (&p->pstate, displacement);
-      write_exp_elt_opcode (&p->pstate, OP_LONG);
       if (got_minus)
-	write_exp_elt_opcode (&p->pstate, UNOP_NEG);
+	displacement = -displacement;
+      disp_op = make_operation<long_const_operation> (long_type, displacement);
     }
 
   /* Getting rid of register indirection prefix.  */
@@ -732,7 +750,7 @@ stap_parse_register_operand (struct stap_parse_info *p)
       p->arg += strlen (reg_ind_prefix);
     }
 
-  if (disp_p && !indirect_p)
+  if (disp_op != nullptr && !indirect_p)
     error (_("Invalid register displacement syntax on expression `%s'."),
 	   p->saved_arg);
 
@@ -790,27 +808,23 @@ stap_parse_register_operand (struct stap_parse_info *p)
 			      " (previous name was '%s')"),
 			    newregname.c_str (), regname.c_str ());
 
-	  regname = newregname;
+	  regname = std::move (newregname);
 	}
     }
 
-  write_exp_elt_opcode (&p->pstate, OP_REGISTER);
-  str.ptr = regname.c_str ();
-  str.length = regname.size ();
-  write_exp_string (&p->pstate, str);
-  write_exp_elt_opcode (&p->pstate, OP_REGISTER);
+  operation_up reg = make_operation<register_operation> (std::move (regname));
 
   if (indirect_p)
     {
-      if (disp_p)
-	write_exp_elt_opcode (&p->pstate, BINOP_ADD);
+      if (disp_op != nullptr)
+	reg = make_operation<add_operation> (std::move (disp_op),
+					     std::move (reg));
 
       /* Casting to the expected type.  */
-      write_exp_elt_opcode (&p->pstate, UNOP_CAST);
-      write_exp_elt_type (&p->pstate, lookup_pointer_type (p->arg_type));
-      write_exp_elt_opcode (&p->pstate, UNOP_CAST);
-
-      write_exp_elt_opcode (&p->pstate, UNOP_IND);
+      struct type *arg_ptr_type = lookup_pointer_type (p->arg_type);
+      reg = make_operation<unop_cast_operation> (std::move (reg),
+						 arg_ptr_type);
+      reg = make_operation<unop_ind_operation> (std::move (reg));
     }
 
   /* Getting rid of the register name suffix.  */
@@ -830,6 +844,8 @@ stap_parse_register_operand (struct stap_parse_info *p)
 	error (_("Missing indirection suffix on expression `%s'."),
 	       p->saved_arg);
     }
+
+  return reg;
 }
 
 /* This function is responsible for parsing a single operand.
@@ -847,23 +863,24 @@ stap_parse_register_operand (struct stap_parse_info *p)
    unrecognized operands, allowing arch-specific parsers to be
    created.  */
 
-static void
+static expr::operation_up
 stap_parse_single_operand (struct stap_parse_info *p)
 {
   struct gdbarch *gdbarch = p->gdbarch;
   const char *int_prefix = NULL;
 
+  using namespace expr;
+
   /* We first try to parse this token as a "special token".  */
-  if (gdbarch_stap_parse_special_token_p (gdbarch)
-      && (gdbarch_stap_parse_special_token (gdbarch, p) != 0))
+  if (gdbarch_stap_parse_special_token_p (gdbarch))
     {
-      /* If the return value of the above function is not zero,
-	 it means it successfully parsed the special token.
-
-	 If it is NULL, we try to parse it using our method.  */
-      return;
+      operation_up token = gdbarch_stap_parse_special_token (gdbarch, p);
+      if (token != nullptr)
+	return token;
     }
 
+  struct type *long_type = builtin_type (gdbarch)->builtin_long;
+  operation_up result;
   if (*p->arg == '-' || *p->arg == '~' || *p->arg == '+' || *p->arg == '!')
     {
       char c = *p->arg;
@@ -906,20 +923,22 @@ stap_parse_single_operand (struct stap_parse_info *p)
 	    error (_("Invalid operator `%c' for register displacement "
 		     "on expression `%s'."), c, p->saved_arg);
 
-	  stap_parse_register_operand (p);
+	  result = stap_parse_register_operand (p);
 	}
       else
 	{
 	  /* This is not a displacement.  We skip the operator, and
 	     deal with it when the recursion returns.  */
 	  ++p->arg;
-	  stap_parse_argument_conditionally (p);
+	  result = stap_parse_argument_conditionally (p);
 	  if (c == '-')
-	    write_exp_elt_opcode (&p->pstate, UNOP_NEG);
+	    result = make_operation<unary_neg_operation> (std::move (result));
 	  else if (c == '~')
-	    write_exp_elt_opcode (&p->pstate, UNOP_COMPLEMENT);
+	    result = (make_operation<unary_complement_operation>
+		      (std::move (result)));
 	  else if (c == '!')
-	    write_exp_elt_opcode (&p->pstate, UNOP_LOGICAL_NOT);
+	    result = (make_operation<unary_logical_not_operation>
+		      (std::move (result)));
 	}
     }
   else if (isdigit (*p->arg))
@@ -947,11 +966,7 @@ stap_parse_single_operand (struct stap_parse_info *p)
 	  const char *int_suffix;
 
 	  /* We are dealing with a numeric constant.  */
-	  write_exp_elt_opcode (&p->pstate, OP_LONG);
-	  write_exp_elt_type (&p->pstate,
-			      builtin_type (gdbarch)->builtin_long);
-	  write_exp_elt_longcst (&p->pstate, number);
-	  write_exp_elt_opcode (&p->pstate, OP_LONG);
+	  result = make_operation<long_const_operation> (long_type, number);
 
 	  p->arg = tmp;
 
@@ -962,7 +977,7 @@ stap_parse_single_operand (struct stap_parse_info *p)
 		   p->saved_arg);
 	}
       else if (stap_is_register_indirection_prefix (gdbarch, tmp, NULL))
-	stap_parse_register_operand (p);
+	result = stap_parse_register_operand (p);
       else
 	error (_("Unknown numeric token on expression `%s'."),
 	       p->saved_arg);
@@ -978,10 +993,7 @@ stap_parse_single_operand (struct stap_parse_info *p)
       number = strtol (p->arg, &endp, 10);
       p->arg = endp;
 
-      write_exp_elt_opcode (&p->pstate, OP_LONG);
-      write_exp_elt_type (&p->pstate, builtin_type (gdbarch)->builtin_long);
-      write_exp_elt_longcst (&p->pstate, number);
-      write_exp_elt_opcode (&p->pstate, OP_LONG);
+      result = make_operation<long_const_operation> (long_type, number);
 
       if (stap_check_integer_suffix (gdbarch, p->arg, &int_suffix))
 	p->arg += strlen (int_suffix);
@@ -991,10 +1003,12 @@ stap_parse_single_operand (struct stap_parse_info *p)
     }
   else if (stap_is_register_prefix (gdbarch, p->arg, NULL)
 	   || stap_is_register_indirection_prefix (gdbarch, p->arg, NULL))
-    stap_parse_register_operand (p);
+    result = stap_parse_register_operand (p);
   else
     error (_("Operator `%c' not recognized on expression `%s'."),
 	   *p->arg, p->saved_arg);
+
+  return result;
 }
 
 /* This function parses an argument conditionally, based on single or
@@ -1003,15 +1017,16 @@ stap_parse_single_operand (struct stap_parse_info *p)
    starts with `-', `~', `+' (i.e., unary operators), a digit, or
    something recognized by `gdbarch_stap_is_single_operand'.  */
 
-static void
+static expr::operation_up
 stap_parse_argument_conditionally (struct stap_parse_info *p)
 {
   gdb_assert (gdbarch_stap_is_single_operand_p (p->gdbarch));
 
+  expr::operation_up result;
   if (*p->arg == '-' || *p->arg == '~' || *p->arg == '+' /* Unary.  */
       || isdigit (*p->arg)
       || gdbarch_stap_is_single_operand (p->gdbarch, p->arg))
-    stap_parse_single_operand (p);
+    result = stap_parse_single_operand (p);
   else if (*p->arg == '(')
     {
       /* We are dealing with a parenthesized operand.  It means we
@@ -1021,7 +1036,7 @@ stap_parse_argument_conditionally (struct stap_parse_info *p)
       p->arg = skip_spaces (p->arg);
       ++p->inside_paren_p;
 
-      stap_parse_argument_1 (p, 0, STAP_OPERAND_PREC_NONE);
+      result = stap_parse_argument_1 (p, {}, STAP_OPERAND_PREC_NONE);
 
       --p->inside_paren_p;
       if (*p->arg != ')')
@@ -1034,13 +1049,16 @@ stap_parse_argument_conditionally (struct stap_parse_info *p)
     }
   else
     error (_("Cannot parse expression `%s'."), p->saved_arg);
+
+  return result;
 }
 
 /* Helper function for `stap_parse_argument'.  Please, see its comments to
    better understand what this function does.  */
 
-static void
-stap_parse_argument_1 (struct stap_parse_info *p, bool has_lhs,
+static expr::operation_up ATTRIBUTE_UNUSED_RESULT
+stap_parse_argument_1 (struct stap_parse_info *p,
+		       expr::operation_up &&lhs_in,
 		       enum stap_operand_prec prec)
 {
   /* This is an operator-precedence parser.
@@ -1054,13 +1072,15 @@ stap_parse_argument_1 (struct stap_parse_info *p, bool has_lhs,
   if (p->inside_paren_p)
     p->arg = skip_spaces (p->arg);
 
-  if (!has_lhs)
+  using namespace expr;
+  operation_up lhs = std::move (lhs_in);
+  if (lhs == nullptr)
     {
       /* We were called without a left-side, either because this is the
 	 first call, or because we were called to parse a parenthesized
 	 expression.  It doesn't really matter; we have to parse the
 	 left-side in order to continue the process.  */
-      stap_parse_argument_conditionally (p);
+      lhs = stap_parse_argument_conditionally (p);
     }
 
   /* Start to parse the right-side, and to "join" left and right sides
@@ -1101,7 +1121,7 @@ stap_parse_argument_1 (struct stap_parse_info *p, bool has_lhs,
 	p->arg = skip_spaces (p->arg);
 
       /* Parse the right-side of the expression.  */
-      stap_parse_argument_conditionally (p);
+      operation_up rhs = stap_parse_argument_conditionally (p);
 
       /* While we still have operators, try to parse another
 	 right-side, but using the current right-side as a left-side.  */
@@ -1123,13 +1143,16 @@ stap_parse_argument_1 (struct stap_parse_info *p, bool has_lhs,
 	      break;
 	    }
 
-	  /* Parse the right-side of the expression, but since we already
-	     have a left-side at this point, set `has_lhs' to 1.  */
-	  stap_parse_argument_1 (p, 1, lookahead_prec);
+	  /* Parse the right-side of the expression, using the current
+	     right-hand-side as the left-hand-side of the new
+	     subexpression.  */
+	  rhs = stap_parse_argument_1 (p, std::move (rhs), lookahead_prec);
 	}
 
-      write_exp_elt_opcode (&p->pstate, opcode);
+      lhs = stap_make_binop (opcode, std::move (lhs), std::move (rhs));
     }
+
+  return lhs;
 }
 
 /* Parse a probe's argument.
@@ -1169,14 +1192,14 @@ stap_parse_argument (const char **arg, struct type *atype,
   struct stap_parse_info p (*arg, atype, language_def (language_c),
 			    gdbarch);
 
-  stap_parse_argument_1 (&p, 0, STAP_OPERAND_PREC_NONE);
+  using namespace expr;
+  operation_up result = stap_parse_argument_1 (&p, {}, STAP_OPERAND_PREC_NONE);
 
   gdb_assert (p.inside_paren_p == 0);
 
   /* Casting the final expression to the appropriate type.  */
-  write_exp_elt_opcode (&p.pstate, UNOP_CAST);
-  write_exp_elt_type (&p.pstate, atype);
-  write_exp_elt_opcode (&p.pstate, UNOP_CAST);
+  result = make_operation<unop_cast_operation> (std::move (result), atype);
+  p.pstate.set_operation (std::move (result));
 
   p.arg = skip_spaces (p.arg);
   *arg = p.arg;
@@ -1265,12 +1288,6 @@ stap_probe::parse_arguments (struct gdbarch *gdbarch)
 
       expression_up expr = stap_parse_argument (&cur, atype, gdbarch);
 
-      if (stap_expression_debug)
-	dump_raw_expression (expr.get (), gdb_stdlog,
-			     "before conversion to prefix form");
-
-      prefixify_expression (expr.get ());
-
       if (stap_expression_debug)
 	dump_prefix_expression (expr.get (), gdb_stdlog);
 
@@ -1722,4 +1739,24 @@ NAME matches the probe names.\n\
 OBJECT matches the executable or shared library name."),
 	   info_probes_cmdlist_get ());
 
+
+  using namespace expr;
+  stap_maker_map[BINOP_ADD] = make_operation<add_operation>;
+  stap_maker_map[BINOP_BITWISE_AND] = make_operation<bitwise_and_operation>;
+  stap_maker_map[BINOP_BITWISE_IOR] = make_operation<bitwise_ior_operation>;
+  stap_maker_map[BINOP_BITWISE_XOR] = make_operation<bitwise_xor_operation>;
+  stap_maker_map[BINOP_DIV] = make_operation<div_operation>;
+  stap_maker_map[BINOP_EQUAL] = make_operation<equal_operation>;
+  stap_maker_map[BINOP_GEQ] = make_operation<geq_operation>;
+  stap_maker_map[BINOP_GTR] = make_operation<gtr_operation>;
+  stap_maker_map[BINOP_LEQ] = make_operation<leq_operation>;
+  stap_maker_map[BINOP_LESS] = make_operation<less_operation>;
+  stap_maker_map[BINOP_LOGICAL_AND] = make_operation<logical_and_operation>;
+  stap_maker_map[BINOP_LOGICAL_OR] = make_operation<logical_or_operation>;
+  stap_maker_map[BINOP_LSH] = make_operation<lsh_operation>;
+  stap_maker_map[BINOP_MUL] = make_operation<mul_operation>;
+  stap_maker_map[BINOP_NOTEQUAL] = make_operation<notequal_operation>;
+  stap_maker_map[BINOP_REM] = make_operation<rem_operation>;
+  stap_maker_map[BINOP_RSH] = make_operation<rsh_operation>;
+  stap_maker_map[BINOP_SUB] = make_operation<sub_operation>;
 }
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 177/203] Convert rust-exp.y to use operations
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (175 preceding siblings ...)
  2021-01-01 21:46 ` [PATCH 176/203] Convert stap probes to create operations Tom Tromey
@ 2021-01-01 21:46 ` Tom Tromey
  2021-01-01 21:46 ` [PATCH 178/203] Convert c-exp.y " Tom Tromey
                   ` (26 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:46 UTC (permalink / raw)
  To: gdb-patches

This converts the Rust parser to generate operations rather than
exp_elements.

The Rust parser already made its own AST, that it then lowered to GDB
expressions.  Ironically, this made conversion trickier, rather than
simpler, than the other parsers, primarily due to the way that binary
operations were lowered.  Perhaps in the future, converting the Rust
parser to directly create operations while parsing would be
worthwhile.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* rust-exp.y: Create operations.
	(rust_parser::convert_params_to_expression): Change return type.
	(binop_maker_ftype): New typedef.
	(maker_map): New global.
	(rust_parser::convert_ast_to_expression): Change return type.
	(rust_language::parser): Update.
	(_initialize_rust_exp): Initialize maker_map.
---
 gdb/ChangeLog  |  10 ++
 gdb/rust-exp.y | 324 +++++++++++++++++++++++++++----------------------
 2 files changed, 190 insertions(+), 144 deletions(-)

diff --git a/gdb/rust-exp.y b/gdb/rust-exp.y
index a6583a6129a..9a5bdd7a836 100644
--- a/gdb/rust-exp.y
+++ b/gdb/rust-exp.y
@@ -41,6 +41,8 @@
 #include "gdbsupport/selftest.h"
 #include "value.h"
 #include "gdbarch.h"
+#include "rust-exp.h"
+#include <unordered_map>
 
 #define GDB_YY_REMAP_PREFIX rust
 #include "yy-remap.h"
@@ -246,11 +248,11 @@ struct rust_parser
   std::vector<struct type *> convert_params_to_types (rust_op_vector *params);
   struct type *convert_ast_to_type (const struct rust_op *operation);
   const char *convert_name (const struct rust_op *operation);
-  void convert_params_to_expression (rust_op_vector *params,
-				     const struct rust_op *top);
-  void convert_ast_to_expression (const struct rust_op *operation,
-				  const struct rust_op *top,
-				  bool want_type = false);
+  std::vector<expr::operation_up> convert_params_to_expression
+       (rust_op_vector *params, const struct rust_op *top);
+  expr::operation_up convert_ast_to_expression (const struct rust_op *opn,
+						const struct rust_op *top,
+						bool want_type = false);
 
   struct rust_op *ast_basic_type (enum type_code typecode);
   const struct rust_op *ast_operation (enum exp_opcode opcode,
@@ -2183,14 +2185,25 @@ rust_parser::convert_name (const struct rust_op *operation)
 /* A helper function that converts a vec of rust_ops to a gdb
    expression.  */
 
-void
+std::vector<expr::operation_up>
 rust_parser::convert_params_to_expression (rust_op_vector *params,
 					   const struct rust_op *top)
 {
+  std::vector<expr::operation_up> result;
   for (const rust_op *elem : *params)
-    convert_ast_to_expression (elem, top);
+    result.push_back (convert_ast_to_expression (elem, top));
+  result.shrink_to_fit ();
+  return result;
 }
 
+typedef expr::operation_up binop_maker_ftype (expr::operation_up &&,
+					      expr::operation_up &&);
+
+/* Map from an expression opcode to a function that will create an
+   instance of the appropriate operation subclass.  Only binary
+   operations are handled this way.  */
+static std::unordered_map<exp_opcode, binop_maker_ftype *> maker_map;
+
 /* Lower a rust_op to a gdb expression.  STATE is the parser state.
    OPERATION is the operation to lower.  TOP is a pointer to the
    top-most operation; it is used to handle the special case where the
@@ -2200,62 +2213,87 @@ rust_parser::convert_params_to_expression (rust_op_vector *params,
    erroring).  If WANT_TYPE is set, then the similar TOP handling is
    not done.  */
 
-void
+expr::operation_up
 rust_parser::convert_ast_to_expression (const struct rust_op *operation,
 					const struct rust_op *top,
 					bool want_type)
 {
+  using namespace expr;
+
   switch (operation->opcode)
     {
     case OP_LONG:
-      write_exp_elt_opcode (pstate, OP_LONG);
-      write_exp_elt_type (pstate, operation->left.typed_val_int.type);
-      write_exp_elt_longcst (pstate, operation->left.typed_val_int.val);
-      write_exp_elt_opcode (pstate, OP_LONG);
-      break;
+      return operation_up
+	(new long_const_operation (operation->left.typed_val_int.type,
+				   operation->left.typed_val_int.val));
 
     case OP_FLOAT:
-      write_exp_elt_opcode (pstate, OP_FLOAT);
-      write_exp_elt_type (pstate, operation->left.typed_val_float.type);
-      write_exp_elt_floatcst (pstate, operation->left.typed_val_float.val);
-      write_exp_elt_opcode (pstate, OP_FLOAT);
-      break;
+      {
+	float_data data;
+	memcpy (data.data (), operation->left.typed_val_float.val,
+		sizeof (operation->left.typed_val_float.val));
+	return operation_up
+	  (new float_const_operation (operation->left.typed_val_float.type,
+				      data));
+      }
 
     case STRUCTOP_STRUCT:
       {
-	convert_ast_to_expression (operation->left.op, top);
-
+	operation_up lhs = convert_ast_to_expression (operation->left.op, top);
+	auto result = new rust_structop (std::move (lhs),
+					 operation->right.sval.ptr);
 	if (operation->completing)
-	  pstate->mark_struct_expression ();
-	write_exp_elt_opcode (pstate, STRUCTOP_STRUCT);
-	write_exp_string (pstate, operation->right.sval);
-	write_exp_elt_opcode (pstate, STRUCTOP_STRUCT);
+	  pstate->mark_struct_expression (result);
+	return operation_up (result);
       }
-      break;
 
     case STRUCTOP_ANONYMOUS:
       {
-	convert_ast_to_expression (operation->left.op, top);
+	operation_up lhs = convert_ast_to_expression (operation->left.op, top);
 
-	write_exp_elt_opcode (pstate, STRUCTOP_ANONYMOUS);
-	write_exp_elt_longcst (pstate, operation->right.typed_val_int.val);
-	write_exp_elt_opcode (pstate, STRUCTOP_ANONYMOUS);
+	return operation_up
+	  (new rust_struct_anon (operation->right.typed_val_int.val,
+				 std::move (lhs)));
       }
-      break;
 
     case UNOP_SIZEOF:
-      convert_ast_to_expression (operation->left.op, top, true);
-      write_exp_elt_opcode (pstate, UNOP_SIZEOF);
-      break;
+      {
+	operation_up lhs = convert_ast_to_expression (operation->left.op, top,
+						      true);
+	return operation_up
+	  (new unop_sizeof_operation (std::move (lhs)));
+      }
 
     case UNOP_PLUS:
+      {
+	operation_up lhs = convert_ast_to_expression (operation->left.op, top);
+	return operation_up
+	  (new unary_plus_operation (std::move (lhs)));
+      }
     case UNOP_NEG:
+      {
+	operation_up lhs = convert_ast_to_expression (operation->left.op, top);
+	return operation_up
+	  (new unary_neg_operation (std::move (lhs)));
+      }
     case UNOP_COMPLEMENT:
+      {
+	operation_up lhs = convert_ast_to_expression (operation->left.op, top);
+	return operation_up
+	  (new rust_unop_compl_operation (std::move (lhs)));
+      }
     case UNOP_IND:
+      {
+	operation_up lhs = convert_ast_to_expression (operation->left.op, top);
+	return operation_up
+	  (new rust_unop_ind_operation (std::move (lhs)));
+      }
     case UNOP_ADDR:
-      convert_ast_to_expression (operation->left.op, top);
-      write_exp_elt_opcode (pstate, operation->opcode);
-      break;
+      {
+	operation_up lhs = convert_ast_to_expression (operation->left.op, top);
+	return operation_up
+	  (new rust_unop_addr_operation (std::move (lhs)));
+      }
 
     case BINOP_SUBSCRIPT:
     case BINOP_MUL:
@@ -2279,45 +2317,45 @@ rust_parser::convert_ast_to_expression (const struct rust_op *operation,
     case BINOP_RSH:
     case BINOP_ASSIGN:
     case OP_RUST_ARRAY:
-      convert_ast_to_expression (operation->left.op, top);
-      convert_ast_to_expression (operation->right.op, top);
-      if (operation->compound_assignment)
-	{
-	  write_exp_elt_opcode (pstate, BINOP_ASSIGN_MODIFY);
-	  write_exp_elt_opcode (pstate, operation->opcode);
-	  write_exp_elt_opcode (pstate, BINOP_ASSIGN_MODIFY);
-	}
-      else
-	write_exp_elt_opcode (pstate, operation->opcode);
-
-      if (operation->compound_assignment
-	  || operation->opcode == BINOP_ASSIGN)
-	{
-	  struct type *type;
-
-	  type = language_lookup_primitive_type (pstate->language (),
-						 pstate->gdbarch (),
-						 "()");
+      {
+	operation_up lhs = convert_ast_to_expression (operation->left.op, top);
+	operation_up rhs = convert_ast_to_expression (operation->right.op,
+						      top);
+	operation_up result;
+	if (operation->compound_assignment)
+	  result = (operation_up
+		    (new assign_modify_operation (operation->opcode,
+						  std::move (lhs),
+						  std::move (rhs))));
+	else
+	  {
+	    auto iter = maker_map.find (operation->opcode);
+	    gdb_assert (iter != maker_map.end ());
+	    result = iter->second (std::move (lhs), std::move (rhs));
+	  }
 
-	  write_exp_elt_opcode (pstate, OP_LONG);
-	  write_exp_elt_type (pstate, type);
-	  write_exp_elt_longcst (pstate, 0);
-	  write_exp_elt_opcode (pstate, OP_LONG);
+	if (operation->compound_assignment
+	    || operation->opcode == BINOP_ASSIGN)
+	  {
+	    struct type *type
+	      = language_lookup_primitive_type (pstate->language (),
+						pstate->gdbarch (),
+						"()");
+
+	    operation_up nil (new long_const_operation (type, 0));
+	    result.reset (new comma_operation (std::move (result),
+					       std::move (nil)));
+	  }
 
-	  write_exp_elt_opcode (pstate, BINOP_COMMA);
-	}
-      break;
+	return result;
+      }
 
     case UNOP_CAST:
       {
 	struct type *type = convert_ast_to_type (operation->right.op);
-
-	convert_ast_to_expression (operation->left.op, top);
-	write_exp_elt_opcode (pstate, UNOP_CAST);
-	write_exp_elt_type (pstate, type);
-	write_exp_elt_opcode (pstate, UNOP_CAST);
+	operation_up lhs = convert_ast_to_expression (operation->left.op, top);
+	return operation_up (new unop_cast_operation (std::move (lhs), type));
       }
-      break;
 
     case OP_FUNCALL:
       {
@@ -2339,42 +2377,39 @@ rust_parser::convert_ast_to_expression (const struct rust_op *operation,
 		    if (!rust_tuple_struct_type_p (type))
 		      error (_("Type %s is not a tuple struct"), varname);
 
+		    std::vector<std::pair<std::string, operation_up>> args
+		      (params->size ());
 		    for (int i = 0; i < params->size (); ++i)
 		      {
 			char *cell = get_print_cell ();
 
+			operation_up op
+			  = convert_ast_to_expression ((*params)[i], top);
 			xsnprintf (cell, PRINT_CELL_SIZE, "__%d", i);
-			write_exp_elt_opcode (pstate, OP_NAME);
-			write_exp_string (pstate, make_stoken (cell));
-			write_exp_elt_opcode (pstate, OP_NAME);
-
-			convert_ast_to_expression ((*params)[i], top);
+			args[i] = { cell, std::move (op) };
 		      }
 
-		    write_exp_elt_opcode (pstate, OP_AGGREGATE);
-		    write_exp_elt_type (pstate, type);
-		    write_exp_elt_longcst (pstate, 2 * params->size ());
-		    write_exp_elt_opcode (pstate, OP_AGGREGATE);
-		    break;
+		    return make_operation<rust_aggregate_operation>
+		      (type, operation_up (), std::move (args));
 		  }
 	      }
 	  }
-	convert_ast_to_expression (operation->left.op, top);
-	convert_params_to_expression (operation->right.params, top);
-	write_exp_elt_opcode (pstate, OP_FUNCALL);
-	write_exp_elt_longcst (pstate, operation->right.params->size ());
-	write_exp_elt_longcst (pstate, OP_FUNCALL);
+	operation_up callee = convert_ast_to_expression (operation->left.op,
+							 top);
+	std::vector<operation_up> args
+	  = convert_params_to_expression (operation->right.params, top);
+	return make_operation<funcall_operation> (std::move (callee),
+						  std::move (args));
       }
-      break;
 
     case OP_ARRAY:
-      gdb_assert (operation->left.op == NULL);
-      convert_params_to_expression (operation->right.params, top);
-      write_exp_elt_opcode (pstate, OP_ARRAY);
-      write_exp_elt_longcst (pstate, 0);
-      write_exp_elt_longcst (pstate, operation->right.params->size () - 1);
-      write_exp_elt_longcst (pstate, OP_ARRAY);
-      break;
+      {
+	gdb_assert (operation->left.op == NULL);
+	std::vector<operation_up> subexps
+	  = convert_params_to_expression (operation->right.params, top);
+	return make_operation<array_operation>
+	  (0, operation->right.params->size () - 1, std::move (subexps));
+      }
 
     case OP_VAR_VALUE:
       {
@@ -2383,20 +2418,16 @@ rust_parser::convert_ast_to_expression (const struct rust_op *operation,
 
 	if (operation->left.sval.ptr[0] == '$')
 	  {
-	    write_dollar_variable (pstate, operation->left.sval);
-	    break;
+	    pstate->push_dollar (operation->left.sval);
+	    return pstate->pop ();
 	  }
 
 	varname = convert_name (operation);
 	sym = lookup_symbol (varname, pstate->expression_context_block,
 			     VAR_DOMAIN);
+	operation_up result;
 	if (sym.symbol != NULL && SYMBOL_CLASS (sym.symbol) != LOC_TYPEDEF)
-	  {
-	    write_exp_elt_opcode (pstate, OP_VAR_VALUE);
-	    write_exp_elt_block (pstate, sym.block);
-	    write_exp_elt_sym (pstate, sym.symbol);
-	    write_exp_elt_opcode (pstate, OP_VAR_VALUE);
-	  }
+	  result.reset (new var_value_operation (sym.symbol, sym.block));
 	else
 	  {
 	    struct type *type = NULL;
@@ -2417,52 +2448,35 @@ rust_parser::convert_ast_to_expression (const struct rust_op *operation,
 		&& type->num_fields () == 0)
 	      {
 		/* A unit-like struct.  */
-		write_exp_elt_opcode (pstate, OP_AGGREGATE);
-		write_exp_elt_type (pstate, type);
-		write_exp_elt_longcst (pstate, 0);
-		write_exp_elt_opcode (pstate, OP_AGGREGATE);
+		result.reset (new rust_aggregate_operation (type, {}, {}));
 	      }
 	    else if (want_type || operation == top)
-	      {
-		write_exp_elt_opcode (pstate, OP_TYPE);
-		write_exp_elt_type (pstate, type);
-		write_exp_elt_opcode (pstate, OP_TYPE);
-	      }
+	      result.reset (new type_operation (type));
 	    else
 	      error (_("Found type '%s', which can't be "
 		       "evaluated in this context"),
 		     varname);
 	  }
+
+	return result;
       }
-      break;
 
     case OP_AGGREGATE:
       {
-	int length;
 	rust_set_vector *fields = operation->right.field_inits;
 	struct type *type;
 	const char *name;
 
-	length = 0;
+	operation_up others;
+	std::vector<std::pair<std::string, operation_up>> field_v;
 	for (const set_field &init : *fields)
 	  {
-	    if (init.name.ptr != NULL)
-	      {
-		write_exp_elt_opcode (pstate, OP_NAME);
-		write_exp_string (pstate, init.name);
-		write_exp_elt_opcode (pstate, OP_NAME);
-		++length;
-	      }
-
-	    convert_ast_to_expression (init.init, top);
-	    ++length;
+	    operation_up expr = convert_ast_to_expression (init.init, top);
 
 	    if (init.name.ptr == NULL)
-	      {
-		/* This is handled differently from Ada in our
-		   evaluator.  */
-		write_exp_elt_opcode (pstate, OP_OTHERS);
-	      }
+	      others = std::move (expr);
+	    else
+	      field_v.emplace_back (init.name.ptr, std::move (expr));
 	  }
 
 	name = convert_name (operation->left.op);
@@ -2475,34 +2489,29 @@ rust_parser::convert_ast_to_expression (const struct rust_op *operation,
 	    || rust_tuple_struct_type_p (type))
 	  error (_("Struct expression applied to non-struct type"));
 
-	write_exp_elt_opcode (pstate, OP_AGGREGATE);
-	write_exp_elt_type (pstate, type);
-	write_exp_elt_longcst (pstate, length);
-	write_exp_elt_opcode (pstate, OP_AGGREGATE);
+	return operation_up
+	  (new rust_aggregate_operation (type, std::move (others),
+					 std::move (field_v)));
       }
-      break;
 
     case OP_STRING:
-      {
-	write_exp_elt_opcode (pstate, OP_STRING);
-	write_exp_string (pstate, operation->left.sval);
-	write_exp_elt_opcode (pstate, OP_STRING);
-      }
-      break;
+      return (operation_up
+	      (new string_operation (::copy_name (operation->left.sval))));
 
     case OP_RANGE:
       {
 	enum range_flag kind = (RANGE_HIGH_BOUND_DEFAULT
 				| RANGE_LOW_BOUND_DEFAULT);
+	operation_up lhs, rhs;
 
 	if (operation->left.op != NULL)
 	  {
-	    convert_ast_to_expression (operation->left.op, top);
+	    lhs = convert_ast_to_expression (operation->left.op, top);
 	    kind &= ~RANGE_LOW_BOUND_DEFAULT;
 	  }
 	if (operation->right.op != NULL)
 	  {
-	    convert_ast_to_expression (operation->right.op, top);
+	    rhs = convert_ast_to_expression (operation->right.op, top);
 	    if (kind == (RANGE_HIGH_BOUND_DEFAULT | RANGE_LOW_BOUND_DEFAULT))
 	      {
 		kind = RANGE_LOW_BOUND_DEFAULT;
@@ -2524,11 +2533,10 @@ rust_parser::convert_ast_to_expression (const struct rust_op *operation,
 	    gdb_assert (!operation->inclusive);
 	  }
 
-	write_exp_elt_opcode (pstate, OP_RANGE);
-	write_exp_elt_longcst (pstate, kind);
-	write_exp_elt_opcode (pstate, OP_RANGE);
+	return operation_up (new rust_range_operation (kind,
+						       std::move (lhs),
+						       std::move (rhs)));
       }
-      break;
 
     default:
       gdb_assert_not_reached ("unhandled opcode in convert_ast_to_expression");
@@ -2551,7 +2559,11 @@ rust_language::parser (struct parser_state *state) const
   result = rustyyparse (&parser);
 
   if (!result || (state->parse_completion && parser.rust_ast != NULL))
-    parser.convert_ast_to_expression (parser.rust_ast, parser.rust_ast);
+    {
+      expr::operation_up op
+	= parser.convert_ast_to_expression (parser.rust_ast, parser.rust_ast);
+      state->set_operation (std::move (op));
+    }
 
   return result;
 }
@@ -2840,6 +2852,30 @@ _initialize_rust_exp ()
      error.  */
   gdb_assert (code == 0);
 
+  using namespace expr;
+  maker_map[BINOP_SUBSCRIPT] = make_operation<rust_subscript_operation>;
+  maker_map[BINOP_MUL] = make_operation<mul_operation>;
+  maker_map[BINOP_REPEAT] = make_operation<repeat_operation>;
+  maker_map[BINOP_DIV] = make_operation<div_operation>;
+  maker_map[BINOP_REM] = make_operation<rem_operation>;
+  maker_map[BINOP_LESS] = make_operation<less_operation>;
+  maker_map[BINOP_GTR] = make_operation<gtr_operation>;
+  maker_map[BINOP_BITWISE_AND] = make_operation<bitwise_and_operation>;
+  maker_map[BINOP_BITWISE_IOR] = make_operation<bitwise_ior_operation>;
+  maker_map[BINOP_BITWISE_XOR] = make_operation<bitwise_xor_operation>;
+  maker_map[BINOP_ADD] = make_operation<add_operation>;
+  maker_map[BINOP_SUB] = make_operation<sub_operation>;
+  maker_map[BINOP_LOGICAL_OR] = make_operation<logical_or_operation>;
+  maker_map[BINOP_LOGICAL_AND] = make_operation<logical_and_operation>;
+  maker_map[BINOP_EQUAL] = make_operation<equal_operation>;
+  maker_map[BINOP_NOTEQUAL] = make_operation<notequal_operation>;
+  maker_map[BINOP_LEQ] = make_operation<leq_operation>;
+  maker_map[BINOP_GEQ] = make_operation<geq_operation>;
+  maker_map[BINOP_LSH] = make_operation<lsh_operation>;
+  maker_map[BINOP_RSH] = make_operation<rsh_operation>;
+  maker_map[BINOP_ASSIGN] = make_operation<assign_operation>;
+  maker_map[OP_RUST_ARRAY] = make_operation<rust_array_operation>;
+
 #if GDB_SELF_TEST
   selftests::register_test ("rust-lex", rust_lex_tests);
 #endif
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 178/203] Convert c-exp.y to use operations
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (176 preceding siblings ...)
  2021-01-01 21:46 ` [PATCH 177/203] Convert rust-exp.y to use operations Tom Tromey
@ 2021-01-01 21:46 ` Tom Tromey
  2021-01-01 21:46 ` [PATCH 179/203] Convert go-exp.y " Tom Tromey
                   ` (25 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:46 UTC (permalink / raw)
  To: gdb-patches

This converts the C parser to generate operations rather than
exp_elements.

One test needed a tweak in order to handle the different debugging
output.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* objc-lang.c (end_msglist): Create operations.
	* c-exp.y: Change parser to create operations.
	(write_destructor_name): Remove.
	(c_parse): Update.

gdb/testsuite/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* gdb.base/debug-expr.exp: Update expected dump output.
---
 gdb/ChangeLog                         |   7 +
 gdb/c-exp.y                           | 656 ++++++++++++++------------
 gdb/objc-lang.c                       |  10 +-
 gdb/testsuite/ChangeLog               |   4 +
 gdb/testsuite/gdb.base/debug-expr.exp |   4 +-
 5 files changed, 371 insertions(+), 310 deletions(-)

diff --git a/gdb/c-exp.y b/gdb/c-exp.y
index 140881d1517..37a7f2c9e56 100644
--- a/gdb/c-exp.y
+++ b/gdb/c-exp.y
@@ -55,6 +55,7 @@
 #include "cp-abi.h"
 #include "type-stack.h"
 #include "target-float.h"
+#include "c-exp.h"
 
 #define parse_type(ps) builtin_type (ps->gdbarch ())
 
@@ -123,6 +124,7 @@ static void yyerror (const char *);
 
 static int type_aggregate_p (struct type *);
 
+using namespace expr;
 %}
 
 /* Although the yacc "value" of an expression is not used,
@@ -164,8 +166,6 @@ static int parse_number (struct parser_state *par_state,
 static struct stoken operator_stoken (const char *);
 static struct stoken typename_stoken (const char *);
 static void check_parameter_typelist (std::vector<struct type *> *);
-static void write_destructor_name (struct parser_state *par_state,
-				   struct stoken);
 
 #ifdef YYBISON
 static void c_print_token (FILE *file, int type, YYSTYPE value);
@@ -282,190 +282,213 @@ start   :	exp1
 	;
 
 type_exp:	type
-			{ write_exp_elt_opcode(pstate, OP_TYPE);
-			  write_exp_elt_type(pstate, $1);
-			  write_exp_elt_opcode(pstate, OP_TYPE);}
+			{
+			  pstate->push_new<type_operation> ($1);
+			}
 	|	TYPEOF '(' exp ')'
 			{
-			  write_exp_elt_opcode (pstate, OP_TYPEOF);
+			  pstate->wrap<typeof_operation> ();
 			}
 	|	TYPEOF '(' type ')'
 			{
-			  write_exp_elt_opcode (pstate, OP_TYPE);
-			  write_exp_elt_type (pstate, $3);
-			  write_exp_elt_opcode (pstate, OP_TYPE);
+			  pstate->push_new<type_operation> ($3);
 			}
 	|	DECLTYPE '(' exp ')'
 			{
-			  write_exp_elt_opcode (pstate, OP_DECLTYPE);
+			  pstate->wrap<decltype_operation> ();
 			}
 	;
 
 /* Expressions, including the comma operator.  */
 exp1	:	exp
 	|	exp1 ',' exp
-			{ write_exp_elt_opcode (pstate, BINOP_COMMA); }
+			{ pstate->wrap2<comma_operation> (); }
 	;
 
 /* Expressions, not including the comma operator.  */
 exp	:	'*' exp    %prec UNARY
-			{ write_exp_elt_opcode (pstate, UNOP_IND); }
+			{ pstate->wrap<unop_ind_operation> (); }
 	;
 
 exp	:	'&' exp    %prec UNARY
-			{ write_exp_elt_opcode (pstate, UNOP_ADDR); }
+			{ pstate->wrap<unop_addr_operation> (); }
 	;
 
 exp	:	'-' exp    %prec UNARY
-			{ write_exp_elt_opcode (pstate, UNOP_NEG); }
+			{ pstate->wrap<unary_neg_operation> (); }
 	;
 
 exp	:	'+' exp    %prec UNARY
-			{ write_exp_elt_opcode (pstate, UNOP_PLUS); }
+			{ pstate->wrap<unary_plus_operation> (); }
 	;
 
 exp	:	'!' exp    %prec UNARY
-			{ write_exp_elt_opcode (pstate, UNOP_LOGICAL_NOT); }
+			{
+			  if (pstate->language ()->la_language
+			      == language_opencl)
+			    pstate->wrap<opencl_not_operation> ();
+			  else
+			    pstate->wrap<unary_logical_not_operation> ();
+			}
 	;
 
 exp	:	'~' exp    %prec UNARY
-			{ write_exp_elt_opcode (pstate, UNOP_COMPLEMENT); }
+			{ pstate->wrap<unary_complement_operation> (); }
 	;
 
 exp	:	INCREMENT exp    %prec UNARY
-			{ write_exp_elt_opcode (pstate, UNOP_PREINCREMENT); }
+			{ pstate->wrap<preinc_operation> (); }
 	;
 
 exp	:	DECREMENT exp    %prec UNARY
-			{ write_exp_elt_opcode (pstate, UNOP_PREDECREMENT); }
+			{ pstate->wrap<predec_operation> (); }
 	;
 
 exp	:	exp INCREMENT    %prec UNARY
-			{ write_exp_elt_opcode (pstate, UNOP_POSTINCREMENT); }
+			{ pstate->wrap<postinc_operation> (); }
 	;
 
 exp	:	exp DECREMENT    %prec UNARY
-			{ write_exp_elt_opcode (pstate, UNOP_POSTDECREMENT); }
+			{ pstate->wrap<postdec_operation> (); }
 	;
 
 exp	:	TYPEID '(' exp ')' %prec UNARY
-			{ write_exp_elt_opcode (pstate, OP_TYPEID); }
+			{ pstate->wrap<typeid_operation> (); }
 	;
 
 exp	:	TYPEID '(' type_exp ')' %prec UNARY
-			{ write_exp_elt_opcode (pstate, OP_TYPEID); }
+			{ pstate->wrap<typeid_operation> (); }
 	;
 
 exp	:	SIZEOF exp       %prec UNARY
-			{ write_exp_elt_opcode (pstate, UNOP_SIZEOF); }
+			{ pstate->wrap<unop_sizeof_operation> (); }
 	;
 
 exp	:	ALIGNOF '(' type_exp ')'	%prec UNARY
-			{ write_exp_elt_opcode (pstate, UNOP_ALIGNOF); }
+			{ pstate->wrap<unop_alignof_operation> (); }
 	;
 
 exp	:	exp ARROW field_name
-			{ write_exp_elt_opcode (pstate, STRUCTOP_PTR);
-			  write_exp_string (pstate, $3);
-			  write_exp_elt_opcode (pstate, STRUCTOP_PTR); }
+			{
+			  pstate->push_new<structop_ptr_operation>
+			    (pstate->pop (), copy_name ($3));
+			}
 	;
 
 exp	:	exp ARROW field_name COMPLETE
-			{ pstate->mark_struct_expression ();
-			  write_exp_elt_opcode (pstate, STRUCTOP_PTR);
-			  write_exp_string (pstate, $3);
-			  write_exp_elt_opcode (pstate, STRUCTOP_PTR); }
+			{
+			  structop_base_operation *op
+			    = new structop_ptr_operation (pstate->pop (),
+							  copy_name ($3));
+			  pstate->mark_struct_expression (op);
+			  pstate->push (operation_up (op));
+			}
 	;
 
 exp	:	exp ARROW COMPLETE
-			{ struct stoken s;
-			  pstate->mark_struct_expression ();
-			  write_exp_elt_opcode (pstate, STRUCTOP_PTR);
-			  s.ptr = "";
-			  s.length = 0;
-			  write_exp_string (pstate, s);
-			  write_exp_elt_opcode (pstate, STRUCTOP_PTR); }
+			{
+			  structop_base_operation *op
+			    = new structop_ptr_operation (pstate->pop (), "");
+			  pstate->mark_struct_expression (op);
+			  pstate->push (operation_up (op));
+			}
 	;
 
 exp	:	exp ARROW '~' name
-			{ write_exp_elt_opcode (pstate, STRUCTOP_PTR);
-			  write_destructor_name (pstate, $4);
-			  write_exp_elt_opcode (pstate, STRUCTOP_PTR); }
+			{
+			  pstate->push_new<structop_ptr_operation>
+			    (pstate->pop (), "~" + copy_name ($4));
+			}
 	;
 
 exp	:	exp ARROW '~' name COMPLETE
-			{ pstate->mark_struct_expression ();
-			  write_exp_elt_opcode (pstate, STRUCTOP_PTR);
-			  write_destructor_name (pstate, $4);
-			  write_exp_elt_opcode (pstate, STRUCTOP_PTR); }
+			{
+			  structop_base_operation *op
+			    = new structop_ptr_operation (pstate->pop (),
+							  "~" + copy_name ($4));
+			  pstate->mark_struct_expression (op);
+			  pstate->push (operation_up (op));
+			}
 	;
 
 exp	:	exp ARROW qualified_name
 			{ /* exp->type::name becomes exp->*(&type::name) */
 			  /* Note: this doesn't work if name is a
 			     static member!  FIXME */
-			  write_exp_elt_opcode (pstate, UNOP_ADDR);
-			  write_exp_elt_opcode (pstate, STRUCTOP_MPTR); }
+			  pstate->wrap<unop_addr_operation> ();
+			  pstate->wrap2<structop_mptr_operation> (); }
 	;
 
 exp	:	exp ARROW_STAR exp
-			{ write_exp_elt_opcode (pstate, STRUCTOP_MPTR); }
+			{ pstate->wrap2<structop_mptr_operation> (); }
 	;
 
 exp	:	exp '.' field_name
-			{ write_exp_elt_opcode (pstate, STRUCTOP_STRUCT);
-			  write_exp_string (pstate, $3);
-			  write_exp_elt_opcode (pstate, STRUCTOP_STRUCT); }
+			{
+			  if (pstate->language ()->la_language
+			      == language_opencl)
+			    pstate->push_new<opencl_structop_operation>
+			      (pstate->pop (), copy_name ($3));
+			  else
+			    pstate->push_new<structop_operation>
+			      (pstate->pop (), copy_name ($3));
+			}
 	;
 
 exp	:	exp '.' field_name COMPLETE
-			{ pstate->mark_struct_expression ();
-			  write_exp_elt_opcode (pstate, STRUCTOP_STRUCT);
-			  write_exp_string (pstate, $3);
-			  write_exp_elt_opcode (pstate, STRUCTOP_STRUCT); }
+			{
+			  structop_base_operation *op
+			    = new structop_operation (pstate->pop (),
+						      copy_name ($3));
+			  pstate->mark_struct_expression (op);
+			  pstate->push (operation_up (op));
+			}
 	;
 
 exp	:	exp '.' COMPLETE
-			{ struct stoken s;
-			  pstate->mark_struct_expression ();
-			  write_exp_elt_opcode (pstate, STRUCTOP_STRUCT);
-			  s.ptr = "";
-			  s.length = 0;
-			  write_exp_string (pstate, s);
-			  write_exp_elt_opcode (pstate, STRUCTOP_STRUCT); }
+			{
+			  structop_base_operation *op
+			    = new structop_operation (pstate->pop (), "");
+			  pstate->mark_struct_expression (op);
+			  pstate->push (operation_up (op));
+			}
 	;
 
 exp	:	exp '.' '~' name
-			{ write_exp_elt_opcode (pstate, STRUCTOP_STRUCT);
-			  write_destructor_name (pstate, $4);
-			  write_exp_elt_opcode (pstate, STRUCTOP_STRUCT); }
+			{
+			  pstate->push_new<structop_operation>
+			    (pstate->pop (), "~" + copy_name ($4));
+			}
 	;
 
 exp	:	exp '.' '~' name COMPLETE
-			{ pstate->mark_struct_expression ();
-			  write_exp_elt_opcode (pstate, STRUCTOP_STRUCT);
-			  write_destructor_name (pstate, $4);
-			  write_exp_elt_opcode (pstate, STRUCTOP_STRUCT); }
+			{
+			  structop_base_operation *op
+			    = new structop_operation (pstate->pop (),
+						      "~" + copy_name ($4));
+			  pstate->mark_struct_expression (op);
+			  pstate->push (operation_up (op));
+			}
 	;
 
 exp	:	exp '.' qualified_name
 			{ /* exp.type::name becomes exp.*(&type::name) */
 			  /* Note: this doesn't work if name is a
 			     static member!  FIXME */
-			  write_exp_elt_opcode (pstate, UNOP_ADDR);
-			  write_exp_elt_opcode (pstate, STRUCTOP_MEMBER); }
+			  pstate->wrap<unop_addr_operation> ();
+			  pstate->wrap2<structop_member_operation> (); }
 	;
 
 exp	:	exp DOT_STAR exp
-			{ write_exp_elt_opcode (pstate, STRUCTOP_MEMBER); }
+			{ pstate->wrap2<structop_member_operation> (); }
 	;
 
 exp	:	exp '[' exp1 ']'
-			{ write_exp_elt_opcode (pstate, BINOP_SUBSCRIPT); }
+			{ pstate->wrap2<subscript_operation> (); }
 	;
 
 exp	:	exp OBJC_LBRAC exp1 ']'
-			{ write_exp_elt_opcode (pstate, BINOP_SUBSCRIPT); }
+			{ pstate->wrap2<subscript_operation> (); }
 	;
 
 /*
@@ -483,43 +506,30 @@ exp	: 	OBJC_LBRAC TYPENAME
 			  if (theclass == 0)
 			    error (_("%s is not an ObjC Class"),
 				   copy.c_str ());
-			  write_exp_elt_opcode (pstate, OP_LONG);
-			  write_exp_elt_type (pstate,
-					      parse_type (pstate)->builtin_int);
-			  write_exp_elt_longcst (pstate, (LONGEST) theclass);
-			  write_exp_elt_opcode (pstate, OP_LONG);
+			  pstate->push_new<long_const_operation>
+			    (parse_type (pstate)->builtin_int,
+			     (LONGEST) theclass);
 			  start_msglist();
 			}
 		msglist ']'
-			{ write_exp_elt_opcode (pstate, OP_OBJC_MSGCALL);
-			  end_msglist (pstate);
-			  write_exp_elt_opcode (pstate, OP_OBJC_MSGCALL);
-			}
+			{ end_msglist (pstate); }
 	;
 
 exp	:	OBJC_LBRAC CLASSNAME
 			{
-			  write_exp_elt_opcode (pstate, OP_LONG);
-			  write_exp_elt_type (pstate,
-					    parse_type (pstate)->builtin_int);
-			  write_exp_elt_longcst (pstate, (LONGEST) $2.theclass);
-			  write_exp_elt_opcode (pstate, OP_LONG);
+			  pstate->push_new<long_const_operation>
+			    (parse_type (pstate)->builtin_int,
+			     (LONGEST) $2.theclass);
 			  start_msglist();
 			}
 		msglist ']'
-			{ write_exp_elt_opcode (pstate, OP_OBJC_MSGCALL);
-			  end_msglist (pstate);
-			  write_exp_elt_opcode (pstate, OP_OBJC_MSGCALL);
-			}
+			{ end_msglist (pstate); }
 	;
 
 exp	:	OBJC_LBRAC exp
 			{ start_msglist(); }
 		msglist ']'
-			{ write_exp_elt_opcode (pstate, OP_OBJC_MSGCALL);
-			  end_msglist (pstate);
-			  write_exp_elt_opcode (pstate, OP_OBJC_MSGCALL);
-			}
+			{ end_msglist (pstate); }
 	;
 
 msglist :	name
@@ -544,21 +554,22 @@ exp	:	exp '('
 			   being accumulated by an outer function call.  */
 			{ pstate->start_arglist (); }
 		arglist ')'	%prec ARROW
-			{ write_exp_elt_opcode (pstate, OP_FUNCALL);
-			  write_exp_elt_longcst (pstate,
-						 pstate->end_arglist ());
-			  write_exp_elt_opcode (pstate, OP_FUNCALL); }
+			{
+			  std::vector<operation_up> args
+			    = pstate->pop_vector (pstate->end_arglist ());
+			  pstate->push_new<funcall_operation>
+			    (pstate->pop (), std::move (args));
+			}
 	;
 
 /* This is here to disambiguate with the production for
    "func()::static_var" further below, which uses
    function_method_void.  */
 exp	:	exp '(' ')' %prec ARROW
-			{ pstate->start_arglist ();
-			  write_exp_elt_opcode (pstate, OP_FUNCALL);
-			  write_exp_elt_longcst (pstate,
-						 pstate->end_arglist ());
-			  write_exp_elt_opcode (pstate, OP_FUNCALL); }
+			{
+			  pstate->push_new<funcall_operation>
+			    (pstate->pop (), std::vector<operation_up> ());
+			}
 	;
 
 
@@ -566,25 +577,18 @@ exp	:	UNKNOWN_CPP_NAME '('
 			{
 			  /* This could potentially be a an argument defined
 			     lookup function (Koenig).  */
-			  write_exp_elt_opcode (pstate, OP_ADL_FUNC);
-			  write_exp_elt_block
-			    (pstate, pstate->expression_context_block);
-			  write_exp_elt_sym (pstate,
-					     NULL); /* Placeholder.  */
-			  write_exp_string (pstate, $1.stoken);
-			  write_exp_elt_opcode (pstate, OP_ADL_FUNC);
-
-			/* This is to save the value of arglist_len
-			   being accumulated by an outer function call.  */
-
+			  /* This is to save the value of arglist_len
+			     being accumulated by an outer function call.  */
 			  pstate->start_arglist ();
 			}
 		arglist ')'	%prec ARROW
 			{
-			  write_exp_elt_opcode (pstate, OP_FUNCALL);
-			  write_exp_elt_longcst (pstate,
-						 pstate->end_arglist ());
-			  write_exp_elt_opcode (pstate, OP_FUNCALL);
+			  std::vector<operation_up> args
+			    = pstate->pop_vector (pstate->end_arglist ());
+			  pstate->push_new<adl_func_operation>
+			    (copy_name ($1.stoken),
+			     pstate->expression_context_block,
+			     std::move (args));
 			}
 	;
 
@@ -606,33 +610,25 @@ arglist	:	arglist ',' exp   %prec ABOVE_COMMA
 function_method:       exp '(' parameter_typelist ')' const_or_volatile
 			{
 			  std::vector<struct type *> *type_list = $3;
-			  LONGEST len = type_list->size ();
-
-			  write_exp_elt_opcode (pstate, TYPE_INSTANCE);
 			  /* Save the const/volatile qualifiers as
 			     recorded by the const_or_volatile
 			     production's actions.  */
-			  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);
-			  write_exp_elt_longcst(pstate, len);
-			  write_exp_elt_opcode (pstate, TYPE_INSTANCE);
+			  type_instance_flags flags
+			    = (cpstate->type_stack
+			       .follow_type_instance_flags ());
+			  pstate->push_new<type_instance_operation>
+			    (flags, std::move (*type_list),
+			     pstate->pop ());
 			}
 	;
 
 function_method_void:	    exp '(' ')' const_or_volatile
-		       { write_exp_elt_opcode (pstate, TYPE_INSTANCE);
-			 /* See above.  */
-			 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);
+		       {
+			  type_instance_flags flags
+			    = (cpstate->type_stack
+			       .follow_type_instance_flags ());
+			  pstate->push_new<type_instance_operation>
+			    (flags, std::vector<type *> (), pstate->pop ());
 		       }
        ;
 
@@ -649,9 +645,8 @@ function_method_void_or_typelist: function_method
 
 exp     :       function_method_void_or_typelist COLONCOLON name
 			{
-			  write_exp_elt_opcode (pstate, OP_FUNC_STATIC_VAR);
-			  write_exp_string (pstate, $3);
-			  write_exp_elt_opcode (pstate, OP_FUNC_STATIC_VAR);
+			  pstate->push_new<func_static_var_operation>
+			    (pstate->pop (), copy_name ($3));
 			}
 	;
 
@@ -659,18 +654,26 @@ rcurly	:	'}'
 			{ $$ = pstate->end_arglist () - 1; }
 	;
 exp	:	lcurly arglist rcurly	%prec ARROW
-			{ write_exp_elt_opcode (pstate, OP_ARRAY);
-			  write_exp_elt_longcst (pstate, (LONGEST) 0);
-			  write_exp_elt_longcst (pstate, (LONGEST) $3);
-			  write_exp_elt_opcode (pstate, OP_ARRAY); }
+			{
+			  std::vector<operation_up> args
+			    = pstate->pop_vector ($3 + 1);
+			  pstate->push_new<array_operation> (0, $3,
+							     std::move (args));
+			}
 	;
 
 exp	:	lcurly type_exp rcurly exp  %prec UNARY
-			{ write_exp_elt_opcode (pstate, UNOP_MEMVAL_TYPE); }
+			{ pstate->wrap2<unop_memval_type_operation> (); }
 	;
 
 exp	:	'(' type_exp ')' exp  %prec UNARY
-			{ write_exp_elt_opcode (pstate, UNOP_CAST_TYPE); }
+			{
+			  if (pstate->language ()->la_language
+			      == language_opencl)
+			    pstate->wrap2<opencl_cast_type_operation> ();
+			  else
+			    pstate->wrap2<unop_cast_type_operation> ();
+			}
 	;
 
 exp	:	'(' exp1 ')'
@@ -680,116 +683,194 @@ exp	:	'(' exp1 ')'
 /* Binary operators in order of decreasing precedence.  */
 
 exp	:	exp '@' exp
-			{ write_exp_elt_opcode (pstate, BINOP_REPEAT); }
+			{ pstate->wrap2<repeat_operation> (); }
 	;
 
 exp	:	exp '*' exp
-			{ write_exp_elt_opcode (pstate, BINOP_MUL); }
+			{ pstate->wrap2<mul_operation> (); }
 	;
 
 exp	:	exp '/' exp
-			{ write_exp_elt_opcode (pstate, BINOP_DIV); }
+			{ pstate->wrap2<div_operation> (); }
 	;
 
 exp	:	exp '%' exp
-			{ write_exp_elt_opcode (pstate, BINOP_REM); }
+			{ pstate->wrap2<rem_operation> (); }
 	;
 
 exp	:	exp '+' exp
-			{ write_exp_elt_opcode (pstate, BINOP_ADD); }
+			{ pstate->wrap2<add_operation> (); }
 	;
 
 exp	:	exp '-' exp
-			{ write_exp_elt_opcode (pstate, BINOP_SUB); }
+			{ pstate->wrap2<sub_operation> (); }
 	;
 
 exp	:	exp LSH exp
-			{ write_exp_elt_opcode (pstate, BINOP_LSH); }
+			{ pstate->wrap2<lsh_operation> (); }
 	;
 
 exp	:	exp RSH exp
-			{ write_exp_elt_opcode (pstate, BINOP_RSH); }
+			{ pstate->wrap2<rsh_operation> (); }
 	;
 
 exp	:	exp EQUAL exp
-			{ write_exp_elt_opcode (pstate, BINOP_EQUAL); }
+			{
+			  if (pstate->language ()->la_language
+			      == language_opencl)
+			    pstate->wrap2<opencl_equal_operation> ();
+			  else
+			    pstate->wrap2<equal_operation> ();
+			}
 	;
 
 exp	:	exp NOTEQUAL exp
-			{ write_exp_elt_opcode (pstate, BINOP_NOTEQUAL); }
+			{
+			  if (pstate->language ()->la_language
+			      == language_opencl)
+			    pstate->wrap2<opencl_notequal_operation> ();
+			  else
+			    pstate->wrap2<notequal_operation> ();
+			}
 	;
 
 exp	:	exp LEQ exp
-			{ write_exp_elt_opcode (pstate, BINOP_LEQ); }
+			{
+			  if (pstate->language ()->la_language
+			      == language_opencl)
+			    pstate->wrap2<opencl_leq_operation> ();
+			  else
+			    pstate->wrap2<leq_operation> ();
+			}
 	;
 
 exp	:	exp GEQ exp
-			{ write_exp_elt_opcode (pstate, BINOP_GEQ); }
+			{
+			  if (pstate->language ()->la_language
+			      == language_opencl)
+			    pstate->wrap2<opencl_geq_operation> ();
+			  else
+			    pstate->wrap2<geq_operation> ();
+			}
 	;
 
 exp	:	exp '<' exp
-			{ write_exp_elt_opcode (pstate, BINOP_LESS); }
+			{
+			  if (pstate->language ()->la_language
+			      == language_opencl)
+			    pstate->wrap2<opencl_less_operation> ();
+			  else
+			    pstate->wrap2<less_operation> ();
+			}
 	;
 
 exp	:	exp '>' exp
-			{ write_exp_elt_opcode (pstate, BINOP_GTR); }
+			{
+			  if (pstate->language ()->la_language
+			      == language_opencl)
+			    pstate->wrap2<opencl_gtr_operation> ();
+			  else
+			    pstate->wrap2<gtr_operation> ();
+			}
 	;
 
 exp	:	exp '&' exp
-			{ write_exp_elt_opcode (pstate, BINOP_BITWISE_AND); }
+			{ pstate->wrap2<bitwise_and_operation> (); }
 	;
 
 exp	:	exp '^' exp
-			{ write_exp_elt_opcode (pstate, BINOP_BITWISE_XOR); }
+			{ pstate->wrap2<bitwise_xor_operation> (); }
 	;
 
 exp	:	exp '|' exp
-			{ write_exp_elt_opcode (pstate, BINOP_BITWISE_IOR); }
+			{ pstate->wrap2<bitwise_ior_operation> (); }
 	;
 
 exp	:	exp ANDAND exp
-			{ write_exp_elt_opcode (pstate, BINOP_LOGICAL_AND); }
+			{
+			  if (pstate->language ()->la_language
+			      == language_opencl)
+			    {
+			      operation_up rhs = pstate->pop ();
+			      operation_up lhs = pstate->pop ();
+			      pstate->push_new<opencl_logical_binop_operation>
+				(BINOP_LOGICAL_AND, std::move (lhs),
+				 std::move (rhs));
+			    }
+			  else
+			    pstate->wrap2<logical_and_operation> ();
+			}
 	;
 
 exp	:	exp OROR exp
-			{ write_exp_elt_opcode (pstate, BINOP_LOGICAL_OR); }
+			{
+			  if (pstate->language ()->la_language
+			      == language_opencl)
+			    {
+			      operation_up rhs = pstate->pop ();
+			      operation_up lhs = pstate->pop ();
+			      pstate->push_new<opencl_logical_binop_operation>
+				(BINOP_LOGICAL_OR, std::move (lhs),
+				 std::move (rhs));
+			    }
+			  else
+			    pstate->wrap2<logical_or_operation> ();
+			}
 	;
 
 exp	:	exp '?' exp ':' exp	%prec '?'
-			{ write_exp_elt_opcode (pstate, TERNOP_COND); }
+			{
+			  operation_up last = pstate->pop ();
+			  operation_up mid = pstate->pop ();
+			  operation_up first = pstate->pop ();
+			  if (pstate->language ()->la_language
+			      == language_opencl)
+			    pstate->push_new<opencl_ternop_cond_operation>
+			      (std::move (first), std::move (mid),
+			       std::move (last));
+			  else
+			    pstate->push_new<ternop_cond_operation>
+			      (std::move (first), std::move (mid),
+			       std::move (last));
+			}
 	;
 
 exp	:	exp '=' exp
-			{ write_exp_elt_opcode (pstate, BINOP_ASSIGN); }
+			{
+			  if (pstate->language ()->la_language
+			      == language_opencl)
+			    pstate->wrap2<opencl_assign_operation> ();
+			  else
+			    pstate->wrap2<assign_operation> ();
+			}
 	;
 
 exp	:	exp ASSIGN_MODIFY exp
-			{ write_exp_elt_opcode (pstate, BINOP_ASSIGN_MODIFY);
-			  write_exp_elt_opcode (pstate, $2);
-			  write_exp_elt_opcode (pstate,
-						BINOP_ASSIGN_MODIFY); }
+			{
+			  operation_up rhs = pstate->pop ();
+			  operation_up lhs = pstate->pop ();
+			  pstate->push_new<assign_modify_operation>
+			    ($2, std::move (lhs), std::move (rhs));
+			}
 	;
 
 exp	:	INT
-			{ write_exp_elt_opcode (pstate, OP_LONG);
-			  write_exp_elt_type (pstate, $1.type);
-			  write_exp_elt_longcst (pstate, (LONGEST) ($1.val));
-			  write_exp_elt_opcode (pstate, OP_LONG); }
+			{
+			  pstate->push_new<long_const_operation>
+			    ($1.type, $1.val);
+			}
 	;
 
 exp	:	COMPLEX_INT
 			{
-			  write_exp_elt_opcode (pstate, OP_LONG);
-			  write_exp_elt_type (pstate, TYPE_TARGET_TYPE ($1.type));
-			  write_exp_elt_longcst (pstate, 0);
-			  write_exp_elt_opcode (pstate, OP_LONG);
-			  write_exp_elt_opcode (pstate, OP_LONG);
-			  write_exp_elt_type (pstate, TYPE_TARGET_TYPE ($1.type));
-			  write_exp_elt_longcst (pstate, (LONGEST) ($1.val));
-			  write_exp_elt_opcode (pstate, OP_LONG);
-			  write_exp_elt_opcode (pstate, OP_COMPLEX);
-			  write_exp_elt_type (pstate, $1.type);
-			  write_exp_elt_opcode (pstate, OP_COMPLEX);
+			  operation_up real
+			    = (make_operation<long_const_operation>
+			       (TYPE_TARGET_TYPE ($1.type), 0));
+			  operation_up imag
+			    = (make_operation<long_const_operation>
+			       (TYPE_TARGET_TYPE ($1.type), $1.val));
+			  pstate->push_new<complex_operation>
+			    (std::move (real), std::move (imag), $1.type);
 			}
 	;
 
@@ -798,7 +879,7 @@ exp	:	CHAR
 			  struct stoken_vector vec;
 			  vec.len = 1;
 			  vec.tokens = &$1;
-			  write_exp_string_vector (pstate, $1.type, &vec);
+			  pstate->push_c_string ($1.type, &vec);
 			}
 	;
 
@@ -806,20 +887,20 @@ exp	:	NAME_OR_INT
 			{ YYSTYPE val;
 			  parse_number (pstate, $1.stoken.ptr,
 					$1.stoken.length, 0, &val);
-			  write_exp_elt_opcode (pstate, OP_LONG);
-			  write_exp_elt_type (pstate, val.typed_val_int.type);
-			  write_exp_elt_longcst (pstate,
-					    (LONGEST) val.typed_val_int.val);
-			  write_exp_elt_opcode (pstate, OP_LONG);
+			  pstate->push_new<long_const_operation>
+			    (val.typed_val_int.type,
+			     val.typed_val_int.val);
 			}
 	;
 
 
 exp	:	FLOAT
-			{ write_exp_elt_opcode (pstate, OP_FLOAT);
-			  write_exp_elt_type (pstate, $1.type);
-			  write_exp_elt_floatcst (pstate, $1.val);
-			  write_exp_elt_opcode (pstate, OP_FLOAT); }
+			{
+			  float_data data;
+			  std::copy (std::begin ($1.val), std::end ($1.val),
+				     std::begin (data));
+			  pstate->push_new<float_const_operation> ($1.type, data);
+			}
 	;
 
 exp	:	COMPLEX_FLOAT
@@ -827,19 +908,22 @@ exp	:	COMPLEX_FLOAT
 			  struct type *underlying
 			    = TYPE_TARGET_TYPE ($1.type);
 
-			  write_exp_elt_opcode (pstate, OP_FLOAT);
-			  write_exp_elt_type (pstate, underlying);
-			  gdb_byte val[16];
-			  target_float_from_host_double (val, underlying, 0);
-			  write_exp_elt_floatcst (pstate, val);
-			  write_exp_elt_opcode (pstate, OP_FLOAT);
-			  write_exp_elt_opcode (pstate, OP_FLOAT);
-			  write_exp_elt_type (pstate, underlying);
-			  write_exp_elt_floatcst (pstate, $1.val);
-			  write_exp_elt_opcode (pstate, OP_FLOAT);
-			  write_exp_elt_opcode (pstate, OP_COMPLEX);
-			  write_exp_elt_type (pstate, $1.type);
-			  write_exp_elt_opcode (pstate, OP_COMPLEX);
+			  float_data val;
+			  target_float_from_host_double (val.data (),
+							 underlying, 0);
+			  operation_up real
+			    = (make_operation<float_const_operation>
+			       (underlying, val));
+
+			  std::copy (std::begin ($1.val), std::end ($1.val),
+				     std::begin (val));
+			  operation_up imag
+			    = (make_operation<float_const_operation>
+			       (underlying, val));
+
+			  pstate->push_new<complex_operation>
+			    (std::move (real), std::move (imag),
+			     $1.type);
 			}
 	;
 
@@ -848,23 +932,22 @@ exp	:	variable
 
 exp	:	DOLLAR_VARIABLE
 			{
-			  write_dollar_variable (pstate, $1);
+			  pstate->push_dollar ($1);
 			}
 	;
 
 exp	:	SELECTOR '(' name ')'
 			{
-			  write_exp_elt_opcode (pstate, OP_OBJC_SELECTOR);
-			  write_exp_string (pstate, $3);
-			  write_exp_elt_opcode (pstate, OP_OBJC_SELECTOR); }
+			  pstate->push_new<objc_selector_operation>
+			    (copy_name ($3));
+			}
 	;
 
 exp	:	SIZEOF '(' type ')'	%prec UNARY
 			{ struct type *type = $3;
-			  write_exp_elt_opcode (pstate, OP_LONG);
-			  write_exp_elt_type (pstate, lookup_signed_typename
-					      (pstate->language (),
-					       "int"));
+			  struct type *int_type
+			    = lookup_signed_typename (pstate->language (),
+						      "int");
 			  type = check_typedef (type);
 
 			    /* $5.3.3/2 of the C++ Standard (n3290 draft)
@@ -873,28 +956,27 @@ exp	:	SIZEOF '(' type ')'	%prec UNARY
 			       the referenced type."  */
 			  if (TYPE_IS_REFERENCE (type))
 			    type = check_typedef (TYPE_TARGET_TYPE (type));
-			  write_exp_elt_longcst (pstate,
-						 (LONGEST) TYPE_LENGTH (type));
-			  write_exp_elt_opcode (pstate, OP_LONG); }
+			  pstate->push_new<long_const_operation>
+			    (int_type, TYPE_LENGTH (type));
+			}
 	;
 
 exp	:	REINTERPRET_CAST '<' type_exp '>' '(' exp ')' %prec UNARY
-			{ write_exp_elt_opcode (pstate,
-						UNOP_REINTERPRET_CAST); }
+			{ pstate->wrap2<reinterpret_cast_operation> (); }
 	;
 
 exp	:	STATIC_CAST '<' type_exp '>' '(' exp ')' %prec UNARY
-			{ write_exp_elt_opcode (pstate, UNOP_CAST_TYPE); }
+			{ pstate->wrap2<unop_cast_type_operation> (); }
 	;
 
 exp	:	DYNAMIC_CAST '<' type_exp '>' '(' exp ')' %prec UNARY
-			{ write_exp_elt_opcode (pstate, UNOP_DYNAMIC_CAST); }
+			{ pstate->wrap2<dynamic_cast_operation> (); }
 	;
 
 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 (pstate, UNOP_CAST_TYPE); }
+			  pstate->wrap2<unop_cast_type_operation> (); }
 	;
 
 string_exp:
@@ -959,7 +1041,7 @@ exp	:	string_exp
 				}
 			    }
 
-			  write_exp_string_vector (pstate, type, &$1);
+			  pstate->push_c_string (type, &$1);
 			  for (i = 0; i < $1.len; ++i)
 			    free ($1.tokens[i].ptr);
 			  free ($1.tokens);
@@ -969,26 +1051,23 @@ exp	:	string_exp
 exp     :	NSSTRING	/* ObjC NextStep NSString constant
 				 * of the form '@' '"' string '"'.
 				 */
-			{ write_exp_elt_opcode (pstate, OP_OBJC_NSSTRING);
-			  write_exp_string (pstate, $1);
-			  write_exp_elt_opcode (pstate, OP_OBJC_NSSTRING); }
+			{
+			  pstate->push_new<objc_nsstring_operation>
+			    (copy_name ($1));
+			}
 	;
 
 /* C++.  */
 exp     :       TRUEKEYWORD
-			{ write_exp_elt_opcode (pstate, OP_LONG);
-			  write_exp_elt_type (pstate,
-					  parse_type (pstate)->builtin_bool);
-			  write_exp_elt_longcst (pstate, (LONGEST) 1);
-			  write_exp_elt_opcode (pstate, OP_LONG); }
+			{ pstate->push_new<long_const_operation>
+			    (parse_type (pstate)->builtin_bool, 1);
+			}
 	;
 
 exp     :       FALSEKEYWORD
-			{ write_exp_elt_opcode (pstate, OP_LONG);
-			  write_exp_elt_type (pstate,
-					  parse_type (pstate)->builtin_bool);
-			  write_exp_elt_longcst (pstate, (LONGEST) 0);
-			  write_exp_elt_opcode (pstate, OP_LONG); }
+			{ pstate->push_new<long_const_operation>
+			    (parse_type (pstate)->builtin_bool, 0);
+			}
 	;
 
 /* end of C++.  */
@@ -1029,9 +1108,7 @@ variable:	name_not_typename ENTRY
 				     "parameters, not for \"%s\""),
 				   copy_name ($1.stoken).c_str ());
 
-			  write_exp_elt_opcode (pstate, OP_VAR_ENTRY_VALUE);
-			  write_exp_elt_sym (pstate, sym);
-			  write_exp_elt_opcode (pstate, OP_VAR_ENTRY_VALUE);
+			  pstate->push_new<var_entry_value_operation> (sym);
 			}
 	;
 
@@ -1048,10 +1125,9 @@ variable:	block COLONCOLON name
 			  if (symbol_read_needs_frame (sym.symbol))
 			    pstate->block_tracker->update (sym);
 
-			  write_exp_elt_opcode (pstate, OP_VAR_VALUE);
-			  write_exp_elt_block (pstate, sym.block);
-			  write_exp_elt_sym (pstate, sym.symbol);
-			  write_exp_elt_opcode (pstate, OP_VAR_VALUE); }
+			  pstate->push_new<var_value_operation> (sym.symbol,
+								 sym.block);
+			}
 	;
 
 qualified_name:	TYPENAME COLONCOLON name
@@ -1062,34 +1138,24 @@ qualified_name:	TYPENAME COLONCOLON name
 			    error (_("`%s' is not defined as an aggregate type."),
 				   TYPE_SAFE_NAME (type));
 
-			  write_exp_elt_opcode (pstate, OP_SCOPE);
-			  write_exp_elt_type (pstate, type);
-			  write_exp_string (pstate, $3);
-			  write_exp_elt_opcode (pstate, OP_SCOPE);
+			  pstate->push_new<scope_operation> (type,
+							     copy_name ($3));
 			}
 	|	TYPENAME COLONCOLON '~' name
 			{
 			  struct type *type = $1.type;
-			  struct stoken tmp_token;
-			  char *buf;
 
 			  type = check_typedef (type);
 			  if (!type_aggregate_p (type))
 			    error (_("`%s' is not defined as an aggregate type."),
 				   TYPE_SAFE_NAME (type));
-			  buf = (char *) alloca ($4.length + 2);
-			  tmp_token.ptr = buf;
-			  tmp_token.length = $4.length + 1;
-			  buf[0] = '~';
-			  memcpy (buf+1, $4.ptr, $4.length);
-			  buf[tmp_token.length] = 0;
+			  std::string name = "~" + std::string ($4.ptr,
+								$4.length);
 
 			  /* Check for valid destructor name.  */
-			  destructor_name_p (tmp_token.ptr, $1.type);
-			  write_exp_elt_opcode (pstate, OP_SCOPE);
-			  write_exp_elt_type (pstate, type);
-			  write_exp_string (pstate, tmp_token);
-			  write_exp_elt_opcode (pstate, OP_SCOPE);
+			  destructor_name_p (name.c_str (), $1.type);
+			  pstate->push_new<scope_operation> (type,
+							     std::move (name));
 			}
 	|	TYPENAME COLONCOLON name COLONCOLON name
 			{
@@ -1108,8 +1174,7 @@ variable:	qualified_name
 			    = lookup_symbol (name.c_str (),
 					     (const struct block *) NULL,
 					     VAR_DOMAIN, NULL).symbol;
-			  write_exp_symbol_reference (pstate, name.c_str (),
-						      sym);
+			  pstate->push_symbol (name.c_str (), sym);
 			}
 	;
 
@@ -1129,14 +1194,11 @@ variable:	name_not_typename
 			      bound_minimal_symbol resolver
 				= find_gnu_ifunc (sym.symbol);
 			      if (resolver.minsym != NULL)
-				write_exp_msymbol (pstate, resolver);
+				pstate->push_new<var_msym_value_operation>
+				  (resolver.minsym, resolver.objfile);
 			      else
-				{
-				  write_exp_elt_opcode (pstate, OP_VAR_VALUE);
-				  write_exp_elt_block (pstate, sym.block);
-				  write_exp_elt_sym (pstate, sym.symbol);
-				  write_exp_elt_opcode (pstate, OP_VAR_VALUE);
-				}
+				pstate->push_new<var_value_operation>
+				  (sym.symbol, sym.block);
 			    }
 			  else if ($1.is_a_field_of_this)
 			    {
@@ -1144,11 +1206,10 @@ variable:	name_not_typename
 				 not inadvertently convert from a method call
 				 to data ref.  */
 			      pstate->block_tracker->update (sym);
-			      write_exp_elt_opcode (pstate, OP_THIS);
-			      write_exp_elt_opcode (pstate, OP_THIS);
-			      write_exp_elt_opcode (pstate, STRUCTOP_PTR);
-			      write_exp_string (pstate, $1.stoken);
-			      write_exp_elt_opcode (pstate, STRUCTOP_PTR);
+			      operation_up thisop
+				= make_operation<op_this_operation> ();
+			      pstate->push_new<structop_ptr_operation>
+				(std::move (thisop), copy_name ($1.stoken));
 			    }
 			  else
 			    {
@@ -1178,15 +1239,11 @@ variable:	name_not_typename
 				   ? find_function_alias_target (msymbol)
 				   : NULL);
 			      if (alias_target != NULL)
-				{
-				  write_exp_elt_opcode (pstate, OP_VAR_VALUE);
-				  write_exp_elt_block
-				    (pstate, SYMBOL_BLOCK_VALUE (alias_target));
-				  write_exp_elt_sym (pstate, alias_target);
-				  write_exp_elt_opcode (pstate, OP_VAR_VALUE);
-				}
+				pstate->push_new<var_value_operation>
+				  (alias_target, SYMBOL_BLOCK_VALUE (alias_target));
 			      else
-				write_exp_msymbol (pstate, msymbol);
+				pstate->push_new<var_msym_value_operation>
+				  (msymbol.minsym, msymbol.objfile);
 			    }
 			}
 	;
@@ -1783,22 +1840,6 @@ name_not_typename :	NAME
 
 %%
 
-/* Like write_exp_string, but prepends a '~'.  */
-
-static void
-write_destructor_name (struct parser_state *par_state, struct stoken token)
-{
-  char *copy = (char *) alloca (token.length + 1);
-
-  copy[0] = '~';
-  memcpy (&copy[1], token.ptr, token.length);
-
-  token.ptr = copy;
-  ++token.length;
-
-  write_exp_string (par_state, token);
-}
-
 /* Returns a stoken of the operator name given by OP (which does not
    include the string "operator").  */
 
@@ -3393,7 +3434,10 @@ c_parse (struct parser_state *par_state)
   popping = 0;
   name_obstack.clear ();
 
-  return yyparse ();
+  int result = yyparse ();
+  if (!result)
+    pstate->set_operation (pstate->pop ());
+  return result;
 }
 
 #ifdef YYBISON
diff --git a/gdb/objc-lang.c b/gdb/objc-lang.c
index 67896284720..aa0360b6818 100644
--- a/gdb/objc-lang.c
+++ b/gdb/objc-lang.c
@@ -43,6 +43,7 @@
 #include "infcall.h"
 #include "valprint.h"
 #include "cli/cli-utils.h"
+#include "c-exp.h"
 
 #include <ctype.h>
 #include <algorithm>
@@ -507,15 +508,20 @@ end_msglist (struct parser_state *ps)
   char *p = msglist_sel;
   CORE_ADDR selid;
 
+  std::vector<expr::operation_up> args = ps->pop_vector (val);
+  expr::operation_up target = ps->pop ();
+  
   selname_chain = sel->next;
   msglist_len = sel->msglist_len;
   msglist_sel = sel->msglist_sel;
   selid = lookup_child_selector (ps->gdbarch (), p);
   if (!selid)
     error (_("Can't find selector \"%s\""), p);
-  write_exp_elt_longcst (ps, selid);
+
+  ps->push_new<expr::objc_msgcall_operation> (selid, std::move (target),
+					      std::move (args));
+
   xfree(p);
-  write_exp_elt_longcst (ps, val);	/* Number of args */
   xfree(sel);
 
   return val;
diff --git a/gdb/testsuite/gdb.base/debug-expr.exp b/gdb/testsuite/gdb.base/debug-expr.exp
index 068c88a3e36..77cf030d906 100644
--- a/gdb/testsuite/gdb.base/debug-expr.exp
+++ b/gdb/testsuite/gdb.base/debug-expr.exp
@@ -45,10 +45,10 @@ gdb_test_debug_expr "print /x {char\[4\]} array" \
 
 # This caused gdb to output garbage and possibly segfault
 gdb_test_debug_expr "print \"hello\"" \
-    ".*OP_STRING\[^\r\n\]*Language-specific string type: 0.*\[\r\n\]\\$$decimal = \"hello\"" \
+    ".*OP_STRING\[^\r\n\]*.*: ordinary string.*\[\r\n\]\\$$decimal = \"hello\"" \
     "string evaluation with debug expr"
 
 # An expression using a function call.
 gdb_test_debug_expr "print call_me ( &val )" \
-    ".*OP_FUNCALL\[^\r\n\]*Number of args: 1.*\[\r\n\]\\$$decimal = 0.*" \
+    ".*OP_FUNCALL\[^\r\n\]*.*UNOP_ADDR.*\[\r\n\]\\$$decimal = 0.*" \
     "function call expression"
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 179/203] Convert go-exp.y to use operations
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (177 preceding siblings ...)
  2021-01-01 21:46 ` [PATCH 178/203] Convert c-exp.y " Tom Tromey
@ 2021-01-01 21:46 ` Tom Tromey
  2021-01-01 21:47 ` [PATCH 180/203] Convert d-exp.y " Tom Tromey
                   ` (24 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:46 UTC (permalink / raw)
  To: gdb-patches

This converts the Go parser to generate operations rather than
exp_elements.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* go-exp.y: Create operations.
	(go_language::parser): Update.
---
 gdb/ChangeLog |   5 ++
 gdb/go-exp.y  | 213 ++++++++++++++++++++++++++------------------------
 2 files changed, 117 insertions(+), 101 deletions(-)

diff --git a/gdb/go-exp.y b/gdb/go-exp.y
index 1d72cf31407..6e070a7f4ff 100644
--- a/gdb/go-exp.y
+++ b/gdb/go-exp.y
@@ -64,6 +64,7 @@
 #include "objfiles.h" /* For have_full_symbols and have_partial_symbols */
 #include "charset.h"
 #include "block.h"
+#include "expop.h"
 
 #define parse_type(ps) builtin_type (ps->gdbarch ())
 
@@ -115,6 +116,8 @@ static void yyerror (const char *);
 /* YYSTYPE gets defined by %union.  */
 static int parse_number (struct parser_state *,
 			 const char *, int, int, YYSTYPE *);
+
+using namespace expr;
 %}
 
 %type <voidval> exp exp1 type_exp start variable lcurly
@@ -193,77 +196,78 @@ start   :	exp1
 	;
 
 type_exp:	type
-			{ write_exp_elt_opcode (pstate, OP_TYPE);
-			  write_exp_elt_type (pstate, $1);
-			  write_exp_elt_opcode (pstate, OP_TYPE); }
+			{ pstate->push_new<type_operation> ($1); }
 	;
 
 /* Expressions, including the comma operator.  */
 exp1	:	exp
 	|	exp1 ',' exp
-			{ write_exp_elt_opcode (pstate, BINOP_COMMA); }
+			{ pstate->wrap2<comma_operation> (); }
 	;
 
 /* Expressions, not including the comma operator.  */
 exp	:	'*' exp    %prec UNARY
-			{ write_exp_elt_opcode (pstate, UNOP_IND); }
+			{ pstate->wrap<unop_ind_operation> (); }
 	;
 
 exp	:	'&' exp    %prec UNARY
-			{ write_exp_elt_opcode (pstate, UNOP_ADDR); }
+			{ pstate->wrap<unop_addr_operation> (); }
 	;
 
 exp	:	'-' exp    %prec UNARY
-			{ write_exp_elt_opcode (pstate, UNOP_NEG); }
+			{ pstate->wrap<unary_neg_operation> (); }
 	;
 
 exp	:	'+' exp    %prec UNARY
-			{ write_exp_elt_opcode (pstate, UNOP_PLUS); }
+			{ pstate->wrap<unary_plus_operation> (); }
 	;
 
 exp	:	'!' exp    %prec UNARY
-			{ write_exp_elt_opcode (pstate, UNOP_LOGICAL_NOT); }
+			{ pstate->wrap<unary_logical_not_operation> (); }
 	;
 
 exp	:	'^' exp    %prec UNARY
-			{ write_exp_elt_opcode (pstate, UNOP_COMPLEMENT); }
+			{ pstate->wrap<unary_complement_operation> (); }
 	;
 
 exp	:	exp INCREMENT    %prec UNARY
-			{ write_exp_elt_opcode (pstate, UNOP_POSTINCREMENT); }
+			{ pstate->wrap<postinc_operation> (); }
 	;
 
 exp	:	exp DECREMENT    %prec UNARY
-			{ write_exp_elt_opcode (pstate, UNOP_POSTDECREMENT); }
+			{ pstate->wrap<postdec_operation> (); }
 	;
 
 /* foo->bar is not in Go.  May want as a gdb extension.  Later.  */
 
 exp	:	exp '.' name_not_typename
-			{ write_exp_elt_opcode (pstate, STRUCTOP_STRUCT);
-			  write_exp_string (pstate, $3.stoken);
-			  write_exp_elt_opcode (pstate, STRUCTOP_STRUCT); }
+			{
+			  pstate->push_new<structop_operation>
+			    (pstate->pop (), copy_name ($3.stoken));
+			}
 	;
 
 exp	:	exp '.' name_not_typename COMPLETE
-			{ pstate->mark_struct_expression ();
-			  write_exp_elt_opcode (pstate, STRUCTOP_STRUCT);
-			  write_exp_string (pstate, $3.stoken);
-			  write_exp_elt_opcode (pstate, STRUCTOP_STRUCT); }
+			{
+			  structop_base_operation *op
+			    = new structop_operation (pstate->pop (),
+						      copy_name ($3.stoken));
+			  pstate->mark_struct_expression (op);
+			  pstate->push (operation_up (op));
+			}
 	;
 
 exp	:	exp '.' COMPLETE
-			{ struct stoken s;
-			  pstate->mark_struct_expression ();
-			  write_exp_elt_opcode (pstate, STRUCTOP_STRUCT);
-			  s.ptr = "";
-			  s.length = 0;
-			  write_exp_string (pstate, s);
-			  write_exp_elt_opcode (pstate, STRUCTOP_STRUCT); }
+			{
+			  structop_base_operation *op
+			    = new structop_operation (pstate->pop (), "");
+			  pstate->mark_struct_expression (op);
+			  pstate->push (operation_up (op));
+			}
 	;
 
 exp	:	exp '[' exp1 ']'
-			{ write_exp_elt_opcode (pstate, BINOP_SUBSCRIPT); }
+			{ pstate->wrap2<subscript_operation> (); }
 	;
 
 exp	:	exp '('
@@ -271,10 +275,12 @@ exp	:	exp '('
 			   being accumulated by an outer function call.  */
 			{ pstate->start_arglist (); }
 		arglist ')'	%prec LEFT_ARROW
-			{ write_exp_elt_opcode (pstate, OP_FUNCALL);
-			  write_exp_elt_longcst (pstate,
-						 pstate->end_arglist ());
-			  write_exp_elt_opcode (pstate, OP_FUNCALL); }
+			{
+			  std::vector<operation_up> args
+			    = pstate->pop_vector (pstate->end_arglist ());
+			  pstate->push_new<funcall_operation>
+			    (pstate->pop (), std::move (args));
+			}
 	;
 
 lcurly	:	'{'
@@ -297,15 +303,17 @@ rcurly	:	'}'
 	;
 
 exp	:	lcurly type rcurly exp  %prec UNARY
-			{ write_exp_elt_opcode (pstate, UNOP_MEMVAL);
-			  write_exp_elt_type (pstate, $2);
-			  write_exp_elt_opcode (pstate, UNOP_MEMVAL); }
+			{
+			  pstate->push_new<unop_memval_operation>
+			    (pstate->pop (), $2);
+			}
 	;
 
 exp	:	type '(' exp ')'  %prec UNARY
-			{ write_exp_elt_opcode (pstate, UNOP_CAST);
-			  write_exp_elt_type (pstate, $1);
-			  write_exp_elt_opcode (pstate, UNOP_CAST); }
+			{
+			  pstate->push_new<unop_cast_operation>
+			    (pstate->pop (), $1);
+			}
 	;
 
 exp	:	'(' exp1 ')'
@@ -315,100 +323,110 @@ exp	:	'(' exp1 ')'
 /* Binary operators in order of decreasing precedence.  */
 
 exp	:	exp '@' exp
-			{ write_exp_elt_opcode (pstate, BINOP_REPEAT); }
+			{ pstate->wrap2<repeat_operation> (); }
 	;
 
 exp	:	exp '*' exp
-			{ write_exp_elt_opcode (pstate, BINOP_MUL); }
+			{ pstate->wrap2<mul_operation> (); }
 	;
 
 exp	:	exp '/' exp
-			{ write_exp_elt_opcode (pstate, BINOP_DIV); }
+			{ pstate->wrap2<div_operation> (); }
 	;
 
 exp	:	exp '%' exp
-			{ write_exp_elt_opcode (pstate, BINOP_REM); }
+			{ pstate->wrap2<rem_operation> (); }
 	;
 
 exp	:	exp '+' exp
-			{ write_exp_elt_opcode (pstate, BINOP_ADD); }
+			{ pstate->wrap2<add_operation> (); }
 	;
 
 exp	:	exp '-' exp
-			{ write_exp_elt_opcode (pstate, BINOP_SUB); }
+			{ pstate->wrap2<sub_operation> (); }
 	;
 
 exp	:	exp LSH exp
-			{ write_exp_elt_opcode (pstate, BINOP_LSH); }
+			{ pstate->wrap2<lsh_operation> (); }
 	;
 
 exp	:	exp RSH exp
-			{ write_exp_elt_opcode (pstate, BINOP_RSH); }
+			{ pstate->wrap2<rsh_operation> (); }
 	;
 
 exp	:	exp EQUAL exp
-			{ write_exp_elt_opcode (pstate, BINOP_EQUAL); }
+			{ pstate->wrap2<equal_operation> (); }
 	;
 
 exp	:	exp NOTEQUAL exp
-			{ write_exp_elt_opcode (pstate, BINOP_NOTEQUAL); }
+			{ pstate->wrap2<notequal_operation> (); }
 	;
 
 exp	:	exp LEQ exp
-			{ write_exp_elt_opcode (pstate, BINOP_LEQ); }
+			{ pstate->wrap2<leq_operation> (); }
 	;
 
 exp	:	exp GEQ exp
-			{ write_exp_elt_opcode (pstate, BINOP_GEQ); }
+			{ pstate->wrap2<geq_operation> (); }
 	;
 
 exp	:	exp '<' exp
-			{ write_exp_elt_opcode (pstate, BINOP_LESS); }
+			{ pstate->wrap2<less_operation> (); }
 	;
 
 exp	:	exp '>' exp
-			{ write_exp_elt_opcode (pstate, BINOP_GTR); }
+			{ pstate->wrap2<gtr_operation> (); }
 	;
 
 exp	:	exp '&' exp
-			{ write_exp_elt_opcode (pstate, BINOP_BITWISE_AND); }
+			{ pstate->wrap2<bitwise_and_operation> (); }
 	;
 
 exp	:	exp '^' exp
-			{ write_exp_elt_opcode (pstate, BINOP_BITWISE_XOR); }
+			{ pstate->wrap2<bitwise_xor_operation> (); }
 	;
 
 exp	:	exp '|' exp
-			{ write_exp_elt_opcode (pstate, BINOP_BITWISE_IOR); }
+			{ pstate->wrap2<bitwise_ior_operation> (); }
 	;
 
 exp	:	exp ANDAND exp
-			{ write_exp_elt_opcode (pstate, BINOP_LOGICAL_AND); }
+			{ pstate->wrap2<logical_and_operation> (); }
 	;
 
 exp	:	exp OROR exp
-			{ write_exp_elt_opcode (pstate, BINOP_LOGICAL_OR); }
+			{ pstate->wrap2<logical_or_operation> (); }
 	;
 
 exp	:	exp '?' exp ':' exp	%prec '?'
-			{ write_exp_elt_opcode (pstate, TERNOP_COND); }
+			{
+			  operation_up last = pstate->pop ();
+			  operation_up mid = pstate->pop ();
+			  operation_up first = pstate->pop ();
+			  pstate->push_new<ternop_cond_operation>
+			    (std::move (first), std::move (mid),
+			     std::move (last));
+			}
 	;
 
 exp	:	exp '=' exp
-			{ write_exp_elt_opcode (pstate, BINOP_ASSIGN); }
+			{ pstate->wrap2<assign_operation> (); }
 	;
 
 exp	:	exp ASSIGN_MODIFY exp
-			{ write_exp_elt_opcode (pstate, BINOP_ASSIGN_MODIFY);
-			  write_exp_elt_opcode (pstate, $2);
-			  write_exp_elt_opcode (pstate, BINOP_ASSIGN_MODIFY); }
+			{
+			  operation_up rhs = pstate->pop ();
+			  operation_up lhs = pstate->pop ();
+			  pstate->push_new<assign_modify_operation>
+			    ($2, std::move (lhs), std::move (rhs));
+			}
 	;
 
 exp	:	INT
-			{ write_exp_elt_opcode (pstate, OP_LONG);
-			  write_exp_elt_type (pstate, $1.type);
-			  write_exp_elt_longcst (pstate, (LONGEST)($1.val));
-			  write_exp_elt_opcode (pstate, OP_LONG); }
+			{
+			  pstate->push_new<long_const_operation>
+			    ($1.type, $1.val);
+			}
 	;
 
 exp	:	CHAR
@@ -416,7 +434,7 @@ exp	:	CHAR
 			  struct stoken_vector vec;
 			  vec.len = 1;
 			  vec.tokens = &$1;
-			  write_exp_string_vector (pstate, $1.type, &vec);
+			  pstate->push_c_string ($1.type, &vec);
 			}
 	;
 
@@ -424,20 +442,20 @@ exp	:	NAME_OR_INT
 			{ YYSTYPE val;
 			  parse_number (pstate, $1.stoken.ptr,
 					$1.stoken.length, 0, &val);
-			  write_exp_elt_opcode (pstate, OP_LONG);
-			  write_exp_elt_type (pstate, val.typed_val_int.type);
-			  write_exp_elt_longcst (pstate, (LONGEST)
-						 val.typed_val_int.val);
-			  write_exp_elt_opcode (pstate, OP_LONG);
+			  pstate->push_new<long_const_operation>
+			    (val.typed_val_int.type,
+			     val.typed_val_int.val);
 			}
 	;
 
 
 exp	:	FLOAT
-			{ write_exp_elt_opcode (pstate, OP_FLOAT);
-			  write_exp_elt_type (pstate, $1.type);
-			  write_exp_elt_floatcst (pstate, $1.val);
-			  write_exp_elt_opcode (pstate, OP_FLOAT); }
+			{
+			  float_data data;
+			  std::copy (std::begin ($1.val), std::end ($1.val),
+				     std::begin (data));
+			  pstate->push_new<float_const_operation> ($1.type, data);
+			}
 	;
 
 exp	:	variable
@@ -445,29 +463,26 @@ exp	:	variable
 
 exp	:	DOLLAR_VARIABLE
 			{
-			  write_dollar_variable (pstate, $1);
+			  pstate->push_dollar ($1);
 			}
 	;
 
 exp	:	SIZEOF_KEYWORD '(' type ')'  %prec UNARY
 			{
 			  /* TODO(dje): Go objects in structs.  */
-			  write_exp_elt_opcode (pstate, OP_LONG);
 			  /* TODO(dje): What's the right type here?  */
-			  write_exp_elt_type
-			    (pstate,
-			     parse_type (pstate)->builtin_unsigned_int);
+			  struct type *size_type
+			    = parse_type (pstate)->builtin_unsigned_int;
 			  $3 = check_typedef ($3);
-			  write_exp_elt_longcst (pstate,
-						 (LONGEST) TYPE_LENGTH ($3));
-			  write_exp_elt_opcode (pstate, OP_LONG);
+			  pstate->push_new<long_const_operation>
+			    (size_type, (LONGEST) TYPE_LENGTH ($3));
 			}
 	;
 
 exp	:	SIZEOF_KEYWORD  '(' exp ')'  %prec UNARY
 			{
 			  /* TODO(dje): Go objects in structs.  */
-			  write_exp_elt_opcode (pstate, UNOP_SIZEOF);
+			  pstate->wrap<unop_sizeof_operation> ();
 			}
 
 string_exp:
@@ -510,8 +525,8 @@ exp	:	string_exp  %prec ABOVE_COMMA
 			{
 			  int i;
 
-			  write_exp_string_vector (pstate, 0 /*always utf8*/,
-						   &$1);
+			  /* Always utf8.  */
+			  pstate->push_c_string (0, &$1);
 			  for (i = 0; i < $1.len; ++i)
 			    free ($1.tokens[i].ptr);
 			  free ($1.tokens);
@@ -519,15 +534,11 @@ exp	:	string_exp  %prec ABOVE_COMMA
 	;
 
 exp	:	TRUE_KEYWORD
-			{ write_exp_elt_opcode (pstate, OP_BOOL);
-			  write_exp_elt_longcst (pstate, (LONGEST) $1);
-			  write_exp_elt_opcode (pstate, OP_BOOL); }
+			{ pstate->push_new<bool_operation> ($1); }
 	;
 
 exp	:	FALSE_KEYWORD
-			{ write_exp_elt_opcode (pstate, OP_BOOL);
-			  write_exp_elt_longcst (pstate, (LONGEST) $1);
-			  write_exp_elt_opcode (pstate, OP_BOOL); }
+			{ pstate->push_new<bool_operation> ($1); }
 	;
 
 variable:	name_not_typename ENTRY
@@ -540,9 +551,7 @@ variable:	name_not_typename ENTRY
 				     "parameters, not for \"%s\""),
 				   copy_name ($1.stoken).c_str ());
 
-			  write_exp_elt_opcode (pstate, OP_VAR_ENTRY_VALUE);
-			  write_exp_elt_sym (pstate, sym);
-			  write_exp_elt_opcode (pstate, OP_VAR_ENTRY_VALUE);
+			  pstate->push_new<var_entry_value_operation> (sym);
 			}
 	;
 
@@ -554,10 +563,8 @@ variable:	name_not_typename
 			      if (symbol_read_needs_frame (sym.symbol))
 				pstate->block_tracker->update (sym);
 
-			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
-			      write_exp_elt_block (pstate, sym.block);
-			      write_exp_elt_sym (pstate, sym.symbol);
-			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
+			      pstate->push_new<var_value_operation>
+				(sym.symbol, sym.block);
 			    }
 			  else if ($1.is_a_field_of_this)
 			    {
@@ -573,7 +580,8 @@ variable:	name_not_typename
 			      msymbol =
 				lookup_bound_minimal_symbol (arg.c_str ());
 			      if (msymbol.minsym != NULL)
-				write_exp_msymbol (pstate, msymbol);
+				pstate->push_new<var_msym_value_operation>
+				  (msymbol.minsym, msymbol.objfile);
 			      else if (!have_full_symbols ()
 				       && !have_partial_symbols ())
 				error (_("No symbol table is loaded.  "
@@ -1572,7 +1580,10 @@ go_language::parser (struct parser_state *par_state) const
   popping = 0;
   name_obstack.clear ();
 
-  return yyparse ();
+  int result = yyparse ();
+  if (!result)
+    pstate->set_operation (pstate->pop ());
+  return result;
 }
 
 static void
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 180/203] Convert d-exp.y to use operations
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (178 preceding siblings ...)
  2021-01-01 21:46 ` [PATCH 179/203] Convert go-exp.y " Tom Tromey
@ 2021-01-01 21:47 ` Tom Tromey
  2021-01-01 21:47 ` [PATCH 181/203] Convert p-exp.y " Tom Tromey
                   ` (23 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:47 UTC (permalink / raw)
  To: gdb-patches

This converts the D parser to generate operations rather than
exp_elements.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* d-exp.y: Create operations.
	(d_parse): Update.
---
 gdb/ChangeLog |   5 +
 gdb/d-exp.y   | 249 ++++++++++++++++++++++++++------------------------
 2 files changed, 134 insertions(+), 120 deletions(-)

diff --git a/gdb/d-exp.y b/gdb/d-exp.y
index dba758e80d0..61ddb983d64 100644
--- a/gdb/d-exp.y
+++ b/gdb/d-exp.y
@@ -52,6 +52,7 @@
 #include "charset.h"
 #include "block.h"
 #include "type-stack.h"
+#include "expop.h"
 
 #define parse_type(ps) builtin_type (ps->gdbarch ())
 #define parse_d_type(ps) builtin_d_type (ps->gdbarch ())
@@ -77,6 +78,8 @@ static void yyerror (const char *);
 
 static int type_aggregate_p (struct type *);
 
+using namespace expr;
+
 %}
 
 /* Although the yacc "value" of an expression is not used,
@@ -191,53 +194,63 @@ Expression:
 CommaExpression:
 	AssignExpression
 |	AssignExpression ',' CommaExpression
-		{ write_exp_elt_opcode (pstate, BINOP_COMMA); }
+		{ pstate->wrap2<comma_operation> (); }
 ;
 
 AssignExpression:
 	ConditionalExpression
 |	ConditionalExpression '=' AssignExpression
-		{ write_exp_elt_opcode (pstate, BINOP_ASSIGN); }
+		{ pstate->wrap2<assign_operation> (); }
 |	ConditionalExpression ASSIGN_MODIFY AssignExpression
-		{ write_exp_elt_opcode (pstate, BINOP_ASSIGN_MODIFY);
-		  write_exp_elt_opcode (pstate, $2);
-		  write_exp_elt_opcode (pstate, BINOP_ASSIGN_MODIFY); }
+		{
+		  operation_up rhs = pstate->pop ();
+		  operation_up lhs = pstate->pop ();
+		  pstate->push_new<assign_modify_operation>
+		    ($2, std::move (lhs), std::move (rhs));
+		}
 ;
 
 ConditionalExpression:
 	OrOrExpression
 |	OrOrExpression '?' Expression ':' ConditionalExpression
-		{ write_exp_elt_opcode (pstate, TERNOP_COND); }
+		{
+		  operation_up last = pstate->pop ();
+		  operation_up mid = pstate->pop ();
+		  operation_up first = pstate->pop ();
+		  pstate->push_new<ternop_cond_operation>
+		    (std::move (first), std::move (mid),
+		     std::move (last));
+		}
 ;
 
 OrOrExpression:
 	AndAndExpression
 |	OrOrExpression OROR AndAndExpression
-		{ write_exp_elt_opcode (pstate, BINOP_LOGICAL_OR); }
+		{ pstate->wrap2<logical_or_operation> (); }
 ;
 
 AndAndExpression:
 	OrExpression
 |	AndAndExpression ANDAND OrExpression
-		{ write_exp_elt_opcode (pstate, BINOP_LOGICAL_AND); }
+		{ pstate->wrap2<logical_and_operation> (); }
 ;
 
 OrExpression:
 	XorExpression
 |	OrExpression '|' XorExpression
-		{ write_exp_elt_opcode (pstate, BINOP_BITWISE_IOR); }
+		{ pstate->wrap2<bitwise_ior_operation> (); }
 ;
 
 XorExpression:
 	AndExpression
 |	XorExpression '^' AndExpression
-		{ write_exp_elt_opcode (pstate, BINOP_BITWISE_XOR); }
+		{ pstate->wrap2<bitwise_xor_operation> (); }
 ;
 
 AndExpression:
 	CmpExpression
 |	AndExpression '&' CmpExpression
-		{ write_exp_elt_opcode (pstate, BINOP_BITWISE_AND); }
+		{ pstate->wrap2<bitwise_and_operation> (); }
 ;
 
 CmpExpression:
@@ -249,120 +262,121 @@ CmpExpression:
 
 EqualExpression:
 	ShiftExpression EQUAL ShiftExpression
-		{ write_exp_elt_opcode (pstate, BINOP_EQUAL); }
+		{ pstate->wrap2<equal_operation> (); }
 |	ShiftExpression NOTEQUAL ShiftExpression
-		{ write_exp_elt_opcode (pstate, BINOP_NOTEQUAL); }
+		{ pstate->wrap2<notequal_operation> (); }
 ;
 
 IdentityExpression:
 	ShiftExpression IDENTITY ShiftExpression
-		{ write_exp_elt_opcode (pstate, BINOP_EQUAL); }
+		{ pstate->wrap2<equal_operation> (); }
 |	ShiftExpression NOTIDENTITY ShiftExpression
-		{ write_exp_elt_opcode (pstate, BINOP_NOTEQUAL); }
+		{ pstate->wrap2<notequal_operation> (); }
 ;
 
 RelExpression:
 	ShiftExpression '<' ShiftExpression
-		{ write_exp_elt_opcode (pstate, BINOP_LESS); }
+		{ pstate->wrap2<less_operation> (); }
 |	ShiftExpression LEQ ShiftExpression
-		{ write_exp_elt_opcode (pstate, BINOP_LEQ); }
+		{ pstate->wrap2<leq_operation> (); }
 |	ShiftExpression '>' ShiftExpression
-		{ write_exp_elt_opcode (pstate, BINOP_GTR); }
+		{ pstate->wrap2<gtr_operation> (); }
 |	ShiftExpression GEQ ShiftExpression
-		{ write_exp_elt_opcode (pstate, BINOP_GEQ); }
+		{ pstate->wrap2<geq_operation> (); }
 ;
 
 ShiftExpression:
 	AddExpression
 |	ShiftExpression LSH AddExpression
-		{ write_exp_elt_opcode (pstate, BINOP_LSH); }
+		{ pstate->wrap2<lsh_operation> (); }
 |	ShiftExpression RSH AddExpression
-		{ write_exp_elt_opcode (pstate, BINOP_RSH); }
+		{ pstate->wrap2<rsh_operation> (); }
 ;
 
 AddExpression:
 	MulExpression
 |	AddExpression '+' MulExpression
-		{ write_exp_elt_opcode (pstate, BINOP_ADD); }
+		{ pstate->wrap2<add_operation> (); }
 |	AddExpression '-' MulExpression
-		{ write_exp_elt_opcode (pstate, BINOP_SUB); }
+		{ pstate->wrap2<sub_operation> (); }
 |	AddExpression '~' MulExpression
-		{ write_exp_elt_opcode (pstate, BINOP_CONCAT); }
+		{ pstate->wrap2<concat_operation> (); }
 ;
 
 MulExpression:
 	UnaryExpression
 |	MulExpression '*' UnaryExpression
-		{ write_exp_elt_opcode (pstate, BINOP_MUL); }
+		{ pstate->wrap2<mul_operation> (); }
 |	MulExpression '/' UnaryExpression
-		{ write_exp_elt_opcode (pstate, BINOP_DIV); }
+		{ pstate->wrap2<div_operation> (); }
 |	MulExpression '%' UnaryExpression
-		{ write_exp_elt_opcode (pstate, BINOP_REM); }
+		{ pstate->wrap2<rem_operation> (); }
 
 UnaryExpression:
 	'&' UnaryExpression
-		{ write_exp_elt_opcode (pstate, UNOP_ADDR); }
+		{ pstate->wrap<unop_addr_operation> (); }
 |	INCREMENT UnaryExpression
-		{ write_exp_elt_opcode (pstate, UNOP_PREINCREMENT); }
+		{ pstate->wrap<preinc_operation> (); }
 |	DECREMENT UnaryExpression
-		{ write_exp_elt_opcode (pstate, UNOP_PREDECREMENT); }
+		{ pstate->wrap<predec_operation> (); }
 |	'*' UnaryExpression
-		{ write_exp_elt_opcode (pstate, UNOP_IND); }
+		{ pstate->wrap<unop_ind_operation> (); }
 |	'-' UnaryExpression
-		{ write_exp_elt_opcode (pstate, UNOP_NEG); }
+		{ pstate->wrap<unary_neg_operation> (); }
 |	'+' UnaryExpression
-		{ write_exp_elt_opcode (pstate, UNOP_PLUS); }
+		{ pstate->wrap<unary_plus_operation> (); }
 |	'!' UnaryExpression
-		{ write_exp_elt_opcode (pstate, UNOP_LOGICAL_NOT); }
+		{ pstate->wrap<unary_logical_not_operation> (); }
 |	'~' UnaryExpression
-		{ write_exp_elt_opcode (pstate, UNOP_COMPLEMENT); }
+		{ pstate->wrap<unary_complement_operation> (); }
 |	TypeExp '.' SIZEOF_KEYWORD
-		{ write_exp_elt_opcode (pstate, UNOP_SIZEOF); }
+		{ pstate->wrap<unop_sizeof_operation> (); }
 |	CastExpression
 |	PowExpression
 ;
 
 CastExpression:
 	CAST_KEYWORD '(' TypeExp ')' UnaryExpression
-		{ write_exp_elt_opcode (pstate, UNOP_CAST_TYPE); }
+		{ pstate->wrap2<unop_cast_type_operation> (); }
 	/* C style cast is illegal D, but is still recognised in
 	   the grammar, so we keep this around for convenience.  */
 |	'(' TypeExp ')' UnaryExpression
-		{ write_exp_elt_opcode (pstate, UNOP_CAST_TYPE); }
-
+		{ pstate->wrap2<unop_cast_type_operation> (); }
 ;
 
 PowExpression:
 	PostfixExpression
 |	PostfixExpression HATHAT UnaryExpression
-		{ write_exp_elt_opcode (pstate, BINOP_EXP); }
+		{ pstate->wrap2<exp_operation> (); }
 ;
 
 PostfixExpression:
 	PrimaryExpression
 |	PostfixExpression '.' COMPLETE
-		{ struct stoken s;
-		  pstate->mark_struct_expression ();
-		  write_exp_elt_opcode (pstate, STRUCTOP_STRUCT);
-		  s.ptr = "";
-		  s.length = 0;
-		  write_exp_string (pstate, s);
-		  write_exp_elt_opcode (pstate, STRUCTOP_STRUCT); }
+		{
+		  structop_base_operation *op
+		    = new structop_ptr_operation (pstate->pop (), "");
+		  pstate->mark_struct_expression (op);
+		  pstate->push (operation_up (op));
+		}
 |	PostfixExpression '.' IDENTIFIER
-		{ write_exp_elt_opcode (pstate, STRUCTOP_STRUCT);
-		  write_exp_string (pstate, $3);
-		  write_exp_elt_opcode (pstate, STRUCTOP_STRUCT); }
+		{
+		  pstate->push_new<structop_operation>
+		    (pstate->pop (), copy_name ($3));
+		}
 |	PostfixExpression '.' IDENTIFIER COMPLETE
-		{ pstate->mark_struct_expression ();
-		  write_exp_elt_opcode (pstate, STRUCTOP_STRUCT);
-		  write_exp_string (pstate, $3);
-		  write_exp_elt_opcode (pstate, STRUCTOP_STRUCT); }
+		{
+		  structop_base_operation *op
+		    = new structop_operation (pstate->pop (), copy_name ($3));
+		  pstate->mark_struct_expression (op);
+		  pstate->push (operation_up (op));
+		}
 |	PostfixExpression '.' SIZEOF_KEYWORD
-		{ write_exp_elt_opcode (pstate, UNOP_SIZEOF); }
+		{ pstate->wrap<unop_sizeof_operation> (); }
 |	PostfixExpression INCREMENT
-		{ write_exp_elt_opcode (pstate, UNOP_POSTINCREMENT); }
+		{ pstate->wrap<postinc_operation> (); }
 |	PostfixExpression DECREMENT
-		{ write_exp_elt_opcode (pstate, UNOP_POSTDECREMENT); }
+		{ pstate->wrap<postdec_operation> (); }
 |	CallExpression
 |	IndexExpression
 |	SliceExpression
@@ -385,21 +399,25 @@ CallExpression:
 	PostfixExpression '('
 		{ pstate->start_arglist (); }
 	ArgumentList_opt ')'
-		{ write_exp_elt_opcode (pstate, OP_FUNCALL);
-		  write_exp_elt_longcst (pstate, pstate->end_arglist ());
-		  write_exp_elt_opcode (pstate, OP_FUNCALL); }
+		{
+		  std::vector<operation_up> args
+		    = pstate->pop_vector (pstate->end_arglist ());
+		  pstate->push_new<funcall_operation>
+		    (pstate->pop (), std::move (args));
+		}
 ;
 
 IndexExpression:
 	PostfixExpression '[' ArgumentList ']'
 		{ if (pstate->arglist_len > 0)
 		    {
-		      write_exp_elt_opcode (pstate, MULTI_SUBSCRIPT);
-		      write_exp_elt_longcst (pstate, pstate->arglist_len);
-		      write_exp_elt_opcode (pstate, MULTI_SUBSCRIPT);
+		      std::vector<operation_up> args
+			= pstate->pop_vector (pstate->arglist_len);
+		      pstate->push_new<multi_subscript_operation>
+			(pstate->pop (), std::move (args));
 		    }
 		  else
-		    write_exp_elt_opcode (pstate, BINOP_SUBSCRIPT);
+		    pstate->wrap2<subscript_operation> ();
 		}
 ;
 
@@ -407,7 +425,14 @@ SliceExpression:
 	PostfixExpression '[' ']'
 		{ /* Do nothing.  */ }
 |	PostfixExpression '[' AssignExpression DOTDOT AssignExpression ']'
-		{ write_exp_elt_opcode (pstate, TERNOP_SLICE); }
+		{
+		  operation_up last = pstate->pop ();
+		  operation_up mid = pstate->pop ();
+		  operation_up first = pstate->pop ();
+		  pstate->push_new<ternop_slice_operation>
+		    (std::move (first), std::move (mid),
+		     std::move (last));
+		}
 ;
 
 PrimaryExpression:
@@ -427,28 +452,26 @@ PrimaryExpression:
 		    {
 		      if (symbol_read_needs_frame (sym.symbol))
 			pstate->block_tracker->update (sym);
-		      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
-		      write_exp_elt_block (pstate, sym.block);
-		      write_exp_elt_sym (pstate, sym.symbol);
-		      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
+		      pstate->push_new<var_value_operation> (sym.symbol,
+							     sym.block);
 		    }
 		  else if (is_a_field_of_this.type != NULL)
 		     {
 		      /* It hangs off of `this'.  Must not inadvertently convert from a
 			 method call to data ref.  */
 		      pstate->block_tracker->update (sym);
-		      write_exp_elt_opcode (pstate, OP_THIS);
-		      write_exp_elt_opcode (pstate, OP_THIS);
-		      write_exp_elt_opcode (pstate, STRUCTOP_PTR);
-		      write_exp_string (pstate, $1);
-		      write_exp_elt_opcode (pstate, STRUCTOP_PTR);
+		      operation_up thisop
+			= make_operation<op_this_operation> ();
+		      pstate->push_new<structop_ptr_operation>
+			(std::move (thisop), std::move (copy));
 		    }
 		  else
 		    {
 		      /* Lookup foreign name in global static symbols.  */
 		      msymbol = lookup_bound_minimal_symbol (copy.c_str ());
 		      if (msymbol.minsym != NULL)
-			write_exp_msymbol (pstate, msymbol);
+			pstate->push_new<var_msym_value_operation>
+			  (msymbol.minsym, msymbol.objfile);
 		      else if (!have_full_symbols () && !have_partial_symbols ())
 			error (_("No symbol table is loaded.  Use the \"file\" command"));
 		      else
@@ -476,9 +499,7 @@ PrimaryExpression:
 				lookup_symbol (name.c_str (),
 					       (const struct block *) NULL,
 					       VAR_DOMAIN, NULL);
-			      write_exp_symbol_reference (pstate,
-							  name.c_str (),
-							  sym.symbol);
+			      pstate->push_symbol (name.c_str (), sym.symbol);
 			    }
 			  else
 			    {
@@ -488,65 +509,54 @@ PrimaryExpression:
 				error (_("`%s' is not defined as an aggregate type."),
 				       TYPE_SAFE_NAME (type));
 
-			      write_exp_elt_opcode (pstate, OP_SCOPE);
-			      write_exp_elt_type (pstate, type);
-			      write_exp_string (pstate, $3);
-			      write_exp_elt_opcode (pstate, OP_SCOPE);
+			      pstate->push_new<scope_operation>
+				(type, copy_name ($3));
 			    }
 			}
 |	DOLLAR_VARIABLE
-		{ write_dollar_variable (pstate, $1); }
+		{ pstate->push_dollar ($1); }
 |	NAME_OR_INT
 		{ YYSTYPE val;
 		  parse_number (pstate, $1.ptr, $1.length, 0, &val);
-		  write_exp_elt_opcode (pstate, OP_LONG);
-		  write_exp_elt_type (pstate, val.typed_val_int.type);
-		  write_exp_elt_longcst (pstate,
-					 (LONGEST) val.typed_val_int.val);
-		  write_exp_elt_opcode (pstate, OP_LONG); }
+		  pstate->push_new<long_const_operation>
+		    (val.typed_val_int.type, val.typed_val_int.val); }
 |	NULL_KEYWORD
 		{ struct type *type = parse_d_type (pstate)->builtin_void;
 		  type = lookup_pointer_type (type);
-		  write_exp_elt_opcode (pstate, OP_LONG);
-		  write_exp_elt_type (pstate, type);
-		  write_exp_elt_longcst (pstate, (LONGEST) 0);
-		  write_exp_elt_opcode (pstate, OP_LONG); }
+		  pstate->push_new<long_const_operation> (type, 0); }
 |	TRUE_KEYWORD
-		{ write_exp_elt_opcode (pstate, OP_BOOL);
-		  write_exp_elt_longcst (pstate, (LONGEST) 1);
-		  write_exp_elt_opcode (pstate, OP_BOOL); }
+		{ pstate->push_new<bool_operation> (true); }
 |	FALSE_KEYWORD
-		{ write_exp_elt_opcode (pstate, OP_BOOL);
-		  write_exp_elt_longcst (pstate, (LONGEST) 0);
-		  write_exp_elt_opcode (pstate, OP_BOOL); }
+		{ pstate->push_new<bool_operation> (false); }
 |	INTEGER_LITERAL
-		{ write_exp_elt_opcode (pstate, OP_LONG);
-		  write_exp_elt_type (pstate, $1.type);
-		  write_exp_elt_longcst (pstate, (LONGEST)($1.val));
-		  write_exp_elt_opcode (pstate, OP_LONG); }
+		{ pstate->push_new<long_const_operation> ($1.type, $1.val); }
 |	FLOAT_LITERAL
-		{ write_exp_elt_opcode (pstate, OP_FLOAT);
-		  write_exp_elt_type (pstate, $1.type);
-		  write_exp_elt_floatcst (pstate, $1.val);
-		  write_exp_elt_opcode (pstate, OP_FLOAT); }
+		{
+		  float_data data;
+		  std::copy (std::begin ($1.val), std::end ($1.val),
+			     std::begin (data));
+		  pstate->push_new<float_const_operation> ($1.type, data);
+		}
 |	CHARACTER_LITERAL
 		{ struct stoken_vector vec;
 		  vec.len = 1;
 		  vec.tokens = &$1;
-		  write_exp_string_vector (pstate, $1.type, &vec); }
+		  pstate->push_c_string (0, &vec); }
 |	StringExp
 		{ int i;
-		  write_exp_string_vector (pstate, 0, &$1);
+		  pstate->push_c_string (0, &$1);
 		  for (i = 0; i < $1.len; ++i)
 		    free ($1.tokens[i].ptr);
 		  free ($1.tokens); }
 |	ArrayLiteral
-		{ write_exp_elt_opcode (pstate, OP_ARRAY);
-		  write_exp_elt_longcst (pstate, (LONGEST) 0);
-		  write_exp_elt_longcst (pstate, (LONGEST) $1 - 1);
-		  write_exp_elt_opcode (pstate, OP_ARRAY); }
+		{
+		  std::vector<operation_up> args
+		    = pstate->pop_vector ($1);
+		  pstate->push_new<array_operation>
+		    (0, $1 - 1, std::move (args));
+		}
 |	TYPEOF_KEYWORD '(' Expression ')'
-		{ write_exp_elt_opcode (pstate, OP_TYPEOF); }
+		{ pstate->wrap<typeof_operation> (); }
 ;
 
 ArrayLiteral:
@@ -595,14 +605,10 @@ TypeExp:
 	'(' TypeExp ')'
 		{ /* Do nothing.  */ }
 |	BasicType
-		{ write_exp_elt_opcode (pstate, OP_TYPE);
-		  write_exp_elt_type (pstate, $1);
-		  write_exp_elt_opcode (pstate, OP_TYPE); }
+		{ pstate->push_new<type_operation> ($1); }
 |	BasicType BasicType2
 		{ $$ = type_stack->follow_types ($1);
-		  write_exp_elt_opcode (pstate, OP_TYPE);
-		  write_exp_elt_type (pstate, $$);
-		  write_exp_elt_opcode (pstate, OP_TYPE);
+		  pstate->push_new<type_operation> ($$);
 		}
 ;
 
@@ -1622,7 +1628,10 @@ d_parse (struct parser_state *par_state)
   popping = 0;
   name_obstack.clear ();
 
-  return yyparse ();
+  int result = yyparse ();
+  if (!result)
+    pstate->set_operation (pstate->pop ());
+  return result;
 }
 
 static void
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 181/203] Convert p-exp.y to use operations
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (179 preceding siblings ...)
  2021-01-01 21:47 ` [PATCH 180/203] Convert d-exp.y " Tom Tromey
@ 2021-01-01 21:47 ` Tom Tromey
  2021-01-01 21:47 ` [PATCH 182/203] Convert m2-exp.y " Tom Tromey
                   ` (22 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:47 UTC (permalink / raw)
  To: gdb-patches

This converts the Pascal parser to generate operations rather than
exp_elements.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* p-exp.y: Create operations.
	(pascal_language::parser): Update.
---
 gdb/ChangeLog |   5 +
 gdb/p-exp.y   | 267 +++++++++++++++++++++++---------------------------
 2 files changed, 130 insertions(+), 142 deletions(-)

diff --git a/gdb/p-exp.y b/gdb/p-exp.y
index 637369e0404..87fabc2ec11 100644
--- a/gdb/p-exp.y
+++ b/gdb/p-exp.y
@@ -55,6 +55,7 @@
 #include "objfiles.h" /* For have_full_symbols and have_partial_symbols.  */
 #include "block.h"
 #include "completer.h"
+#include "expop.h"
 
 #define parse_type(ps) builtin_type (ps->gdbarch ())
 
@@ -78,6 +79,8 @@ static int yylex (void);
 static void yyerror (const char *);
 
 static char *uptok (const char *, int);
+
+using namespace expr;
 %}
 
 /* Although the yacc "value" of an expression is not used,
@@ -203,44 +206,43 @@ normal_start	:
 	;
 
 type_exp:	type
-			{ write_exp_elt_opcode (pstate, OP_TYPE);
-			  write_exp_elt_type (pstate, $1);
-			  write_exp_elt_opcode (pstate, OP_TYPE);
+			{
+			  pstate->push_new<type_operation> ($1);
 			  current_type = $1; } ;
 
 /* Expressions, including the comma operator.  */
 exp1	:	exp
 	|	exp1 ',' exp
-			{ write_exp_elt_opcode (pstate, BINOP_COMMA); }
+			{ pstate->wrap2<comma_operation> (); }
 	;
 
 /* Expressions, not including the comma operator.  */
 exp	:	exp '^'   %prec UNARY
-			{ write_exp_elt_opcode (pstate, UNOP_IND);
+			{ pstate->wrap<unop_ind_operation> ();
 			  if (current_type)
 			    current_type = TYPE_TARGET_TYPE (current_type); }
 	;
 
 exp	:	'@' exp    %prec UNARY
-			{ write_exp_elt_opcode (pstate, UNOP_ADDR);
+			{ pstate->wrap<unop_addr_operation> ();
 			  if (current_type)
 			    current_type = TYPE_POINTER_TYPE (current_type); }
 	;
 
 exp	:	'-' exp    %prec UNARY
-			{ write_exp_elt_opcode (pstate, UNOP_NEG); }
+			{ pstate->wrap<unary_neg_operation> (); }
 	;
 
 exp	:	NOT exp    %prec UNARY
-			{ write_exp_elt_opcode (pstate, UNOP_LOGICAL_NOT); }
+			{ pstate->wrap<unary_logical_not_operation> (); }
 	;
 
 exp	:	INCREMENT '(' exp ')'   %prec UNARY
-			{ write_exp_elt_opcode (pstate, UNOP_PREINCREMENT); }
+			{ pstate->wrap<preinc_operation> (); }
 	;
 
 exp	:	DECREMENT  '(' exp ')'   %prec UNARY
-			{ write_exp_elt_opcode (pstate, UNOP_PREDECREMENT); }
+			{ pstate->wrap<predec_operation> (); }
 	;
 
 
@@ -249,9 +251,9 @@ field_exp	:	exp '.'	%prec UNARY
 	;
 
 exp	:	field_exp FIELDNAME
-			{ write_exp_elt_opcode (pstate, STRUCTOP_STRUCT);
-			  write_exp_string (pstate, $2);
-			  write_exp_elt_opcode (pstate, STRUCTOP_STRUCT);
+			{
+			  pstate->push_new<structop_operation>
+			    (pstate->pop (), copy_name ($2));
 			  search_field = 0;
 			  if (current_type)
 			    {
@@ -267,9 +269,9 @@ exp	:	field_exp FIELDNAME
 
 
 exp	:	field_exp name
-			{ write_exp_elt_opcode (pstate, STRUCTOP_STRUCT);
-			  write_exp_string (pstate, $2);
-			  write_exp_elt_opcode (pstate, STRUCTOP_STRUCT);
+			{
+			  pstate->push_new<structop_operation>
+			    (pstate->pop (), copy_name ($2));
 			  search_field = 0;
 			  if (current_type)
 			    {
@@ -283,19 +285,21 @@ exp	:	field_exp name
 			}
 	;
 exp	:	field_exp  name COMPLETE
-			{ pstate->mark_struct_expression ();
-			  write_exp_elt_opcode (pstate, STRUCTOP_STRUCT);
-			  write_exp_string (pstate, $2);
-			  write_exp_elt_opcode (pstate, STRUCTOP_STRUCT); }
+			{
+			  structop_base_operation *op
+			    = new structop_ptr_operation (pstate->pop (),
+							  copy_name ($2));
+			  pstate->mark_struct_expression (op);
+			  pstate->push (operation_up (op));
+			}
 	;
 exp	:	field_exp COMPLETE
-			{ struct stoken s;
-			  pstate->mark_struct_expression ();
-			  write_exp_elt_opcode (pstate, STRUCTOP_STRUCT);
-			  s.ptr = "";
-			  s.length = 0;
-			  write_exp_string (pstate, s);
-			  write_exp_elt_opcode (pstate, STRUCTOP_STRUCT); }
+			{
+			  structop_base_operation *op
+			    = new structop_ptr_operation (pstate->pop (), "");
+			  pstate->mark_struct_expression (op);
+			  pstate->push (operation_up (op));
+			}
 	;
 
 exp	:	exp '['
@@ -306,24 +310,16 @@ exp	:	exp '['
 						     NULL, NULL, &arrayname);
 			  if (arrayfieldindex)
 			    {
-			      struct stoken stringsval;
-			      char *buf;
-
-			      buf = (char *) alloca (strlen (arrayname) + 1);
-			      stringsval.ptr = buf;
-			      stringsval.length = strlen (arrayname);
-			      strcpy (buf, arrayname);
 			      current_type
 				= (current_type
 				   ->field (arrayfieldindex - 1).type ());
-			      write_exp_elt_opcode (pstate, STRUCTOP_STRUCT);
-			      write_exp_string (pstate, stringsval);
-			      write_exp_elt_opcode (pstate, STRUCTOP_STRUCT);
+			      pstate->push_new<structop_operation>
+				(pstate->pop (), arrayname);
 			    }
 			  push_current_type ();  }
 		exp1 ']'
 			{ pop_current_type ();
-			  write_exp_elt_opcode (pstate, BINOP_SUBSCRIPT);
+			  pstate->wrap2<subscript_operation> ();
 			  if (current_type)
 			    current_type = TYPE_TARGET_TYPE (current_type); }
 	;
@@ -334,10 +330,11 @@ exp	:	exp '('
 			{ push_current_type ();
 			  pstate->start_arglist (); }
 		arglist ')'	%prec ARROW
-			{ write_exp_elt_opcode (pstate, OP_FUNCALL);
-			  write_exp_elt_longcst (pstate,
-						 pstate->end_arglist ());
-			  write_exp_elt_opcode (pstate, OP_FUNCALL);
+			{
+			  std::vector<operation_up> args
+			    = pstate->pop_vector (pstate->end_arglist ());
+			  pstate->push_new<funcall_operation>
+			    (pstate->pop (), std::move (args));
 			  pop_current_type ();
 			  if (current_type)
  	  		    current_type = TYPE_TARGET_TYPE (current_type);
@@ -358,11 +355,10 @@ exp	:	type '(' exp ')' %prec UNARY
 			      if ((current_type->code () == TYPE_CODE_PTR)
 				  && (TYPE_TARGET_TYPE (current_type)->code () == TYPE_CODE_STRUCT)
 				  && (($1)->code () == TYPE_CODE_STRUCT))
-				write_exp_elt_opcode (pstate, UNOP_IND);
+				pstate->wrap<unop_ind_operation> ();
 			    }
-			  write_exp_elt_opcode (pstate, UNOP_CAST);
-			  write_exp_elt_type (pstate, $1);
-			  write_exp_elt_opcode (pstate, UNOP_CAST);
+			  pstate->push_new<unop_cast_operation>
+			    (pstate->pop (), $1);
 			  current_type = $1; }
 	;
 
@@ -373,7 +369,7 @@ exp	:	'(' exp1 ')'
 /* Binary operators in order of decreasing precedence.  */
 
 exp	:	exp '*' exp
-			{ write_exp_elt_opcode (pstate, BINOP_MUL); }
+			{ pstate->wrap2<mul_operation> (); }
 	;
 
 exp	:	exp '/' {
@@ -385,138 +381,141 @@ exp	:	exp '/' {
 			  if (leftdiv_is_integer && current_type
 			      && is_integral_type (current_type))
 			    {
-			      write_exp_elt_opcode (pstate, UNOP_CAST);
-			      write_exp_elt_type (pstate,
-						  parse_type (pstate)
-						  ->builtin_long_double);
+			      pstate->push_new<unop_cast_operation>
+				(pstate->pop (),
+				 parse_type (pstate)->builtin_long_double);
 			      current_type
 				= parse_type (pstate)->builtin_long_double;
-			      write_exp_elt_opcode (pstate, UNOP_CAST);
 			      leftdiv_is_integer = 0;
 			    }
 
-			  write_exp_elt_opcode (pstate, BINOP_DIV);
+			  pstate->wrap2<div_operation> ();
 			}
 	;
 
 exp	:	exp DIV exp
-			{ write_exp_elt_opcode (pstate, BINOP_INTDIV); }
+			{ pstate->wrap2<intdiv_operation> (); }
 	;
 
 exp	:	exp MOD exp
-			{ write_exp_elt_opcode (pstate, BINOP_REM); }
+			{ pstate->wrap2<rem_operation> (); }
 	;
 
 exp	:	exp '+' exp
-			{ write_exp_elt_opcode (pstate, BINOP_ADD); }
+			{ pstate->wrap2<add_operation> (); }
 	;
 
 exp	:	exp '-' exp
-			{ write_exp_elt_opcode (pstate, BINOP_SUB); }
+			{ pstate->wrap2<sub_operation> (); }
 	;
 
 exp	:	exp LSH exp
-			{ write_exp_elt_opcode (pstate, BINOP_LSH); }
+			{ pstate->wrap2<lsh_operation> (); }
 	;
 
 exp	:	exp RSH exp
-			{ write_exp_elt_opcode (pstate, BINOP_RSH); }
+			{ pstate->wrap2<rsh_operation> (); }
 	;
 
 exp	:	exp '=' exp
-			{ write_exp_elt_opcode (pstate, BINOP_EQUAL);
+			{
+			  pstate->wrap2<equal_operation> ();
 			  current_type = parse_type (pstate)->builtin_bool;
 			}
 	;
 
 exp	:	exp NOTEQUAL exp
-			{ write_exp_elt_opcode (pstate, BINOP_NOTEQUAL);
+			{
+			  pstate->wrap2<notequal_operation> ();
 			  current_type = parse_type (pstate)->builtin_bool;
 			}
 	;
 
 exp	:	exp LEQ exp
-			{ write_exp_elt_opcode (pstate, BINOP_LEQ);
+			{
+			  pstate->wrap2<leq_operation> ();
 			  current_type = parse_type (pstate)->builtin_bool;
 			}
 	;
 
 exp	:	exp GEQ exp
-			{ write_exp_elt_opcode (pstate, BINOP_GEQ);
+			{
+			  pstate->wrap2<geq_operation> ();
 			  current_type = parse_type (pstate)->builtin_bool;
 			}
 	;
 
 exp	:	exp '<' exp
-			{ write_exp_elt_opcode (pstate, BINOP_LESS);
+			{
+			  pstate->wrap2<less_operation> ();
 			  current_type = parse_type (pstate)->builtin_bool;
 			}
 	;
 
 exp	:	exp '>' exp
-			{ write_exp_elt_opcode (pstate, BINOP_GTR);
+			{
+			  pstate->wrap2<gtr_operation> ();
 			  current_type = parse_type (pstate)->builtin_bool;
 			}
 	;
 
 exp	:	exp ANDAND exp
-			{ write_exp_elt_opcode (pstate, BINOP_BITWISE_AND); }
+			{ pstate->wrap2<bitwise_and_operation> (); }
 	;
 
 exp	:	exp XOR exp
-			{ write_exp_elt_opcode (pstate, BINOP_BITWISE_XOR); }
+			{ pstate->wrap2<bitwise_xor_operation> (); }
 	;
 
 exp	:	exp OR exp
-			{ write_exp_elt_opcode (pstate, BINOP_BITWISE_IOR); }
+			{ pstate->wrap2<bitwise_ior_operation> (); }
 	;
 
 exp	:	exp ASSIGN exp
-			{ write_exp_elt_opcode (pstate, BINOP_ASSIGN); }
+			{ pstate->wrap2<assign_operation> (); }
 	;
 
 exp	:	TRUEKEYWORD
-			{ write_exp_elt_opcode (pstate, OP_BOOL);
-			  write_exp_elt_longcst (pstate, (LONGEST) $1);
+			{
+			  pstate->push_new<bool_operation> ($1);
 			  current_type = parse_type (pstate)->builtin_bool;
-			  write_exp_elt_opcode (pstate, OP_BOOL); }
+			}
 	;
 
 exp	:	FALSEKEYWORD
-			{ write_exp_elt_opcode (pstate, OP_BOOL);
-			  write_exp_elt_longcst (pstate, (LONGEST) $1);
+			{
+			  pstate->push_new<bool_operation> ($1);
 			  current_type = parse_type (pstate)->builtin_bool;
-			  write_exp_elt_opcode (pstate, OP_BOOL); }
+			}
 	;
 
 exp	:	INT
-			{ write_exp_elt_opcode (pstate, OP_LONG);
-			  write_exp_elt_type (pstate, $1.type);
+			{
+			  pstate->push_new<long_const_operation>
+			    ($1.type, $1.val);
 			  current_type = $1.type;
-			  write_exp_elt_longcst (pstate, (LONGEST)($1.val));
-			  write_exp_elt_opcode (pstate, OP_LONG); }
+			}
 	;
 
 exp	:	NAME_OR_INT
 			{ YYSTYPE val;
 			  parse_number (pstate, $1.stoken.ptr,
 					$1.stoken.length, 0, &val);
-			  write_exp_elt_opcode (pstate, OP_LONG);
-			  write_exp_elt_type (pstate, val.typed_val_int.type);
+			  pstate->push_new<long_const_operation>
+			    (val.typed_val_int.type,
+			     val.typed_val_int.val);
 			  current_type = val.typed_val_int.type;
-			  write_exp_elt_longcst (pstate, (LONGEST)
-						 val.typed_val_int.val);
-			  write_exp_elt_opcode (pstate, OP_LONG);
 			}
 	;
 
 
 exp	:	FLOAT
-			{ write_exp_elt_opcode (pstate, OP_FLOAT);
-			  write_exp_elt_type (pstate, $1.type);
-			  current_type = $1.type;
-			  write_exp_elt_floatcst (pstate, $1.val);
-			  write_exp_elt_opcode (pstate, OP_FLOAT); }
+			{
+			  float_data data;
+			  std::copy (std::begin ($1.val), std::end ($1.val),
+				     std::begin (data));
+			  pstate->push_new<float_const_operation> ($1.type, data);
+			}
 	;
 
 exp	:	variable
@@ -524,7 +523,7 @@ exp	:	variable
 
 exp	:	DOLLAR_VARIABLE
 			{
-			  write_dollar_variable (pstate, $1);
+			  pstate->push_dollar ($1);
 
 			  /* $ is the normal prefix for pascal
 			     hexadecimal values but this conflicts
@@ -549,18 +548,16 @@ exp	:	DOLLAR_VARIABLE
  	;
 
 exp	:	SIZEOF '(' type ')'	%prec UNARY
-			{ write_exp_elt_opcode (pstate, OP_LONG);
-			  write_exp_elt_type (pstate,
-					    parse_type (pstate)->builtin_int);
+			{
 			  current_type = parse_type (pstate)->builtin_int;
 			  $3 = check_typedef ($3);
-			  write_exp_elt_longcst (pstate,
-						 (LONGEST) TYPE_LENGTH ($3));
-			  write_exp_elt_opcode (pstate, OP_LONG); }
+			  pstate->push_new<long_const_operation>
+			    (parse_type (pstate)->builtin_int,
+			     TYPE_LENGTH ($3)); }
 	;
 
 exp	:	SIZEOF  '(' exp ')'      %prec UNARY
-			{ write_exp_elt_opcode (pstate, UNOP_SIZEOF);
+			{ pstate->wrap<unop_sizeof_operation> ();
 			  current_type = parse_type (pstate)->builtin_int; }
 
 exp	:	STRING
@@ -571,27 +568,17 @@ exp	:	STRING
 			     string.  */
 			  const char *sp = $1.ptr; int count = $1.length;
 
-			  while (count-- > 0)
-			    {
-			      write_exp_elt_opcode (pstate, OP_LONG);
-			      write_exp_elt_type (pstate,
-						  parse_type (pstate)
-						  ->builtin_char);
-			      write_exp_elt_longcst (pstate,
-						     (LONGEST) (*sp++));
-			      write_exp_elt_opcode (pstate, OP_LONG);
-			    }
-			  write_exp_elt_opcode (pstate, OP_LONG);
-			  write_exp_elt_type (pstate,
-					      parse_type (pstate)
-					      ->builtin_char);
-			  write_exp_elt_longcst (pstate, (LONGEST)'\0');
-			  write_exp_elt_opcode (pstate, OP_LONG);
-			  write_exp_elt_opcode (pstate, OP_ARRAY);
-			  write_exp_elt_longcst (pstate, (LONGEST) 0);
-			  write_exp_elt_longcst (pstate,
-						 (LONGEST) ($1.length));
-			  write_exp_elt_opcode (pstate, OP_ARRAY); }
+			  std::vector<operation_up> args (count + 1);
+			  for (int i = 0; i < count; ++i)
+			    args[i] = (make_operation<long_const_operation>
+				       (parse_type (pstate)->builtin_char,
+					*sp++));
+			  args[count] = (make_operation<long_const_operation>
+					 (parse_type (pstate)->builtin_char,
+					  '\0'));
+			  pstate->push_new<array_operation>
+			    (0, $1.length, std::move (args));
+			}
 	;
 
 /* Object pascal  */
@@ -599,8 +586,7 @@ exp	:	THIS
 			{
 			  struct value * this_val;
 			  struct type * this_type;
-			  write_exp_elt_opcode (pstate, OP_THIS);
-			  write_exp_elt_opcode (pstate, OP_THIS);
+			  pstate->push_new<op_this_operation> ();
 			  /* We need type of this.  */
 			  this_val
 			    = value_of_this_silent (pstate->language ());
@@ -613,7 +599,7 @@ exp	:	THIS
 			      if (this_type->code () == TYPE_CODE_PTR)
 				{
 				  this_type = TYPE_TARGET_TYPE (this_type);
-				  write_exp_elt_opcode (pstate, UNOP_IND);
+				  pstate->wrap<unop_ind_operation> ();
 				}
 			    }
 
@@ -665,10 +651,9 @@ variable:	block COLONCOLON name
 			    error (_("No symbol \"%s\" in specified context."),
 				   copy.c_str ());
 
-			  write_exp_elt_opcode (pstate, OP_VAR_VALUE);
-			  write_exp_elt_block (pstate, sym.block);
-			  write_exp_elt_sym (pstate, sym.symbol);
-			  write_exp_elt_opcode (pstate, OP_VAR_VALUE); }
+			  pstate->push_new<var_value_operation>
+			    (sym.symbol, sym.block);
+			}
 	;
 
 qualified_name:	typebase COLONCOLON name
@@ -680,10 +665,8 @@ qualified_name:	typebase COLONCOLON name
 			    error (_("`%s' is not defined as an aggregate type."),
 				   type->name ());
 
-			  write_exp_elt_opcode (pstate, OP_SCOPE);
-			  write_exp_elt_type (pstate, type);
-			  write_exp_string (pstate, $3);
-			  write_exp_elt_opcode (pstate, OP_SCOPE);
+			  pstate->push_new<scope_operation>
+			    (type, copy_name ($3));
 			}
 	;
 
@@ -697,8 +680,7 @@ variable:	qualified_name
 			    lookup_symbol (name.c_str (),
 					   (const struct block *) NULL,
 					   VAR_DOMAIN, NULL).symbol;
-			  write_exp_symbol_reference (pstate, name.c_str (),
-						      sym);
+			  pstate->push_symbol (name.c_str (), sym);
 			}
 	;
 
@@ -710,10 +692,8 @@ variable:	name_not_typename
 			      if (symbol_read_needs_frame (sym.symbol))
 				pstate->block_tracker->update (sym);
 
-			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
-			      write_exp_elt_block (pstate, sym.block);
-			      write_exp_elt_sym (pstate, sym.symbol);
-			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
+			      pstate->push_new<var_value_operation>
+				(sym.symbol, sym.block);
 			      current_type = sym.symbol->type; }
 			  else if ($1.is_a_field_of_this)
 			    {
@@ -723,11 +703,10 @@ variable:	name_not_typename
 				 not inadvertently convert from a method call
 				 to data ref.  */
 			      pstate->block_tracker->update (sym);
-			      write_exp_elt_opcode (pstate, OP_THIS);
-			      write_exp_elt_opcode (pstate, OP_THIS);
-			      write_exp_elt_opcode (pstate, STRUCTOP_PTR);
-			      write_exp_string (pstate, $1.stoken);
-			      write_exp_elt_opcode (pstate, STRUCTOP_PTR);
+			      operation_up thisop
+				= make_operation<op_this_operation> ();
+			      pstate->push_new<structop_operation>
+				(std::move (thisop), copy_name ($1.stoken));
 			      /* We need type of this.  */
 			      this_val
 				= value_of_this_silent (pstate->language ());
@@ -750,7 +729,8 @@ variable:	name_not_typename
 			      msymbol =
 				lookup_bound_minimal_symbol (arg.c_str ());
 			      if (msymbol.minsym != NULL)
-				write_exp_msymbol (pstate, msymbol);
+				pstate->push_new<var_msym_value_operation>
+				  (msymbol.minsym, msymbol.objfile);
 			      else if (!have_full_symbols ()
 				       && !have_partial_symbols ())
 				error (_("No symbol table is loaded.  "
@@ -1718,7 +1698,10 @@ pascal_language::parser (struct parser_state *par_state) const
   pstate = par_state;
   paren_depth = 0;
 
-  return yyparse ();
+  int result = yyparse ();
+  if (!result)
+    pstate->set_operation (pstate->pop ());
+  return result;
 }
 
 static void
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 182/203] Convert m2-exp.y to use operations
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (180 preceding siblings ...)
  2021-01-01 21:47 ` [PATCH 181/203] Convert p-exp.y " Tom Tromey
@ 2021-01-01 21:47 ` Tom Tromey
  2021-01-01 21:47 ` [PATCH 183/203] Convert f-exp.y " Tom Tromey
                   ` (21 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:47 UTC (permalink / raw)
  To: gdb-patches

This converts the Modula-2 parser to generate operations rather than
exp_elements.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* m2-exp.y: Create operations.
	(m2_language::parser): Update.
---
 gdb/ChangeLog |   5 ++
 gdb/m2-exp.y  | 234 ++++++++++++++++++++++++--------------------------
 2 files changed, 117 insertions(+), 122 deletions(-)

diff --git a/gdb/m2-exp.y b/gdb/m2-exp.y
index d94cf6905fe..43cbd3ebf73 100644
--- a/gdb/m2-exp.y
+++ b/gdb/m2-exp.y
@@ -47,6 +47,7 @@
 #include "symfile.h" /* Required by objfiles.h.  */
 #include "objfiles.h" /* For have_full_symbols and have_partial_symbols */
 #include "block.h"
+#include "m2-exp.h"
 
 #define parse_type(ps) builtin_type (ps->gdbarch ())
 #define parse_m2_type(ps) builtin_m2_type (ps->gdbarch ())
@@ -72,6 +73,7 @@ static int parse_number (int);
 /* The sign of the number being parsed.  */
 static int number_sign = 1;
 
+using namespace expr;
 %}
 
 /* Although the yacc "value" of an expression is not used,
@@ -153,31 +155,28 @@ start   :	exp
 	;
 
 type_exp:	type
-		{ write_exp_elt_opcode (pstate, OP_TYPE);
-		  write_exp_elt_type (pstate, $1);
-		  write_exp_elt_opcode (pstate, OP_TYPE);
-		}
+		{ pstate->push_new<type_operation> ($1); }
 	;
 
 /* Expressions */
 
 exp     :       exp '^'   %prec UNARY
-			{ write_exp_elt_opcode (pstate, UNOP_IND); }
+			{ pstate->wrap<unop_ind_operation> (); }
 	;
 
 exp	:	'-'
 			{ number_sign = -1; }
 		exp    %prec UNARY
 			{ number_sign = 1;
-			  write_exp_elt_opcode (pstate, UNOP_NEG); }
+			  pstate->wrap<unary_neg_operation> (); }
 	;
 
 exp	:	'+' exp    %prec UNARY
-		{ write_exp_elt_opcode (pstate, UNOP_PLUS); }
+		{ pstate->wrap<unary_plus_operation> (); }
 	;
 
 exp	:	not_exp exp %prec UNARY
-			{ write_exp_elt_opcode (pstate, UNOP_LOGICAL_NOT); }
+			{ pstate->wrap<unary_logical_not_operation> (); }
 	;
 
 not_exp	:	NOT
@@ -185,91 +184,90 @@ not_exp	:	NOT
 	;
 
 exp	:	CAP '(' exp ')'
-			{ write_exp_elt_opcode (pstate, UNOP_CAP); }
+			{ error (_("CAP function is not implemented")); }
 	;
 
 exp	:	ORD '(' exp ')'
-			{ write_exp_elt_opcode (pstate, UNOP_ORD); }
+			{ error (_("ORD function is not implemented")); }
 	;
 
 exp	:	ABS '(' exp ')'
-			{ write_exp_elt_opcode (pstate, UNOP_ABS); }
+			{ error (_("ABS function is not implemented")); }
 	;
 
 exp	: 	HIGH '(' exp ')'
-			{ write_exp_elt_opcode (pstate, UNOP_HIGH); }
+			{ pstate->wrap<m2_unop_high_operation> (); }
 	;
 
 exp 	:	MIN_FUNC '(' type ')'
-			{ write_exp_elt_opcode (pstate, UNOP_MIN);
-			  write_exp_elt_type (pstate, $3);
-			  write_exp_elt_opcode (pstate, UNOP_MIN); }
+			{ error (_("MIN function is not implemented")); }
 	;
 
 exp	: 	MAX_FUNC '(' type ')'
-			{ write_exp_elt_opcode (pstate, UNOP_MAX);
-			  write_exp_elt_type (pstate, $3);
-			  write_exp_elt_opcode (pstate, UNOP_MAX); }
+			{ error (_("MAX function is not implemented")); }
 	;
 
 exp	:	FLOAT_FUNC '(' exp ')'
-			{ write_exp_elt_opcode (pstate, UNOP_FLOAT); }
+			{ error (_("FLOAT function is not implemented")); }
 	;
 
 exp	:	VAL '(' type ',' exp ')'
-			{ write_exp_elt_opcode (pstate, BINOP_VAL);
-			  write_exp_elt_type (pstate, $3);
-			  write_exp_elt_opcode (pstate, BINOP_VAL); }
+			{ error (_("VAL function is not implemented")); }
 	;
 
 exp	:	CHR '(' exp ')'
-			{ write_exp_elt_opcode (pstate, UNOP_CHR); }
+			{ error (_("CHR function is not implemented")); }
 	;
 
 exp	:	ODD '(' exp ')'
-			{ write_exp_elt_opcode (pstate, UNOP_ODD); }
+			{ error (_("ODD function is not implemented")); }
 	;
 
 exp	:	TRUNC '(' exp ')'
-			{ write_exp_elt_opcode (pstate, UNOP_TRUNC); }
+			{ error (_("TRUNC function is not implemented")); }
 	;
 
 exp	:	TSIZE '(' exp ')'
-			{ write_exp_elt_opcode (pstate, UNOP_SIZEOF); }
+			{ pstate->wrap<unop_sizeof_operation> (); }
 	;
 
 exp	:	SIZE exp       %prec UNARY
-			{ write_exp_elt_opcode (pstate, UNOP_SIZEOF); }
+			{ pstate->wrap<unop_sizeof_operation> (); }
 	;
 
 
 exp	:	INC '(' exp ')'
-			{ write_exp_elt_opcode (pstate, UNOP_PREINCREMENT); }
+			{ pstate->wrap<preinc_operation> (); }
 	;
 
 exp	:	INC '(' exp ',' exp ')'
-			{ write_exp_elt_opcode (pstate, BINOP_ASSIGN_MODIFY);
-			  write_exp_elt_opcode (pstate, BINOP_ADD);
-			  write_exp_elt_opcode (pstate,
-						BINOP_ASSIGN_MODIFY); }
+			{
+			  operation_up rhs = pstate->pop ();
+			  operation_up lhs = pstate->pop ();
+			  pstate->push_new<assign_modify_operation>
+			    (BINOP_ADD, std::move (lhs), std::move (rhs));
+			}
 	;
 
 exp	:	DEC '(' exp ')'
-			{ write_exp_elt_opcode (pstate, UNOP_PREDECREMENT);}
+			{ pstate->wrap<predec_operation> (); }
 	;
 
 exp	:	DEC '(' exp ',' exp ')'
-			{ write_exp_elt_opcode (pstate, BINOP_ASSIGN_MODIFY);
-			  write_exp_elt_opcode (pstate, BINOP_SUB);
-			  write_exp_elt_opcode (pstate,
-						BINOP_ASSIGN_MODIFY); }
+			{
+			  operation_up rhs = pstate->pop ();
+			  operation_up lhs = pstate->pop ();
+			  pstate->push_new<assign_modify_operation>
+			    (BINOP_SUB, std::move (lhs), std::move (rhs));
+			}
 	;
 
 exp	:	exp DOT NAME
-			{ write_exp_elt_opcode (pstate, STRUCTOP_STRUCT);
-			  write_exp_string (pstate, $3);
-			  write_exp_elt_opcode (pstate, STRUCTOP_STRUCT); }
-	;
+			{
+			  pstate->push_new<structop_operation>
+			    (pstate->pop (), copy_name ($3));
+			}
+;
 
 exp	:	set
 	;
@@ -302,10 +300,10 @@ exp     :       exp '['
 		non_empty_arglist ']'  %prec DOT
 			{
 			  gdb_assert (pstate->arglist_len > 0);
-			  write_exp_elt_opcode (pstate, MULTI_SUBSCRIPT);
-			  write_exp_elt_longcst (pstate,
-						 pstate->end_arglist());
-			  write_exp_elt_opcode (pstate, MULTI_SUBSCRIPT);
+			  std::vector<operation_up> args
+			    = pstate->pop_vector (pstate->end_arglist ());
+			  pstate->push_new<multi_subscript_operation>
+			    (pstate->pop (), std::move (args));
 			}
 	;
 
@@ -314,10 +312,12 @@ exp	:	exp '('
 			   being accumulated by an outer function call.  */
 			{ pstate->start_arglist (); }
 		arglist ')'	%prec DOT
-			{ write_exp_elt_opcode (pstate, OP_FUNCALL);
-			  write_exp_elt_longcst (pstate,
-						 pstate->end_arglist ());
-			  write_exp_elt_opcode (pstate, OP_FUNCALL); }
+			{
+			  std::vector<operation_up> args
+			    = pstate->pop_vector (pstate->end_arglist ());
+			  pstate->push_new<funcall_operation>
+			    (pstate->pop (), std::move (args));
+			}
 	;
 
 arglist	:
@@ -343,15 +343,17 @@ non_empty_arglist
 
 /* GDB construct */
 exp	:	'{' type '}' exp  %prec UNARY
-			{ write_exp_elt_opcode (pstate, UNOP_MEMVAL);
-			  write_exp_elt_type (pstate, $2);
-			  write_exp_elt_opcode (pstate, UNOP_MEMVAL); }
+			{
+			  pstate->push_new<unop_memval_operation>
+			    (pstate->pop (), $2);
+			}
 	;
 
 exp     :       type '(' exp ')' %prec UNARY
-			{ write_exp_elt_opcode (pstate, UNOP_CAST);
-			  write_exp_elt_type (pstate, $1);
-			  write_exp_elt_opcode (pstate, UNOP_CAST); }
+			{
+			  pstate->push_new<unop_cast_operation>
+			    (pstate->pop (), $1);
+			}
 	;
 
 exp	:	'(' exp ')'
@@ -363,140 +365,127 @@ exp	:	'(' exp ')'
 
 /* GDB construct */
 exp	:	exp '@' exp
-			{ write_exp_elt_opcode (pstate, BINOP_REPEAT); }
+			{ pstate->wrap2<repeat_operation> (); }
 	;
 
 exp	:	exp '*' exp
-			{ write_exp_elt_opcode (pstate, BINOP_MUL); }
+			{ pstate->wrap2<mul_operation> (); }
 	;
 
 exp	:	exp '/' exp
-			{ write_exp_elt_opcode (pstate, BINOP_DIV); }
+			{ pstate->wrap2<div_operation> (); }
 	;
 
 exp     :       exp DIV exp
-			{ write_exp_elt_opcode (pstate, BINOP_INTDIV); }
+			{ pstate->wrap2<intdiv_operation> (); }
 	;
 
 exp	:	exp MOD exp
-			{ write_exp_elt_opcode (pstate, BINOP_REM); }
+			{ pstate->wrap2<rem_operation> (); }
 	;
 
 exp	:	exp '+' exp
-			{ write_exp_elt_opcode (pstate, BINOP_ADD); }
+			{ pstate->wrap2<add_operation> (); }
 	;
 
 exp	:	exp '-' exp
-			{ write_exp_elt_opcode (pstate, BINOP_SUB); }
+			{ pstate->wrap2<sub_operation> (); }
 	;
 
 exp	:	exp '=' exp
-			{ write_exp_elt_opcode (pstate, BINOP_EQUAL); }
+			{ pstate->wrap2<equal_operation> (); }
 	;
 
 exp	:	exp NOTEQUAL exp
-			{ write_exp_elt_opcode (pstate, BINOP_NOTEQUAL); }
+			{ pstate->wrap2<notequal_operation> (); }
 	|       exp '#' exp
-			{ write_exp_elt_opcode (pstate, BINOP_NOTEQUAL); }
+			{ pstate->wrap2<notequal_operation> (); }
 	;
 
 exp	:	exp LEQ exp
-			{ write_exp_elt_opcode (pstate, BINOP_LEQ); }
+			{ pstate->wrap2<leq_operation> (); }
 	;
 
 exp	:	exp GEQ exp
-			{ write_exp_elt_opcode (pstate, BINOP_GEQ); }
+			{ pstate->wrap2<geq_operation> (); }
 	;
 
 exp	:	exp '<' exp
-			{ write_exp_elt_opcode (pstate, BINOP_LESS); }
+			{ pstate->wrap2<less_operation> (); }
 	;
 
 exp	:	exp '>' exp
-			{ write_exp_elt_opcode (pstate, BINOP_GTR); }
+			{ pstate->wrap2<gtr_operation> (); }
 	;
 
 exp	:	exp LOGICAL_AND exp
-			{ write_exp_elt_opcode (pstate, BINOP_LOGICAL_AND); }
+			{ pstate->wrap2<logical_and_operation> (); }
 	;
 
 exp	:	exp OROR exp
-			{ write_exp_elt_opcode (pstate, BINOP_LOGICAL_OR); }
+			{ pstate->wrap2<logical_or_operation> (); }
 	;
 
 exp	:	exp ASSIGN exp
-			{ write_exp_elt_opcode (pstate, BINOP_ASSIGN); }
+			{ pstate->wrap2<assign_operation> (); }
 	;
 
 
 /* Constants */
 
 exp	:	M2_TRUE
-			{ write_exp_elt_opcode (pstate, OP_BOOL);
-			  write_exp_elt_longcst (pstate, (LONGEST) $1);
-			  write_exp_elt_opcode (pstate, OP_BOOL); }
+			{ pstate->push_new<bool_operation> ($1); }
 	;
 
 exp	:	M2_FALSE
-			{ write_exp_elt_opcode (pstate, OP_BOOL);
-			  write_exp_elt_longcst (pstate, (LONGEST) $1);
-			  write_exp_elt_opcode (pstate, OP_BOOL); }
+			{ pstate->push_new<bool_operation> ($1); }
 	;
 
 exp	:	INT
-			{ write_exp_elt_opcode (pstate, OP_LONG);
-			  write_exp_elt_type (pstate,
-					parse_m2_type (pstate)->builtin_int);
-			  write_exp_elt_longcst (pstate, (LONGEST) $1);
-			  write_exp_elt_opcode (pstate, OP_LONG); }
+			{
+			  pstate->push_new<long_const_operation>
+			    (parse_m2_type (pstate)->builtin_int, $1);
+			}
 	;
 
 exp	:	UINT
 			{
-			  write_exp_elt_opcode (pstate, OP_LONG);
-			  write_exp_elt_type (pstate,
-					      parse_m2_type (pstate)
-					      ->builtin_card);
-			  write_exp_elt_longcst (pstate, (LONGEST) $1);
-			  write_exp_elt_opcode (pstate, OP_LONG);
+			  pstate->push_new<long_const_operation>
+			    (parse_m2_type (pstate)->builtin_card, $1);
 			}
 	;
 
 exp	:	CHAR
-			{ write_exp_elt_opcode (pstate, OP_LONG);
-			  write_exp_elt_type (pstate,
-					      parse_m2_type (pstate)
-					      ->builtin_char);
-			  write_exp_elt_longcst (pstate, (LONGEST) $1);
-			  write_exp_elt_opcode (pstate, OP_LONG); }
+			{
+			  pstate->push_new<long_const_operation>
+			    (parse_m2_type (pstate)->builtin_char, $1);
+			}
 	;
 
 
 exp	:	FLOAT
-			{ write_exp_elt_opcode (pstate, OP_FLOAT);
-			  write_exp_elt_type (pstate,
-					      parse_m2_type (pstate)
-					      ->builtin_real);
-			  write_exp_elt_floatcst (pstate, $1);
-			  write_exp_elt_opcode (pstate, OP_FLOAT); }
+			{
+			  float_data data;
+			  std::copy (std::begin ($1), std::end ($1),
+				     std::begin (data));
+			  pstate->push_new<float_const_operation>
+			    (parse_m2_type (pstate)->builtin_real, data);
+			}
 	;
 
 exp	:	variable
 	;
 
 exp	:	SIZE '(' type ')'	%prec UNARY
-			{ write_exp_elt_opcode (pstate, OP_LONG);
-			  write_exp_elt_type (pstate,
-					    parse_type (pstate)->builtin_int);
-			  write_exp_elt_longcst (pstate,
-						 (LONGEST) TYPE_LENGTH ($3));
-			  write_exp_elt_opcode (pstate, OP_LONG); }
+			{
+			  pstate->push_new<long_const_operation>
+			    (parse_m2_type (pstate)->builtin_int,
+			     TYPE_LENGTH ($3));
+			}
 	;
 
 exp	:	STRING
-			{ write_exp_elt_opcode (pstate, OP_M2_STRING);
-			  write_exp_string (pstate, $1);
-			  write_exp_elt_opcode (pstate, OP_M2_STRING); }
+			{ error (_("strings are not implemented")); }
 	;
 
 /* This will be used for extensions later.  Like adding modules.  */
@@ -527,15 +516,15 @@ fblock	:	block COLONCOLON BLOCKNAME
 
 /* Useful for assigning to PROCEDURE variables */
 variable:	fblock
-			{ write_exp_elt_opcode (pstate, OP_VAR_VALUE);
-			  write_exp_elt_block (pstate, NULL);
-			  write_exp_elt_sym (pstate, $1);
-			  write_exp_elt_opcode (pstate, OP_VAR_VALUE); }
+			{
+			  pstate->push_new<var_value_operation>
+			    ($1, nullptr);
+			}
 	;
 
 /* GDB internal ($foo) variable */
 variable:	DOLLAR_VARIABLE
-			{ write_dollar_variable (pstate, $1); }
+			{ pstate->push_dollar ($1); }
 	;
 
 /* GDB scope operator */
@@ -550,10 +539,9 @@ variable:	block COLONCOLON NAME
 			  if (symbol_read_needs_frame (sym.symbol))
 			    pstate->block_tracker->update (sym);
 
-			  write_exp_elt_opcode (pstate, OP_VAR_VALUE);
-			  write_exp_elt_block (pstate, sym.block);
-			  write_exp_elt_sym (pstate, sym.symbol);
-			  write_exp_elt_opcode (pstate, OP_VAR_VALUE); }
+			  pstate->push_new<var_value_operation>
+			    (sym.symbol, sym.block);
+			}
 	;
 
 /* Base case for variables.  */
@@ -568,8 +556,7 @@ variable:	NAME
 					     VAR_DOMAIN,
 					     &is_a_field_of_this);
 
-			  write_exp_symbol_reference (pstate, name.c_str (),
-						      sym.symbol);
+			  pstate->push_symbol (name.c_str (), sym.symbol);
 			}
 	;
 
@@ -1015,7 +1002,10 @@ m2_language::parser (struct parser_state *par_state) const
   pstate = par_state;
   paren_depth = 0;
 
-  return yyparse ();
+  int result = yyparse ();
+  if (!result)
+    pstate->set_operation (pstate->pop ());
+  return result;
 }
 
 static void
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 183/203] Convert f-exp.y to use operations
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (181 preceding siblings ...)
  2021-01-01 21:47 ` [PATCH 182/203] Convert m2-exp.y " Tom Tromey
@ 2021-01-01 21:47 ` Tom Tromey
  2021-01-01 21:47 ` [PATCH 184/203] Convert ada-exp.y " Tom Tromey
                   ` (20 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:47 UTC (permalink / raw)
  To: gdb-patches

This converts the Fortran parser to generate operations rather than
exp_elements.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* f-exp.y: Create operations.
	(f_language::parser): Update.
---
 gdb/ChangeLog |   5 +
 gdb/f-exp.y   | 322 ++++++++++++++++++++++++++++++--------------------
 2 files changed, 198 insertions(+), 129 deletions(-)

diff --git a/gdb/f-exp.y b/gdb/f-exp.y
index 6001e77060b..3aee19facce 100644
--- a/gdb/f-exp.y
+++ b/gdb/f-exp.y
@@ -55,6 +55,7 @@
 #include <ctype.h>
 #include <algorithm>
 #include "type-stack.h"
+#include "f-exp.h"
 
 #define parse_type(ps) builtin_type (ps->gdbarch ())
 #define parse_f_type(ps) builtin_f_type (ps->gdbarch ())
@@ -89,6 +90,7 @@ static void push_kind_type (LONGEST val, struct type *type);
 
 static struct type *convert_to_kind_type (struct type *basetype, int kind);
 
+using namespace expr;
 %}
 
 /* Although the yacc "value" of an expression is not used,
@@ -208,9 +210,7 @@ start   :	exp
 	;
 
 type_exp:	type
-			{ write_exp_elt_opcode (pstate, OP_TYPE);
-			  write_exp_elt_type (pstate, $1);
-			  write_exp_elt_opcode (pstate, OP_TYPE); }
+			{ pstate->push_new<type_operation> ($1); }
 	;
 
 exp     :       '(' exp ')'
@@ -219,31 +219,31 @@ exp     :       '(' exp ')'
 
 /* Expressions, not including the comma operator.  */
 exp	:	'*' exp    %prec UNARY
-			{ write_exp_elt_opcode (pstate, UNOP_IND); }
+			{ pstate->wrap<unop_ind_operation> (); }
 	;
 
 exp	:	'&' exp    %prec UNARY
-			{ write_exp_elt_opcode (pstate, UNOP_ADDR); }
+			{ pstate->wrap<unop_addr_operation> (); }
 	;
 
 exp	:	'-' exp    %prec UNARY
-			{ write_exp_elt_opcode (pstate, UNOP_NEG); }
+			{ pstate->wrap<unary_neg_operation> (); }
 	;
 
 exp	:	BOOL_NOT exp    %prec UNARY
-			{ write_exp_elt_opcode (pstate, UNOP_LOGICAL_NOT); }
+			{ pstate->wrap<unary_logical_not_operation> (); }
 	;
 
 exp	:	'~' exp    %prec UNARY
-			{ write_exp_elt_opcode (pstate, UNOP_COMPLEMENT); }
+			{ pstate->wrap<unary_complement_operation> (); }
 	;
 
 exp	:	SIZEOF exp       %prec UNARY
-			{ write_exp_elt_opcode (pstate, UNOP_SIZEOF); }
+			{ pstate->wrap<unop_sizeof_operation> (); }
 	;
 
 exp	:	KIND '(' exp ')'       %prec UNARY
-			{ write_exp_elt_opcode (pstate, UNOP_FORTRAN_KIND); }
+			{ pstate->wrap<fortran_kind_operation> (); }
 	;
 
 /* No more explicit array operators, we treat everything in F77 as 
@@ -254,20 +254,50 @@ exp	:	KIND '(' exp ')'       %prec UNARY
 exp	:	exp '(' 
 			{ pstate->start_arglist (); }
 		arglist ')'	
-			{ write_exp_elt_opcode (pstate,
-						OP_F77_UNDETERMINED_ARGLIST);
-			  write_exp_elt_longcst (pstate,
-						 pstate->end_arglist ());
-			  write_exp_elt_opcode (pstate,
-					      OP_F77_UNDETERMINED_ARGLIST); }
+			{
+			  std::vector<operation_up> args
+			    = pstate->pop_vector (pstate->end_arglist ());
+			  pstate->push_new<fortran_undetermined>
+			    (pstate->pop (), std::move (args));
+			}
 	;
 
 exp	:	UNOP_INTRINSIC '(' exp ')'
-			{ write_exp_elt_opcode (pstate, $1); }
+			{
+			  switch ($1)
+			    {
+			    case UNOP_ABS:
+			      pstate->wrap<fortran_abs_operation> ();
+			      break;
+			    case UNOP_FORTRAN_FLOOR:
+			      pstate->wrap<fortran_floor_operation> ();
+			      break;
+			    case UNOP_FORTRAN_CEILING:
+			      pstate->wrap<fortran_ceil_operation> ();
+			      break;
+			    default:
+			      gdb_assert_not_reached ("unhandled intrinsic");
+			    }
+			}
 	;
 
 exp	:	BINOP_INTRINSIC '(' exp ',' exp ')'
-			{ write_exp_elt_opcode (pstate, $1); }
+			{
+			  switch ($1)
+			    {
+			    case BINOP_MOD:
+			      pstate->wrap2<fortran_mod_operation> ();
+			      break;
+			    case BINOP_FORTRAN_MODULO:
+			      pstate->wrap2<fortran_modulo_operation> ();
+			      break;
+			    case BINOP_FORTRAN_CMPLX:
+			      pstate->wrap2<fortran_cmplx_operation> ();
+			      break;
+			    default:
+			      gdb_assert_not_reached ("unhandled intrinsic");
+			    }
+			}
 	;
 
 arglist	:
@@ -292,63 +322,90 @@ arglist	:	arglist ',' subrange   %prec ABOVE_COMMA
 /* There are four sorts of subrange types in F90.  */
 
 subrange:	exp ':' exp	%prec ABOVE_COMMA
-			{ write_exp_elt_opcode (pstate, OP_RANGE);
-			  write_exp_elt_longcst (pstate, RANGE_STANDARD);
-			  write_exp_elt_opcode (pstate, OP_RANGE); }
+			{
+			  operation_up high = pstate->pop ();
+			  operation_up low = pstate->pop ();
+			  pstate->push_new<fortran_range_operation>
+			    (RANGE_STANDARD, std::move (low),
+			     std::move (high), operation_up ());
+			}
 	;
 
 subrange:	exp ':'	%prec ABOVE_COMMA
-			{ write_exp_elt_opcode (pstate, OP_RANGE);
-			  write_exp_elt_longcst (pstate,
-						 RANGE_HIGH_BOUND_DEFAULT);
-			  write_exp_elt_opcode (pstate, OP_RANGE); }
+			{
+			  operation_up low = pstate->pop ();
+			  pstate->push_new<fortran_range_operation>
+			    (RANGE_HIGH_BOUND_DEFAULT, std::move (low),
+			     operation_up (), operation_up ());
+			}
 	;
 
 subrange:	':' exp	%prec ABOVE_COMMA
-			{ write_exp_elt_opcode (pstate, OP_RANGE);
-			  write_exp_elt_longcst (pstate,
-						 RANGE_LOW_BOUND_DEFAULT);
-			  write_exp_elt_opcode (pstate, OP_RANGE); }
+			{
+			  operation_up high = pstate->pop ();
+			  pstate->push_new<fortran_range_operation>
+			    (RANGE_LOW_BOUND_DEFAULT, operation_up (),
+			     std::move (high), operation_up ());
+			}
 	;
 
 subrange:	':'	%prec ABOVE_COMMA
-			{ write_exp_elt_opcode (pstate, OP_RANGE);
-			  write_exp_elt_longcst (pstate,
-						 (RANGE_LOW_BOUND_DEFAULT
-						  | RANGE_HIGH_BOUND_DEFAULT));
-			  write_exp_elt_opcode (pstate, OP_RANGE); }
+			{
+			  pstate->push_new<fortran_range_operation>
+			    (RANGE_LOW_BOUND_DEFAULT
+			     | RANGE_HIGH_BOUND_DEFAULT,
+			     operation_up (), operation_up (),
+			     operation_up ());
+			}
 	;
 
 /* And each of the four subrange types can also have a stride.  */
 subrange:	exp ':' exp ':' exp	%prec ABOVE_COMMA
-			{ write_exp_elt_opcode (pstate, OP_RANGE);
-			  write_exp_elt_longcst (pstate, RANGE_HAS_STRIDE);
-			  write_exp_elt_opcode (pstate, OP_RANGE); }
+			{
+			  operation_up stride = pstate->pop ();
+			  operation_up high = pstate->pop ();
+			  operation_up low = pstate->pop ();
+			  pstate->push_new<fortran_range_operation>
+			    (RANGE_STANDARD | RANGE_HAS_STRIDE,
+			     std::move (low), std::move (high),
+			     std::move (stride));
+			}
 	;
 
 subrange:	exp ':' ':' exp	%prec ABOVE_COMMA
-			{ write_exp_elt_opcode (pstate, OP_RANGE);
-			  write_exp_elt_longcst (pstate,
-						 (RANGE_HIGH_BOUND_DEFAULT
-						  | RANGE_HAS_STRIDE));
-			  write_exp_elt_opcode (pstate, OP_RANGE); }
+			{
+			  operation_up stride = pstate->pop ();
+			  operation_up low = pstate->pop ();
+			  pstate->push_new<fortran_range_operation>
+			    (RANGE_HIGH_BOUND_DEFAULT
+			     | RANGE_HAS_STRIDE,
+			     std::move (low), operation_up (),
+			     std::move (stride));
+			}
 	;
 
 subrange:	':' exp ':' exp	%prec ABOVE_COMMA
-			{ write_exp_elt_opcode (pstate, OP_RANGE);
-			  write_exp_elt_longcst (pstate,
-						 (RANGE_LOW_BOUND_DEFAULT
-						  | RANGE_HAS_STRIDE));
-			  write_exp_elt_opcode (pstate, OP_RANGE); }
+			{
+			  operation_up stride = pstate->pop ();
+			  operation_up high = pstate->pop ();
+			  pstate->push_new<fortran_range_operation>
+			    (RANGE_LOW_BOUND_DEFAULT
+			     | RANGE_HAS_STRIDE,
+			     operation_up (), std::move (high),
+			     std::move (stride));
+			}
 	;
 
 subrange:	':' ':' exp	%prec ABOVE_COMMA
-			{ write_exp_elt_opcode (pstate, OP_RANGE);
-			  write_exp_elt_longcst (pstate,
-						 (RANGE_LOW_BOUND_DEFAULT
-						  | RANGE_HIGH_BOUND_DEFAULT
-						  | RANGE_HAS_STRIDE));
-			  write_exp_elt_opcode (pstate, OP_RANGE); }
+			{
+			  operation_up stride = pstate->pop ();
+			  pstate->push_new<fortran_range_operation>
+			    (RANGE_LOW_BOUND_DEFAULT
+			     | RANGE_HIGH_BOUND_DEFAULT
+			     | RANGE_HAS_STRIDE,
+			     operation_up (), operation_up (),
+			     std::move (stride));
+			}
 	;
 
 complexnum:     exp ',' exp 
@@ -356,193 +413,197 @@ complexnum:     exp ',' exp
 	;
 
 exp	:	'(' complexnum ')'
-			{ write_exp_elt_opcode (pstate, OP_COMPLEX);
-			  write_exp_elt_type (pstate,
-					      parse_f_type (pstate)
-					      ->builtin_complex_s16);
-			  write_exp_elt_opcode (pstate, OP_COMPLEX); }
+			{
+			  operation_up rhs = pstate->pop ();
+			  operation_up lhs = pstate->pop ();
+			  pstate->push_new<complex_operation>
+			    (std::move (lhs), std::move (rhs),
+			     parse_f_type (pstate)->builtin_complex_s16);
+			}
 	;
 
 exp	:	'(' type ')' exp  %prec UNARY
-			{ write_exp_elt_opcode (pstate, UNOP_CAST);
-			  write_exp_elt_type (pstate, $2);
-			  write_exp_elt_opcode (pstate, UNOP_CAST); }
+			{
+			  pstate->push_new<unop_cast_operation>
+			    (pstate->pop (), $2);
+			}
 	;
 
 exp     :       exp '%' name
-			{ write_exp_elt_opcode (pstate, STRUCTOP_STRUCT);
-			  write_exp_string (pstate, $3);
-			  write_exp_elt_opcode (pstate, STRUCTOP_STRUCT); }
+			{
+			  pstate->push_new<structop_operation>
+			    (pstate->pop (), copy_name ($3));
+			}
 	;
 
 exp     :       exp '%' name COMPLETE
-			{ pstate->mark_struct_expression ();
-			  write_exp_elt_opcode (pstate, STRUCTOP_STRUCT);
-			  write_exp_string (pstate, $3);
-			  write_exp_elt_opcode (pstate, STRUCTOP_STRUCT); }
+			{
+			  structop_base_operation *op
+			    = new structop_operation (pstate->pop (),
+						      copy_name ($3));
+			  pstate->mark_struct_expression (op);
+			  pstate->push (operation_up (op));
+			}
 	;
 
 exp     :       exp '%' COMPLETE
-			{ struct stoken s;
-			  pstate->mark_struct_expression ();
-			  write_exp_elt_opcode (pstate, STRUCTOP_PTR);
-			  s.ptr = "";
-			  s.length = 0;
-			  write_exp_string (pstate, s);
-			  write_exp_elt_opcode (pstate, STRUCTOP_PTR); }
+			{
+			  structop_base_operation *op
+			    = new structop_operation (pstate->pop (), "");
+			  pstate->mark_struct_expression (op);
+			  pstate->push (operation_up (op));
+			}
+	;
 
 /* Binary operators in order of decreasing precedence.  */
 
 exp	:	exp '@' exp
-			{ write_exp_elt_opcode (pstate, BINOP_REPEAT); }
+			{ pstate->wrap2<repeat_operation> (); }
 	;
 
 exp	:	exp STARSTAR exp
-			{ write_exp_elt_opcode (pstate, BINOP_EXP); }
+			{ pstate->wrap2<exp_operation> (); }
 	;
 
 exp	:	exp '*' exp
-			{ write_exp_elt_opcode (pstate, BINOP_MUL); }
+			{ pstate->wrap2<mul_operation> (); }
 	;
 
 exp	:	exp '/' exp
-			{ write_exp_elt_opcode (pstate, BINOP_DIV); }
+			{ pstate->wrap2<div_operation> (); }
 	;
 
 exp	:	exp '+' exp
-			{ write_exp_elt_opcode (pstate, BINOP_ADD); }
+			{ pstate->wrap2<add_operation> (); }
 	;
 
 exp	:	exp '-' exp
-			{ write_exp_elt_opcode (pstate, BINOP_SUB); }
+			{ pstate->wrap2<sub_operation> (); }
 	;
 
 exp	:	exp LSH exp
-			{ write_exp_elt_opcode (pstate, BINOP_LSH); }
+			{ pstate->wrap2<lsh_operation> (); }
 	;
 
 exp	:	exp RSH exp
-			{ write_exp_elt_opcode (pstate, BINOP_RSH); }
+			{ pstate->wrap2<rsh_operation> (); }
 	;
 
 exp	:	exp EQUAL exp
-			{ write_exp_elt_opcode (pstate, BINOP_EQUAL); }
+			{ pstate->wrap2<equal_operation> (); }
 	;
 
 exp	:	exp NOTEQUAL exp
-			{ write_exp_elt_opcode (pstate, BINOP_NOTEQUAL); }
+			{ pstate->wrap2<notequal_operation> (); }
 	;
 
 exp	:	exp LEQ exp
-			{ write_exp_elt_opcode (pstate, BINOP_LEQ); }
+			{ pstate->wrap2<leq_operation> (); }
 	;
 
 exp	:	exp GEQ exp
-			{ write_exp_elt_opcode (pstate, BINOP_GEQ); }
+			{ pstate->wrap2<geq_operation> (); }
 	;
 
 exp	:	exp LESSTHAN exp
-			{ write_exp_elt_opcode (pstate, BINOP_LESS); }
+			{ pstate->wrap2<less_operation> (); }
 	;
 
 exp	:	exp GREATERTHAN exp
-			{ write_exp_elt_opcode (pstate, BINOP_GTR); }
+			{ pstate->wrap2<gtr_operation> (); }
 	;
 
 exp	:	exp '&' exp
-			{ write_exp_elt_opcode (pstate, BINOP_BITWISE_AND); }
+			{ pstate->wrap2<bitwise_and_operation> (); }
 	;
 
 exp	:	exp '^' exp
-			{ write_exp_elt_opcode (pstate, BINOP_BITWISE_XOR); }
+			{ pstate->wrap2<bitwise_xor_operation> (); }
 	;
 
 exp	:	exp '|' exp
-			{ write_exp_elt_opcode (pstate, BINOP_BITWISE_IOR); }
+			{ pstate->wrap2<bitwise_ior_operation> (); }
 	;
 
 exp     :       exp BOOL_AND exp
-			{ write_exp_elt_opcode (pstate, BINOP_LOGICAL_AND); }
+			{ pstate->wrap2<logical_and_operation> (); }
 	;
 
 
 exp	:	exp BOOL_OR exp
-			{ write_exp_elt_opcode (pstate, BINOP_LOGICAL_OR); }
+			{ pstate->wrap2<logical_or_operation> (); }
 	;
 
 exp	:	exp '=' exp
-			{ write_exp_elt_opcode (pstate, BINOP_ASSIGN); }
+			{ pstate->wrap2<assign_operation> (); }
 	;
 
 exp	:	exp ASSIGN_MODIFY exp
-			{ write_exp_elt_opcode (pstate, BINOP_ASSIGN_MODIFY);
-			  write_exp_elt_opcode (pstate, $2);
-			  write_exp_elt_opcode (pstate, BINOP_ASSIGN_MODIFY); }
+			{
+			  operation_up rhs = pstate->pop ();
+			  operation_up lhs = pstate->pop ();
+			  pstate->push_new<assign_modify_operation>
+			    ($2, std::move (lhs), std::move (rhs));
+			}
 	;
 
 exp	:	INT
-			{ write_exp_elt_opcode (pstate, OP_LONG);
-			  write_exp_elt_type (pstate, $1.type);
-			  write_exp_elt_longcst (pstate, (LONGEST) ($1.val));
-			  write_exp_elt_opcode (pstate, OP_LONG); }
+			{
+			  pstate->push_new<long_const_operation>
+			    ($1.type, $1.val);
+			}
 	;
 
 exp	:	NAME_OR_INT
 			{ YYSTYPE val;
 			  parse_number (pstate, $1.stoken.ptr,
 					$1.stoken.length, 0, &val);
-			  write_exp_elt_opcode (pstate, OP_LONG);
-			  write_exp_elt_type (pstate, val.typed_val.type);
-			  write_exp_elt_longcst (pstate,
-						 (LONGEST)val.typed_val.val);
-			  write_exp_elt_opcode (pstate, OP_LONG); }
+			  pstate->push_new<long_const_operation>
+			    (val.typed_val.type,
+			     val.typed_val.val);
+			}
 	;
 
 exp	:	FLOAT
-			{ write_exp_elt_opcode (pstate, OP_FLOAT);
-			  write_exp_elt_type (pstate, $1.type);
-			  write_exp_elt_floatcst (pstate, $1.val);
-			  write_exp_elt_opcode (pstate, OP_FLOAT); }
+			{
+			  float_data data;
+			  std::copy (std::begin ($1.val), std::end ($1.val),
+				     std::begin (data));
+			  pstate->push_new<float_const_operation> ($1.type, data);
+			}
 	;
 
 exp	:	variable
 	;
 
 exp	:	DOLLAR_VARIABLE
-			{ write_dollar_variable (pstate, $1); }
+			{ pstate->push_dollar ($1); }
 	;
 
 exp	:	SIZEOF '(' type ')'	%prec UNARY
-			{ write_exp_elt_opcode (pstate, OP_LONG);
-			  write_exp_elt_type (pstate,
-					      parse_f_type (pstate)
-					      ->builtin_integer);
+			{
 			  $3 = check_typedef ($3);
-			  write_exp_elt_longcst (pstate,
-						 (LONGEST) TYPE_LENGTH ($3));
-			  write_exp_elt_opcode (pstate, OP_LONG); }
+			  pstate->push_new<long_const_operation>
+			    (parse_f_type (pstate)->builtin_integer,
+			     TYPE_LENGTH ($3));
+			}
 	;
 
 exp     :       BOOLEAN_LITERAL
-			{ write_exp_elt_opcode (pstate, OP_BOOL);
-			  write_exp_elt_longcst (pstate, (LONGEST) $1);
-			  write_exp_elt_opcode (pstate, OP_BOOL);
-			}
+			{ pstate->push_new<bool_operation> ($1); }
 	;
 
 exp	:	STRING_LITERAL
 			{
-			  write_exp_elt_opcode (pstate, OP_STRING);
-			  write_exp_string (pstate, $1);
-			  write_exp_elt_opcode (pstate, OP_STRING);
+			  pstate->push_new<string_operation>
+			    (copy_name ($1));
 			}
 	;
 
 variable:	name_not_typename
 			{ struct block_symbol sym = $1.sym;
 			  std::string name = copy_name ($1.stoken);
-			  write_exp_symbol_reference (pstate, name.c_str (),
-						      sym.symbol);
+			  pstate->push_symbol (name.c_str (), sym.symbol);
 			}
 	;
 
@@ -1415,7 +1476,10 @@ f_language::parser (struct parser_state *par_state) const
   scoped_restore restore_type_stack = make_scoped_restore (&type_stack,
 							   &stack);
 
-  return yyparse ();
+  int result = yyparse ();
+  if (!result)
+    pstate->set_operation (pstate->pop ());
+  return result;
 }
 
 static void
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 184/203] Convert ada-exp.y to use operations
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (182 preceding siblings ...)
  2021-01-01 21:47 ` [PATCH 183/203] Convert f-exp.y " Tom Tromey
@ 2021-01-01 21:47 ` Tom Tromey
  2021-01-01 21:47 ` [PATCH 185/203] Remove now-unused Rust evaluator code Tom Tromey
                   ` (19 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:47 UTC (permalink / raw)
  To: gdb-patches

This converts the Ada parser to generate operations rather than
exp_elements.

This was the most difficult of the parser conversions, partly due to
the decision to integrate Ada expression resolution into the parse,
and partly due to Ada aggregregate assignment.  A couple of new
per-parse globals are introduced, along with a number of helper
functions.  Resolution is done in 'ada_pop', yielding the unfortunate
rule that ada-exp.y should generally not use parser_state::pop
(exceptions are marked).

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* ada-exp.y: Create operations.
	(empty_stoken): Remove.
	(ada_pop, ada_wrap, ada_addrof, ada_un_wrap2, ada_wrap2)
	(ada_wrap_op, ada_wrap3, ada_funcall): New functions.
	(components): New global.
	(push_component, choice_component, pop_component, pop_components):
	New functions.
	(associations): New global
	(push_association, pop_association, pop_associations): New
	functions.
	(ada_parse): Update.
	(write_var_from_sym, write_int): Create operations.
	(write_exp_op_with_string): Remove.
	(write_object_renaming, write_selectors, write_ambiguous_var)
	(write_var_or_type, write_name_assoc): Create operations.
---
 gdb/ChangeLog |  18 ++
 gdb/ada-exp.y | 621 +++++++++++++++++++++++++++++++++-----------------
 2 files changed, 436 insertions(+), 203 deletions(-)

diff --git a/gdb/ada-exp.y b/gdb/ada-exp.y
index b55a0b434f7..033bde38d3c 100644
--- a/gdb/ada-exp.y
+++ b/gdb/ada-exp.y
@@ -47,6 +47,7 @@
 #include "objfiles.h" /* For have_full_symbols and have_partial_symbols */
 #include "frame.h"
 #include "block.h"
+#include "ada-exp.h"
 
 #define parse_type(ps) builtin_type (ps->gdbarch ())
 
@@ -67,8 +68,6 @@ struct name_info {
 
 static struct parser_state *pstate = NULL;
 
-static struct stoken empty_stoken = { "", 0 };
-
 /* If expression is in the context of TYPE'(...), then TYPE, else
  * NULL.  */
 static struct type *type_qualifier;
@@ -90,9 +89,6 @@ static struct type* write_var_or_type (struct parser_state *,
 
 static void write_name_assoc (struct parser_state *, struct stoken);
 
-static void write_exp_op_with_string (struct parser_state *, enum exp_opcode,
-				      struct stoken);
-
 static const struct block *block_lookup (const struct block *, const char *);
 
 static LONGEST convert_char_literal (struct type *, LONGEST);
@@ -114,6 +110,198 @@ static struct type *type_boolean (struct parser_state *);
 
 static struct type *type_system_address (struct parser_state *);
 
+using namespace expr;
+
+/* Like parser_state::pop, but handles Ada type resolution.
+   DEPROCEDURE_P and CONTEXT_TYPE are passed to the resolve method, if
+   called.  */
+static operation_up
+ada_pop (bool deprocedure_p = true, struct type *context_type = nullptr)
+{
+  /* Of course it's ok to call parser_state::pop here... */
+  operation_up result = pstate->pop ();
+  ada_resolvable *res = dynamic_cast<ada_resolvable *> (result.get ());
+  if (res != nullptr
+      && res->resolve (pstate->expout.get (),
+		       deprocedure_p,
+		       pstate->parse_completion,
+		       pstate->block_tracker,
+		       context_type))
+    result
+      = make_operation<ada_funcall_operation> (std::move (result),
+					       std::vector<operation_up> ());
+
+  return result;
+}
+
+/* Like parser_state::wrap, but use ada_pop to pop the value.  */
+template<typename T>
+void
+ada_wrap ()
+{
+  operation_up arg = ada_pop ();
+  pstate->push_new<T> (std::move (arg));
+}
+
+/* Create and push an address-of operation, as appropriate for Ada.
+   If TYPE is not NULL, the resulting operation will be wrapped in a
+   cast to TYPE.  */
+static void
+ada_addrof (struct type *type = nullptr)
+{
+  operation_up arg = ada_pop (false);
+  operation_up addr = make_operation<unop_addr_operation> (std::move (arg));
+  operation_up wrapped
+    = make_operation<ada_wrapped_operation> (std::move (addr));
+  if (type != nullptr)
+    wrapped = make_operation<unop_cast_operation> (std::move (wrapped), type);
+  pstate->push (std::move (wrapped));
+}
+
+/* A variant of parser_state::wrap2 that uses ada_pop to pop both
+   operands, and then pushes a new Ada-wrapped operation of the
+   template type T.  */
+template<typename T>
+void
+ada_un_wrap2 ()
+{
+  operation_up rhs = ada_pop ();
+  operation_up lhs = ada_pop ();
+  operation_up wrapped = make_operation<T> (std::move (lhs), std::move (rhs));
+  pstate->push_new<ada_wrapped_operation> (std::move (wrapped));
+}
+
+/* A variant of parser_state::wrap2 that uses ada_pop to pop both
+   operands.  Unlike ada_un_wrap2, ada_wrapped_operation is not
+   used.  */
+template<typename T>
+void
+ada_wrap2 ()
+{
+  operation_up rhs = ada_pop ();
+  operation_up lhs = ada_pop ();
+  pstate->push_new<T> (std::move (lhs), std::move (rhs));
+}
+
+/* A variant of parser_state::wrap2 that uses ada_pop to pop both
+   operands.  OP is also passed to the constructor of the new binary
+   operation.  */
+template<typename T>
+void
+ada_wrap_op (enum exp_opcode op)
+{
+  operation_up rhs = ada_pop ();
+  operation_up lhs = ada_pop ();
+  pstate->push_new<T> (op, std::move (lhs), std::move (rhs));
+}
+
+/* Pop three operands using ada_pop, then construct a new ternary
+   operation of type T and push it.  */
+template<typename T>
+void
+ada_wrap3 ()
+{
+  operation_up rhs = ada_pop ();
+  operation_up mid = ada_pop ();
+  operation_up lhs = ada_pop ();
+  pstate->push_new<T> (std::move (lhs), std::move (mid), std::move (rhs));
+}
+
+/* Pop NARGS operands, then a callee operand, and use these to
+   construct and push a new Ada function call operation.  */
+static void
+ada_funcall (int nargs)
+{
+  std::vector<operation_up> args (nargs);
+  for (int i = 0; i < nargs; ++i)
+    args[nargs - i - 1] = ada_pop ();
+  /* Call parser_state::pop here, because we don't want to
+     function-convert the callee slot of a call we're already
+     constructing.  */
+  operation_up callee = pstate->pop ();
+  pstate->push_new<ada_funcall_operation> (std::move (callee),
+					   std::move (args));
+}
+
+/* The components being constructed during this parse.  */
+static std::vector<ada_component_up> components;
+
+/* Create a new ada_component_up of the indicated type and arguments,
+   and push it on the global 'components' vector.  */
+template<typename T, typename... Arg>
+void
+push_component (Arg... args)
+{
+  components.emplace_back (new T (std::forward<Arg> (args)...));
+}
+
+/* Examine the final element of the 'components' vector, and return it
+   as a pointer to an ada_choices_component.  The caller is
+   responsible for ensuring that the final element is in fact an
+   ada_choices_component.  */
+static ada_choices_component *
+choice_component ()
+{
+  ada_component *last = components.back ().get ();
+  ada_choices_component *result = dynamic_cast<ada_choices_component *> (last);
+  gdb_assert (result != nullptr);
+  return result;
+}
+
+/* Pop the most recent component from the global stack, and return
+   it.  */
+static ada_component_up
+pop_component ()
+{
+  ada_component_up result = std::move (components.back ());
+  components.pop_back ();
+  return result;
+}
+
+/* Pop the N most recent components from the global stack, and return
+   them in a vector.  */
+static std::vector<ada_component_up>
+pop_components (int n)
+{
+  std::vector<ada_component_up> result (n);
+  for (int i = 1; i <= n; ++i)
+    result[n - i] = pop_component ();
+  return result;
+}
+
+/* The associations being constructed during this parse.  */
+static std::vector<ada_association_up> associations;
+
+/* Create a new ada_association_up of the indicated type and
+   arguments, and push it on the global 'associations' vector.  */
+template<typename T, typename... Arg>
+void
+push_association (Arg... args)
+{
+  associations.emplace_back (new T (std::forward<Arg> (args)...));
+}
+
+/* Pop the most recent association from the global stack, and return
+   it.  */
+static ada_association_up
+pop_association ()
+{
+  ada_association_up result = std::move (associations.back ());
+  associations.pop_back ();
+  return result;
+}
+
+/* Pop the N most recent associations from the global stack, and
+   return them in a vector.  */
+static std::vector<ada_association_up>
+pop_associations (int n)
+{
+  std::vector<ada_association_up> result (n);
+  for (int i = 1; i <= n; ++i)
+    result[n - i] = pop_association ();
+  return result;
+}
+
 %}
 
 %union
@@ -135,7 +323,7 @@ static struct type *type_system_address (struct parser_state *);
 
 %type <lval> positional_list component_groups component_associations
 %type <lval> aggregate_component_list 
-%type <tval> var_or_type
+%type <tval> var_or_type type_prefix opt_type_prefix
 
 %token <typed_val> INT NULL_PTR CHARLIT
 %token <typed_val_float> FLOAT
@@ -188,43 +376,38 @@ start   :	exp1
 /* Expressions, including the sequencing operator.  */
 exp1	:	exp
 	|	exp1 ';' exp
-			{ write_exp_elt_opcode (pstate, BINOP_COMMA); }
+			{ ada_wrap2<comma_operation> (); }
 	| 	primary ASSIGN exp   /* Extension for convenience */
-			{ write_exp_elt_opcode (pstate, BINOP_ASSIGN); }
+			{ ada_wrap2<ada_assign_operation> (); }
 	;
 
 /* Expressions, not including the sequencing operator.  */
 primary :	primary DOT_ALL
-			{ write_exp_elt_opcode (pstate, UNOP_IND); }
+			{ ada_wrap<ada_unop_ind_operation> (); }
 	;
 
 primary :	primary DOT_ID
-			{ write_exp_op_with_string (pstate, STRUCTOP_STRUCT,
-						    $2); }
+			{
+			  operation_up arg = ada_pop ();
+			  pstate->push_new<ada_structop_operation>
+			    (std::move (arg), copy_name ($2));
+			}
 	;
 
 primary :	primary '(' arglist ')'
-			{
-			  write_exp_elt_opcode (pstate, OP_FUNCALL);
-			  write_exp_elt_longcst (pstate, $3);
-			  write_exp_elt_opcode (pstate, OP_FUNCALL);
-			}
+			{ ada_funcall ($3); }
 	|	var_or_type '(' arglist ')'
 			{
 			  if ($1 != NULL)
 			    {
 			      if ($3 != 1)
 				error (_("Invalid conversion"));
-			      write_exp_elt_opcode (pstate, UNOP_CAST);
-			      write_exp_elt_type (pstate, $1);
-			      write_exp_elt_opcode (pstate, UNOP_CAST);
+			      operation_up arg = ada_pop ();
+			      pstate->push_new<unop_cast_operation>
+				(std::move (arg), $1);
 			    }
 			  else
-			    {
-			      write_exp_elt_opcode (pstate, OP_FUNCALL);
-			      write_exp_elt_longcst (pstate, $3);
-			      write_exp_elt_opcode (pstate, OP_FUNCALL);
-			    }
+			    ada_funcall ($3);
 			}
 	;
 
@@ -233,9 +416,10 @@ primary :	var_or_type '\'' save_qualifier { type_qualifier = $1; }
 			{
 			  if ($1 == NULL)
 			    error (_("Type required for qualification"));
-			  write_exp_elt_opcode (pstate, UNOP_QUAL);
-			  write_exp_elt_type (pstate, $1);
-			  write_exp_elt_opcode (pstate, UNOP_QUAL);
+			  operation_up arg = ada_pop (true,
+						      check_typedef ($1));
+			  pstate->push_new<ada_qual_operation>
+			    (std::move (arg), $1);
 			  type_qualifier = $3;
 			}
 	;
@@ -245,10 +429,10 @@ save_qualifier : 	{ $$ = type_qualifier; }
 
 primary :
 		primary '(' simple_exp DOTDOT simple_exp ')'
-			{ write_exp_elt_opcode (pstate, TERNOP_SLICE); }
+			{ ada_wrap3<ada_ternop_slice_operation> (); }
 	|	var_or_type '(' simple_exp DOTDOT simple_exp ')'
 			{ if ($1 == NULL) 
-			    write_exp_elt_opcode (pstate, TERNOP_SLICE);
+			    ada_wrap3<ada_ternop_slice_operation> ();
 			  else
 			    error (_("Cannot slice a type"));
 			}
@@ -267,38 +451,40 @@ primary :	'(' exp1 ')'	{ }
 
 primary :	var_or_type	%prec VAR
 			{ if ($1 != NULL)
-			    {
-			      write_exp_elt_opcode (pstate, OP_TYPE);
-			      write_exp_elt_type (pstate, $1);
-			      write_exp_elt_opcode (pstate, OP_TYPE);
-			    }
+			    pstate->push_new<type_operation> ($1);
 			}
 	;
 
 primary :	DOLLAR_VARIABLE /* Various GDB extensions */
-			{ write_dollar_variable (pstate, $1); }
+			{ pstate->push_dollar ($1); }
 	;
 
 primary :     	aggregate
+			{
+			  pstate->push_new<ada_aggregate_operation>
+			    (pop_component ());
+			}
 	;        
 
 simple_exp : 	primary
 	;
 
 simple_exp :	'-' simple_exp    %prec UNARY
-			{ write_exp_elt_opcode (pstate, UNOP_NEG); }
+			{ ada_wrap<ada_neg_operation> (); }
 	;
 
 simple_exp :	'+' simple_exp    %prec UNARY
-			{ write_exp_elt_opcode (pstate, UNOP_PLUS); }
+			{
+			  /* No need to do anything.  */
+			}
 	;
 
 simple_exp :	NOT simple_exp    %prec UNARY
-			{ write_exp_elt_opcode (pstate, UNOP_LOGICAL_NOT); }
+			{ ada_wrap<unary_logical_not_operation> (); }
 	;
 
 simple_exp :    ABS simple_exp	   %prec UNARY
-			{ write_exp_elt_opcode (pstate, UNOP_ABS); }
+			{ ada_wrap<ada_abs_operation> (); }
 	;
 
 arglist	:		{ $$ = 0; }
@@ -319,111 +505,114 @@ primary :	'{' var_or_type '}' primary  %prec '.'
 			{ 
 			  if ($2 == NULL)
 			    error (_("Type required within braces in coercion"));
-			  write_exp_elt_opcode (pstate, UNOP_MEMVAL);
-			  write_exp_elt_type (pstate, $2);
-			  write_exp_elt_opcode (pstate, UNOP_MEMVAL);
+			  operation_up arg = ada_pop ();
+			  pstate->push_new<unop_memval_operation>
+			    (std::move (arg), $2);
 			}
 	;
 
 /* Binary operators in order of decreasing precedence.  */
 
 simple_exp 	: 	simple_exp STARSTAR simple_exp
-			{ write_exp_elt_opcode (pstate, BINOP_EXP); }
+			{ ada_wrap2<ada_binop_exp_operation> (); }
 	;
 
 simple_exp	:	simple_exp '*' simple_exp
-			{ write_exp_elt_opcode (pstate, BINOP_MUL); }
+			{ ada_wrap2<ada_binop_mul_operation> (); }
 	;
 
 simple_exp	:	simple_exp '/' simple_exp
-			{ write_exp_elt_opcode (pstate, BINOP_DIV); }
+			{ ada_wrap2<ada_binop_div_operation> (); }
 	;
 
 simple_exp	:	simple_exp REM simple_exp /* May need to be fixed to give correct Ada REM */
-			{ write_exp_elt_opcode (pstate, BINOP_REM); }
+			{ ada_wrap2<ada_binop_rem_operation> (); }
 	;
 
 simple_exp	:	simple_exp MOD simple_exp
-			{ write_exp_elt_opcode (pstate, BINOP_MOD); }
+			{ ada_wrap2<ada_binop_mod_operation> (); }
 	;
 
 simple_exp	:	simple_exp '@' simple_exp	/* GDB extension */
-			{ write_exp_elt_opcode (pstate, BINOP_REPEAT); }
+			{ ada_wrap2<repeat_operation> (); }
 	;
 
 simple_exp	:	simple_exp '+' simple_exp
-			{ write_exp_elt_opcode (pstate, BINOP_ADD); }
+			{ ada_wrap_op<ada_binop_addsub_operation> (BINOP_ADD); }
 	;
 
 simple_exp	:	simple_exp '&' simple_exp
-			{ write_exp_elt_opcode (pstate, BINOP_CONCAT); }
+			{ ada_wrap2<concat_operation> (); }
 	;
 
 simple_exp	:	simple_exp '-' simple_exp
-			{ write_exp_elt_opcode (pstate, BINOP_SUB); }
+			{ ada_wrap_op<ada_binop_addsub_operation> (BINOP_SUB); }
 	;
 
 relation :	simple_exp
 	;
 
 relation :	simple_exp '=' simple_exp
-			{ write_exp_elt_opcode (pstate, BINOP_EQUAL); }
+			{ ada_wrap_op<ada_binop_equal_operation> (BINOP_EQUAL); }
 	;
 
 relation :	simple_exp NOTEQUAL simple_exp
-			{ write_exp_elt_opcode (pstate, BINOP_NOTEQUAL); }
+			{ ada_wrap_op<ada_binop_equal_operation> (BINOP_NOTEQUAL); }
 	;
 
 relation :	simple_exp LEQ simple_exp
-			{ write_exp_elt_opcode (pstate, BINOP_LEQ); }
+			{ ada_un_wrap2<leq_operation> (); }
 	;
 
 relation :	simple_exp IN simple_exp DOTDOT simple_exp
-			{ write_exp_elt_opcode (pstate, TERNOP_IN_RANGE); }
+			{ ada_wrap3<ada_ternop_range_operation> (); }
 	|       simple_exp IN primary TICK_RANGE tick_arglist
-			{ write_exp_elt_opcode (pstate, BINOP_IN_BOUNDS);
-			  write_exp_elt_longcst (pstate, (LONGEST) $5);
-			  write_exp_elt_opcode (pstate, BINOP_IN_BOUNDS);
+			{
+			  operation_up rhs = ada_pop ();
+			  operation_up lhs = ada_pop ();
+			  pstate->push_new<ada_binop_in_bounds_operation>
+			    (std::move (lhs), std::move (rhs), $5);
 			}
  	|	simple_exp IN var_or_type	%prec TICK_ACCESS
 			{ 
 			  if ($3 == NULL)
 			    error (_("Right operand of 'in' must be type"));
-			  write_exp_elt_opcode (pstate, UNOP_IN_RANGE);
-			  write_exp_elt_type (pstate, $3);
-			  write_exp_elt_opcode (pstate, UNOP_IN_RANGE);
+			  operation_up arg = ada_pop ();
+			  pstate->push_new<ada_unop_range_operation>
+			    (std::move (arg), $3);
 			}
 	|	simple_exp NOT IN simple_exp DOTDOT simple_exp
-			{ write_exp_elt_opcode (pstate, TERNOP_IN_RANGE);
-			  write_exp_elt_opcode (pstate, UNOP_LOGICAL_NOT);
-			}
+			{ ada_wrap3<ada_ternop_range_operation> ();
+			  ada_wrap<unary_logical_not_operation> (); }
 	|       simple_exp NOT IN primary TICK_RANGE tick_arglist
-			{ write_exp_elt_opcode (pstate, BINOP_IN_BOUNDS);
-			  write_exp_elt_longcst (pstate, (LONGEST) $6);
-			  write_exp_elt_opcode (pstate, BINOP_IN_BOUNDS);
-			  write_exp_elt_opcode (pstate, UNOP_LOGICAL_NOT);
+			{
+			  operation_up rhs = ada_pop ();
+			  operation_up lhs = ada_pop ();
+			  pstate->push_new<ada_binop_in_bounds_operation>
+			    (std::move (lhs), std::move (rhs), $6);
+			  ada_wrap<unary_logical_not_operation> ();
 			}
  	|	simple_exp NOT IN var_or_type	%prec TICK_ACCESS
 			{ 
 			  if ($4 == NULL)
 			    error (_("Right operand of 'in' must be type"));
-			  write_exp_elt_opcode (pstate, UNOP_IN_RANGE);
-			  write_exp_elt_type (pstate, $4);
-			  write_exp_elt_opcode (pstate, UNOP_IN_RANGE);
-			  write_exp_elt_opcode (pstate, UNOP_LOGICAL_NOT);
+			  operation_up arg = ada_pop ();
+			  pstate->push_new<ada_unop_range_operation>
+			    (std::move (arg), $4);
+			  ada_wrap<unary_logical_not_operation> ();
 			}
 	;
 
 relation :	simple_exp GEQ simple_exp
-			{ write_exp_elt_opcode (pstate, BINOP_GEQ); }
+			{ ada_un_wrap2<geq_operation> (); }
 	;
 
 relation :	simple_exp '<' simple_exp
-			{ write_exp_elt_opcode (pstate, BINOP_LESS); }
+			{ ada_un_wrap2<less_operation> (); }
 	;
 
 relation :	simple_exp '>' simple_exp
-			{ write_exp_elt_opcode (pstate, BINOP_GTR); }
+			{ ada_un_wrap2<gtr_operation> (); }
 	;
 
 exp	:	relation
@@ -436,36 +625,36 @@ exp	:	relation
 
 and_exp :
 		relation _AND_ relation 
-			{ write_exp_elt_opcode (pstate, BINOP_BITWISE_AND); }
+			{ ada_wrap2<ada_bitwise_and_operation> (); }
 	|	and_exp _AND_ relation
-			{ write_exp_elt_opcode (pstate, BINOP_BITWISE_AND); }
+			{ ada_wrap2<ada_bitwise_and_operation> (); }
 	;
 
 and_then_exp :
 	       relation _AND_ THEN relation
-			{ write_exp_elt_opcode (pstate, BINOP_LOGICAL_AND); }
+			{ ada_wrap2<logical_and_operation> (); }
 	|	and_then_exp _AND_ THEN relation
-			{ write_exp_elt_opcode (pstate, BINOP_LOGICAL_AND); }
+			{ ada_wrap2<logical_and_operation> (); }
 	;
 
 or_exp :
 		relation OR relation 
-			{ write_exp_elt_opcode (pstate, BINOP_BITWISE_IOR); }
+			{ ada_wrap2<ada_bitwise_ior_operation> (); }
 	|	or_exp OR relation
-			{ write_exp_elt_opcode (pstate, BINOP_BITWISE_IOR); }
+			{ ada_wrap2<ada_bitwise_ior_operation> (); }
 	;
 
 or_else_exp :
 	       relation OR ELSE relation
-			{ write_exp_elt_opcode (pstate, BINOP_LOGICAL_OR); }
+			{ ada_wrap2<logical_or_operation> (); }
 	|      or_else_exp OR ELSE relation
-			{ write_exp_elt_opcode (pstate, BINOP_LOGICAL_OR); }
+			{ ada_wrap2<logical_or_operation> (); }
 	;
 
 xor_exp :       relation XOR relation
-			{ write_exp_elt_opcode (pstate, BINOP_BITWISE_XOR); }
+			{ ada_wrap2<ada_bitwise_xor_operation> (); }
 	|	xor_exp XOR relation
-			{ write_exp_elt_opcode (pstate, BINOP_BITWISE_XOR); }
+			{ ada_wrap2<ada_bitwise_xor_operation> (); }
 	;
 
 /* Primaries can denote types (OP_TYPE).  In cases such as 
@@ -477,37 +666,51 @@ xor_exp :       relation XOR relation
    aType'access evaluates to a type that evaluate_subexp attempts to 
    evaluate. */
 primary :	primary TICK_ACCESS
-			{ write_exp_elt_opcode (pstate, UNOP_ADDR); }
+			{ ada_addrof (); }
 	|	primary TICK_ADDRESS
-			{ write_exp_elt_opcode (pstate, UNOP_ADDR);
-			  write_exp_elt_opcode (pstate, UNOP_CAST);
-			  write_exp_elt_type (pstate,
-					      type_system_address (pstate));
-			  write_exp_elt_opcode (pstate, UNOP_CAST);
-			}
+			{ ada_addrof (type_system_address (pstate)); }
 	|	primary TICK_FIRST tick_arglist
-			{ write_int (pstate, $3, type_int (pstate));
-			  write_exp_elt_opcode (pstate, OP_ATR_FIRST); }
+			{
+			  operation_up arg = ada_pop ();
+			  pstate->push_new<ada_unop_atr_operation>
+			    (std::move (arg), OP_ATR_FIRST, $3);
+			}
 	|	primary TICK_LAST tick_arglist
-			{ write_int (pstate, $3, type_int (pstate));
-			  write_exp_elt_opcode (pstate, OP_ATR_LAST); }
+			{
+			  operation_up arg = ada_pop ();
+			  pstate->push_new<ada_unop_atr_operation>
+			    (std::move (arg), OP_ATR_LAST, $3);
+			}
 	| 	primary TICK_LENGTH tick_arglist
-			{ write_int (pstate, $3, type_int (pstate));
-			  write_exp_elt_opcode (pstate, OP_ATR_LENGTH); }
+			{
+			  operation_up arg = ada_pop ();
+			  pstate->push_new<ada_unop_atr_operation>
+			    (std::move (arg), OP_ATR_LENGTH, $3);
+			}
 	|       primary TICK_SIZE
-			{ write_exp_elt_opcode (pstate, OP_ATR_SIZE); }
+			{ ada_wrap<ada_atr_size_operation> (); }
 	|	primary TICK_TAG
-			{ write_exp_elt_opcode (pstate, OP_ATR_TAG); }
+			{ ada_wrap<ada_atr_tag_operation> (); }
 	|       opt_type_prefix TICK_MIN '(' exp ',' exp ')'
-			{ write_exp_elt_opcode (pstate, OP_ATR_MIN); }
+			{ ada_wrap2<ada_binop_min_operation> (); }
 	|       opt_type_prefix TICK_MAX '(' exp ',' exp ')'
-			{ write_exp_elt_opcode (pstate, OP_ATR_MAX); }
+			{ ada_wrap2<ada_binop_max_operation> (); }
 	| 	opt_type_prefix TICK_POS '(' exp ')'
-			{ write_exp_elt_opcode (pstate, OP_ATR_POS); }
+			{ ada_wrap<ada_pos_operation> (); }
 	|	type_prefix TICK_VAL '(' exp ')'
-			{ write_exp_elt_opcode (pstate, OP_ATR_VAL); }
+			{
+			  operation_up arg = ada_pop ();
+			  pstate->push_new<ada_atr_val_operation>
+			    ($1, std::move (arg));
+			}
 	|	type_prefix TICK_MODULUS
-			{ write_exp_elt_opcode (pstate, OP_ATR_MODULUS); }
+			{
+			  struct type *type_arg = check_typedef ($1);
+			  if (!ada_is_modular_type (type_arg))
+			    error (_("'modulus must be applied to modular type"));
+			  write_int (pstate, ada_modulus (type_arg),
+				     TYPE_TARGET_TYPE (type_arg));
+			}
 	;
 
 tick_arglist :			%prec '('
@@ -521,18 +724,15 @@ type_prefix :
 			{ 
 			  if ($1 == NULL)
 			    error (_("Prefix must be type"));
-			  write_exp_elt_opcode (pstate, OP_TYPE);
-			  write_exp_elt_type (pstate, $1);
-			  write_exp_elt_opcode (pstate, OP_TYPE); }
+			  $$ = $1;
+			}
 	;
 
 opt_type_prefix :
 		type_prefix
+			{ $$ = $1; }
 	| 	/* EMPTY */
-			{ write_exp_elt_opcode (pstate, OP_TYPE);
-			  write_exp_elt_type (pstate,
-					  parse_type (pstate)->builtin_void);
-			  write_exp_elt_opcode (pstate, OP_TYPE); }
+			{ $$ = parse_type (pstate)->builtin_void; }
 	;
 
 
@@ -549,10 +749,13 @@ primary	:	CHARLIT
 	;
 
 primary	:	FLOAT
-			{ write_exp_elt_opcode (pstate, OP_FLOAT);
-			  write_exp_elt_type (pstate, $1.type);
-			  write_exp_elt_floatcst (pstate, $1.val);
-			  write_exp_elt_opcode (pstate, OP_FLOAT);
+			{
+			  float_data data;
+			  std::copy (std::begin ($1.val), std::end ($1.val),
+				     std::begin (data));
+			  pstate->push_new<float_const_operation>
+			    ($1.type, data);
+			  ada_wrap<ada_wrapped_operation> ();
 			}
 	;
 
@@ -562,7 +765,8 @@ primary	:	NULL_PTR
 
 primary	:	STRING
 			{ 
-			  write_exp_op_with_string (pstate, OP_STRING, $1);
+			  pstate->push_new<ada_string_operation>
+			    (copy_name ($1));
 			}
 	;
 
@@ -584,7 +788,7 @@ var_or_type:	NAME   	    %prec VAR
 			{ 
 			  $$ = write_var_or_type (pstate, NULL, $1);
 			  if ($$ == NULL)
-			    write_exp_elt_opcode (pstate, UNOP_ADDR);
+			    ada_addrof ();
 			  else
 			    $$ = lookup_pointer_type ($$);
 			}
@@ -592,7 +796,7 @@ var_or_type:	NAME   	    %prec VAR
 			{ 
 			  $$ = write_var_or_type (pstate, $1, $2);
 			  if ($$ == NULL)
-			    write_exp_elt_opcode (pstate, UNOP_ADDR);
+			    ada_addrof ();
 			  else
 			    $$ = lookup_pointer_type ($$);
 			}
@@ -608,18 +812,20 @@ block   :       NAME COLONCOLON
 aggregate :
 		'(' aggregate_component_list ')'  
 			{
-			  write_exp_elt_opcode (pstate, OP_AGGREGATE);
-			  write_exp_elt_longcst (pstate, $2);
-			  write_exp_elt_opcode (pstate, OP_AGGREGATE);
+			  std::vector<ada_component_up> components
+			    = pop_components ($2);
+
+			  push_component<ada_aggregate_component>
+			    (std::move (components));
 			}
 	;
 
 aggregate_component_list :
 		component_groups	 { $$ = $1; }
 	|	positional_list exp
-			{ write_exp_elt_opcode (pstate, OP_POSITIONAL);
-			  write_exp_elt_longcst (pstate, $1);
-			  write_exp_elt_opcode (pstate, OP_POSITIONAL);
+			{
+			  push_component<ada_positional_component>
+			    ($1, ada_pop ());
 			  $$ = $1 + 1;
 			}
 	|	positional_list component_groups
@@ -628,15 +834,15 @@ aggregate_component_list :
 
 positional_list :
 		exp ','
-			{ write_exp_elt_opcode (pstate, OP_POSITIONAL);
-			  write_exp_elt_longcst (pstate, 0);
-			  write_exp_elt_opcode (pstate, OP_POSITIONAL);
+			{
+			  push_component<ada_positional_component>
+			    (0, ada_pop ());
 			  $$ = 1;
 			} 
 	|	positional_list exp ','
-			{ write_exp_elt_opcode (pstate, OP_POSITIONAL);
-			  write_exp_elt_longcst (pstate, $1);
-			  write_exp_elt_opcode (pstate, OP_POSITIONAL);
+			{
+			  push_component<ada_positional_component>
+			    ($1, ada_pop ());
 			  $$ = $1 + 1; 
 			}
 	;
@@ -649,15 +855,16 @@ component_groups:
 	;
 
 others 	:	OTHERS ARROW exp
-			{ write_exp_elt_opcode (pstate, OP_OTHERS); }
+			{
+			  push_component<ada_others_component> (ada_pop ());
+			}
 	;
 
 component_group :
 		component_associations
 			{
-			  write_exp_elt_opcode (pstate, OP_CHOICES);
-			  write_exp_elt_longcst (pstate, $1);
-			  write_exp_elt_opcode (pstate, OP_CHOICES);
+			  ada_choices_component *choices = choice_component ();
+			  choices->set_associations (pop_associations ($1));
 			}
 	;
 
@@ -667,36 +874,60 @@ component_group :
    decisions until after the => or '|', we convert the ambiguity to a 
    resolved shift/reduce conflict. */
 component_associations :
-		NAME ARROW 
-			{ write_name_assoc (pstate, $1); }
-		    exp	{ $$ = 1; }
+		NAME ARROW exp
+			{
+			  push_component<ada_choices_component> (ada_pop ());
+			  write_name_assoc (pstate, $1);
+			  $$ = 1;
+			}
 	|	simple_exp ARROW exp
-			{ $$ = 1; }
-	|	simple_exp DOTDOT simple_exp ARROW 
-			{ write_exp_elt_opcode (pstate, OP_DISCRETE_RANGE);
-			  write_exp_op_with_string (pstate, OP_NAME,
-						    empty_stoken);
+			{
+			  push_component<ada_choices_component> (ada_pop ());
+			  push_association<ada_name_association> (ada_pop ());
+			  $$ = 1;
+			}
+	|	simple_exp DOTDOT simple_exp ARROW exp
+			{
+			  push_component<ada_choices_component> (ada_pop ());
+			  operation_up rhs = ada_pop ();
+			  operation_up lhs = ada_pop ();
+			  push_association<ada_discrete_range_association>
+			    (std::move (lhs), std::move (rhs));
+			  $$ = 1;
+			}
+	|	NAME '|' component_associations
+			{
+			  write_name_assoc (pstate, $1);
+			  $$ = $3 + 1;
+			}
+	|	simple_exp '|' component_associations
+			{
+			  push_association<ada_name_association> (ada_pop ());
+			  $$ = $3 + 1;
+			}
+	|	simple_exp DOTDOT simple_exp '|' component_associations
+
+			{
+			  operation_up rhs = ada_pop ();
+			  operation_up lhs = ada_pop ();
+			  push_association<ada_discrete_range_association>
+			    (std::move (lhs), std::move (rhs));
+			  $$ = $5 + 1;
 			}
-		    exp { $$ = 1; }
-	|	NAME '|' 
-			{ write_name_assoc (pstate, $1); }
-		    component_associations  { $$ = $4 + 1; }
-	|	simple_exp '|'  
-		    component_associations  { $$ = $3 + 1; }
-	|	simple_exp DOTDOT simple_exp '|'
-			{ write_exp_elt_opcode (pstate, OP_DISCRETE_RANGE); }
-		    component_associations  { $$ = $6 + 1; }
 	;
 
 /* Some extensions borrowed from C, for the benefit of those who find they
    can't get used to Ada notation in GDB.  */
 
 primary	:	'*' primary		%prec '.'
-			{ write_exp_elt_opcode (pstate, UNOP_IND); }
+			{ ada_wrap<ada_unop_ind_operation> (); }
 	|	'&' primary		%prec '.'
-			{ write_exp_elt_opcode (pstate, UNOP_ADDR); }
+			{ ada_addrof (); }
 	|	primary '[' exp ']'
-			{ write_exp_elt_opcode (pstate, BINOP_SUBSCRIPT); }
+			{
+			  ada_wrap2<subscript_operation> ();
+			  ada_wrap<ada_wrapped_operation> ();
+			}
 	;
 
 %%
@@ -737,8 +968,18 @@ ada_parse (struct parser_state *par_state)
   type_qualifier = NULL;
   obstack_free (&temp_parse_space, NULL);
   obstack_init (&temp_parse_space);
+  components.clear ();
+  associations.clear ();
 
-  return yyparse ();
+  int result = yyparse ();
+  if (!result)
+    {
+      struct type *context_type = nullptr;
+      if (par_state->void_context_p)
+	context_type = parse_type (par_state)->builtin_void;
+      pstate->set_operation (ada_pop (true, context_type));
+    }
+  return result;
 }
 
 static void
@@ -758,10 +999,7 @@ write_var_from_sym (struct parser_state *par_state,
   if (symbol_read_needs_frame (sym))
     par_state->block_tracker->update (block, INNERMOST_BLOCK_FOR_SYMBOLS);
 
-  write_exp_elt_opcode (par_state, OP_VAR_VALUE);
-  write_exp_elt_block (par_state, block);
-  write_exp_elt_sym (par_state, sym);
-  write_exp_elt_opcode (par_state, OP_VAR_VALUE);
+  par_state->push_new<ada_var_value_operation> (sym, block);
 }
 
 /* Write integer or boolean constant ARG of type TYPE.  */
@@ -769,22 +1007,10 @@ write_var_from_sym (struct parser_state *par_state,
 static void
 write_int (struct parser_state *par_state, LONGEST arg, struct type *type)
 {
-  write_exp_elt_opcode (par_state, OP_LONG);
-  write_exp_elt_type (par_state, type);
-  write_exp_elt_longcst (par_state, arg);
-  write_exp_elt_opcode (par_state, OP_LONG);
+  pstate->push_new<long_const_operation> (type, arg);
+  ada_wrap<ada_wrapped_operation> ();
 }
 
-/* Write an OPCODE, string, OPCODE sequence to the current expression.  */
-static void
-write_exp_op_with_string (struct parser_state *par_state,
-			  enum exp_opcode opcode, struct stoken token)
-{
-  write_exp_elt_opcode (par_state, opcode);
-  write_exp_string (par_state, token);
-  write_exp_elt_opcode (par_state, opcode);
-}
-  
 /* Emit expression corresponding to the renamed object named 
  * designated by RENAMED_ENTITY[0 .. RENAMED_ENTITY_LEN-1] in the
  * context of ORIG_LEFT_CONTEXT, to which is applied the operations
@@ -852,7 +1078,7 @@ write_object_renaming (struct parser_state *par_state,
       switch (*renaming_expr) {
       case 'A':
 	renaming_expr += 1;
-	write_exp_elt_opcode (par_state, UNOP_IND);
+	ada_wrap<ada_unop_ind_operation> ();
 	break;
       case 'L':
 	slice_state = LOWER_BOUND;
@@ -866,10 +1092,7 @@ write_object_renaming (struct parser_state *par_state,
 	    if (next == renaming_expr)
 	      goto BadEncoding;
 	    renaming_expr = next;
-	    write_exp_elt_opcode (par_state, OP_LONG);
-	    write_exp_elt_type (par_state, type_int (par_state));
-	    write_exp_elt_longcst (par_state, (LONGEST) val);
-	    write_exp_elt_opcode (par_state, OP_LONG);
+	    write_int (par_state, val, type_int (par_state));
 	  }
 	else
 	  {
@@ -896,25 +1119,19 @@ write_object_renaming (struct parser_state *par_state,
 				index_sym_info.symbol);
 	  }
 	if (slice_state == SIMPLE_INDEX)
-	  {
-	    write_exp_elt_opcode (par_state, OP_FUNCALL);
-	    write_exp_elt_longcst (par_state, (LONGEST) 1);
-	    write_exp_elt_opcode (par_state, OP_FUNCALL);
-	  }
+	  ada_funcall (1);
 	else if (slice_state == LOWER_BOUND)
 	  slice_state = UPPER_BOUND;
 	else if (slice_state == UPPER_BOUND)
 	  {
-	    write_exp_elt_opcode (par_state, TERNOP_SLICE);
+	    ada_wrap3<ada_ternop_slice_operation> ();
 	    slice_state = SIMPLE_INDEX;
 	  }
 	break;
 
       case 'R':
 	{
-	  struct stoken field_name;
 	  const char *end;
-	  char *buf;
 
 	  renaming_expr += 1;
 
@@ -923,13 +1140,12 @@ write_object_renaming (struct parser_state *par_state,
 	  end = strchr (renaming_expr, 'X');
 	  if (end == NULL)
 	    end = renaming_expr + strlen (renaming_expr);
-	  field_name.length = end - renaming_expr;
-	  buf = (char *) malloc (end - renaming_expr + 1);
-	  field_name.ptr = buf;
-	  strncpy (buf, renaming_expr, end - renaming_expr);
-	  buf[end - renaming_expr] = '\000';
+
+	  operation_up arg = ada_pop ();
+	  pstate->push_new<ada_structop_operation>
+	    (std::move (arg), std::string (renaming_expr,
+					   end - renaming_expr));
 	  renaming_expr = end;
-	  write_exp_op_with_string (par_state, STRUCTOP_STRUCT, field_name);
 	  break;
 	}
 
@@ -1086,15 +1302,14 @@ write_selectors (struct parser_state *par_state, char *sels)
 {
   while (*sels != '\0')
     {
-      struct stoken field_name;
       char *p = chop_separator (sels);
       sels = p;
       while (*sels != '\0' && *sels != '.' 
 	     && (sels[0] != '_' || sels[1] != '_'))
 	sels += 1;
-      field_name.length = sels - p;
-      field_name.ptr = p;
-      write_exp_op_with_string (par_state, STRUCTOP_STRUCT, field_name);
+      operation_up arg = ada_pop ();
+      pstate->push_new<ada_structop_operation>
+	(std::move (arg), std::string (p, sels - p));
     }
 }
 
@@ -1112,10 +1327,7 @@ write_ambiguous_var (struct parser_state *par_state,
   sym->set_linkage_name (obstack_strndup (&temp_parse_space, name, len));
   sym->set_language (language_ada, nullptr);
 
-  write_exp_elt_opcode (par_state, OP_VAR_VALUE);
-  write_exp_elt_block (par_state, block);
-  write_exp_elt_sym (par_state, sym);
-  write_exp_elt_opcode (par_state, OP_VAR_VALUE);
+  par_state->push_new<ada_var_value_operation> (sym, block);
 }
 
 /* A convenient wrapper around ada_get_field_index that takes
@@ -1306,7 +1518,8 @@ write_var_or_type (struct parser_state *par_state,
 		= ada_lookup_simple_minsym (encoded_name);
 	      if (msym.minsym != NULL)
 		{
-		  write_exp_msymbol (par_state, msym);
+		  par_state->push_new<ada_var_msym_value_operation>
+		    (msym.minsym, msym.objfile);
 		  /* Maybe cause error here rather than later? FIXME? */
 		  write_selectors (par_state, encoded_name + tail_index);
 		  return NULL;
@@ -1368,13 +1581,15 @@ write_name_assoc (struct parser_state *par_state, struct stoken name)
 					  VAR_DOMAIN, &syms);
 
       if (nsyms != 1 || SYMBOL_CLASS (syms[0].symbol) == LOC_TYPEDEF)
-	write_exp_op_with_string (par_state, OP_NAME, name);
+	pstate->push_new<ada_string_operation> (copy_name (name));
       else
 	write_var_from_sym (par_state, syms[0].block, syms[0].symbol);
     }
   else
     if (write_var_or_type (par_state, NULL, name) != NULL)
       error (_("Invalid use of type."));
+
+  push_association<ada_name_association> (ada_pop ());
 }
 
 /* Convert the character literal whose ASCII value would be VAL to the
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 185/203] Remove now-unused Rust evaluator code
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (183 preceding siblings ...)
  2021-01-01 21:47 ` [PATCH 184/203] Convert ada-exp.y " Tom Tromey
@ 2021-01-01 21:47 ` Tom Tromey
  2021-01-01 21:47 ` [PATCH 186/203] Remove now-unused Fortran " Tom Tromey
                   ` (18 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:47 UTC (permalink / raw)
  To: gdb-patches

Now that the Rust parser has switched to the new style, there is no
need for the old Rust evaluation code.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* rust-lang.h (class rust_language) <expression_ops,
	exp_descriptor_tab>: Remove.
	* rust-lang.c (rust_evaluate_funcall): Remove.
	(rust_range, rust_subscript, eval_op_rust_complement): Don't use
	EVAL_SKIP.
	(rust_evaluate_subexp): Remove.
	(rust_aggregate_operation::evaluate): Don't use EVAL_SKIP.
	(rust_operator_length, rust_dump_subexp_body, rust_print_subexp)
	(rust_operator_check, rust_language::exp_descriptor_tab): Remove.
---
 gdb/ChangeLog   |  12 ++
 gdb/rust-lang.c | 507 +-----------------------------------------------
 gdb/rust-lang.h |  10 -
 3 files changed, 13 insertions(+), 516 deletions(-)

diff --git a/gdb/rust-lang.c b/gdb/rust-lang.c
index 7605b64b384..5a4a4bb9937 100644
--- a/gdb/rust-lang.c
+++ b/gdb/rust-lang.c
@@ -963,82 +963,6 @@ rust_slice_type (const char *name, struct type *elt_type,
 
 \f
 
-/* A helper for rust_evaluate_subexp that handles OP_FUNCALL.  */
-
-static struct value *
-rust_evaluate_funcall (struct expression *exp, int *pos, enum noside noside)
-{
-  int i;
-  int num_args = exp->elts[*pos + 1].longconst;
-  const char *method;
-  struct value *function, *result, *arg0;
-  struct type *type, *fn_type;
-  const struct block *block;
-  struct block_symbol sym;
-
-  /* For an ordinary function call we can simply defer to the
-     generic implementation.  */
-  if (exp->elts[*pos + 3].opcode != STRUCTOP_STRUCT)
-    return evaluate_subexp_standard (NULL, exp, pos, noside);
-
-  /* Skip over the OP_FUNCALL and the STRUCTOP_STRUCT.  */
-  *pos += 4;
-  method = &exp->elts[*pos + 1].string;
-  *pos += 3 + BYTES_TO_EXP_ELEM (exp->elts[*pos].longconst + 1);
-
-  /* Evaluate the argument to STRUCTOP_STRUCT, then find its
-     type in order to look up the method.  */
-  arg0 = evaluate_subexp (nullptr, exp, pos, noside);
-
-  if (noside == EVAL_SKIP)
-    {
-      for (i = 0; i < num_args; ++i)
-	evaluate_subexp (nullptr, exp, pos, noside);
-      return arg0;
-    }
-
-  std::vector<struct value *> args (num_args + 1);
-  args[0] = arg0;
-
-  /* We don't yet implement real Deref semantics.  */
-  while (value_type (args[0])->code () == TYPE_CODE_PTR)
-    args[0] = value_ind (args[0]);
-
-  type = value_type (args[0]);
-  if ((type->code () != TYPE_CODE_STRUCT
-       && type->code () != TYPE_CODE_UNION
-       && type->code () != TYPE_CODE_ENUM)
-      || rust_tuple_type_p (type))
-    error (_("Method calls only supported on struct or enum types"));
-  if (type->name () == NULL)
-    error (_("Method call on nameless type"));
-
-  std::string name = std::string (type->name ()) + "::" + method;
-
-  block = get_selected_block (0);
-  sym = lookup_symbol (name.c_str (), block, VAR_DOMAIN, NULL);
-  if (sym.symbol == NULL)
-    error (_("Could not find function named '%s'"), name.c_str ());
-
-  fn_type = SYMBOL_TYPE (sym.symbol);
-  if (fn_type->num_fields () == 0)
-    error (_("Function '%s' takes no arguments"), name.c_str ());
-
-  if (fn_type->field (0).type ()->code () == TYPE_CODE_PTR)
-    args[0] = value_addr (args[0]);
-
-  function = address_of_variable (sym.symbol, block);
-
-  for (i = 0; i < num_args; ++i)
-    args[i + 1] = evaluate_subexp (nullptr, exp, pos, noside);
-
-  if (noside == EVAL_AVOID_SIDE_EFFECTS)
-    result = value_zero (TYPE_TARGET_TYPE (fn_type), not_lval);
-  else
-    result = call_function_by_hand (function, NULL, args);
-  return result;
-}
-
 /* A helper for rust_evaluate_subexp that handles OP_RANGE.  */
 
 struct value *
@@ -1055,9 +979,6 @@ rust_range (struct type *expect_type, struct expression *exp,
 
   bool inclusive = !(kind & RANGE_HIGH_BOUND_EXCLUSIVE);
 
-  if (noside == EVAL_SKIP)
-    return value_from_longest (builtin_type (exp->gdbarch)->builtin_int, 1);
-
   if (low == NULL)
     {
       if (high == NULL)
@@ -1181,9 +1102,6 @@ rust_subscript (struct type *expect_type, struct expression *exp,
   LONGEST high = 0;
   int want_slice = 0;
 
-  if (noside == EVAL_SKIP)
-    return lhs;
-
   rhstype = check_typedef (value_type (rhs));
   if (rust_range_type_p (rhstype))
     {
@@ -1347,11 +1265,6 @@ eval_op_rust_complement (struct type *expect_type, struct expression *exp,
 			 enum exp_opcode opcode,
 			 struct value *value)
 {
-  if (noside == EVAL_SKIP)
-    {
-      /* Preserving the type is enough.  */
-      return value;
-    }
   if (value_type (value)->code () == TYPE_CODE_BOOL)
     return value_from_longest (value_type (value), value_logical_not (value));
   return value_complement (value);
@@ -1502,204 +1415,6 @@ eval_op_rust_structop (struct type *expect_type, struct expression *exp,
   return result;
 }
 
-/* evaluate_exp implementation for Rust.  */
-
-static struct value *
-rust_evaluate_subexp (struct type *expect_type, struct expression *exp,
-		      int *pos, enum noside noside)
-{
-  struct value *result;
-  enum exp_opcode op = exp->elts[*pos].opcode;
-
-  switch (op)
-    {
-    case UNOP_IND:
-      {
-	if (noside != EVAL_NORMAL)
-	  result = evaluate_subexp_standard (expect_type, exp, pos, noside);
-	else
-	  {
-	    ++*pos;
-	    struct value *value = evaluate_subexp (expect_type, exp, pos,
-						   noside);
-	    result = eval_op_rust_ind (expect_type, exp, noside, op, value);
-	  }
-      }
-      break;
-
-    case UNOP_COMPLEMENT:
-      {
-	struct value *value;
-
-	++*pos;
-	value = evaluate_subexp (nullptr, exp, pos, noside);
-	result = eval_op_rust_complement (expect_type, exp, noside, op, value);
-      }
-      break;
-
-    case BINOP_SUBSCRIPT:
-      {
-	++*pos;
-	struct value *lhs = evaluate_subexp (nullptr, exp, pos, noside);
-	struct value *rhs = evaluate_subexp (nullptr, exp, pos, noside);
-	result = rust_subscript (expect_type, exp, noside, false, lhs, rhs);
-      }
-      break;
-
-    case OP_FUNCALL:
-      result = rust_evaluate_funcall (exp, pos, noside);
-      break;
-
-    case OP_AGGREGATE:
-      {
-	int pc = (*pos)++;
-	struct type *type = exp->elts[pc + 1].type;
-	int arglen = longest_to_int (exp->elts[pc + 2].longconst);
-	int i;
-	CORE_ADDR addr = 0;
-	struct value *addrval = NULL;
-
-	*pos += 3;
-
-	if (noside == EVAL_NORMAL)
-	  {
-	    addrval = value_allocate_space_in_inferior (TYPE_LENGTH (type));
-	    addr = value_as_long (addrval);
-	    result = value_at_lazy (type, addr);
-	  }
-
-	if (arglen > 0 && exp->elts[*pos].opcode == OP_OTHERS)
-	  {
-	    struct value *init;
-
-	    ++*pos;
-	    init = rust_evaluate_subexp (NULL, exp, pos, noside);
-	    if (noside == EVAL_NORMAL)
-	      {
-		/* This isn't quite right but will do for the time
-		   being, seeing that we can't implement the Copy
-		   trait anyway.  */
-		value_assign (result, init);
-	      }
-
-	    --arglen;
-	  }
-
-	gdb_assert (arglen % 2 == 0);
-	for (i = 0; i < arglen; i += 2)
-	  {
-	    int len;
-	    const char *fieldname;
-	    struct value *value, *field;
-
-	    gdb_assert (exp->elts[*pos].opcode == OP_NAME);
-	    ++*pos;
-	    len = longest_to_int (exp->elts[*pos].longconst);
-	    ++*pos;
-	    fieldname = &exp->elts[*pos].string;
-	    *pos += 2 + BYTES_TO_EXP_ELEM (len + 1);
-
-	    value = rust_evaluate_subexp (NULL, exp, pos, noside);
-	    if (noside == EVAL_NORMAL)
-	      {
-		field = value_struct_elt (&result, NULL, fieldname, NULL,
-					  "structure");
-		value_assign (field, value);
-	      }
-	  }
-
-	if (noside == EVAL_SKIP)
-	  return value_from_longest (builtin_type (exp->gdbarch)->builtin_int,
-				     1);
-	else if (noside == EVAL_AVOID_SIDE_EFFECTS)
-	  result = allocate_value (type);
-	else
-	  result = value_at_lazy (type, addr);
-      }
-      break;
-
-    case OP_RUST_ARRAY:
-      {
-	(*pos)++;
-	struct value *elt;
-	struct value *ncopies;
-
-	elt = rust_evaluate_subexp (NULL, exp, pos, noside);
-	ncopies = rust_evaluate_subexp (NULL, exp, pos, noside);
-	return eval_op_rust_array (expect_type, exp, noside, op, elt, ncopies);
-      }
-      break;
-
-    case STRUCTOP_ANONYMOUS:
-      {
-	/* Anonymous field access, i.e. foo.1.  */
-	struct value *lhs;
-	int pc, field_number;
-
-	pc = (*pos)++;
-	field_number = longest_to_int (exp->elts[pc + 1].longconst);
-	(*pos) += 2;
-	lhs = evaluate_subexp (nullptr, exp, pos, noside);
-
-	return eval_op_rust_struct_anon (expect_type, exp, noside,
-					 field_number, lhs);
-      }
-      break;
-
-    case STRUCTOP_STRUCT:
-      {
-	struct value *lhs;
-	int tem, pc;
-
-	pc = (*pos)++;
-	tem = longest_to_int (exp->elts[pc + 1].longconst);
-	(*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1);
-	lhs = evaluate_subexp (nullptr, exp, pos, noside);
-
-	const char *field_name = &exp->elts[pc + 2].string;
-	return eval_op_rust_structop (expect_type, exp, noside, lhs,
-				      field_name);
-      }
-      break;
-
-    case OP_RANGE:
-      {
-	struct value *low = NULL, *high = NULL;
-	auto kind
-	  = (enum range_flag) longest_to_int (exp->elts[*pos + 1].longconst);
-	*pos += 3;
-
-	if (!(kind & RANGE_LOW_BOUND_DEFAULT))
-	  low = evaluate_subexp (nullptr, exp, pos, noside);
-	if (!(kind & RANGE_HIGH_BOUND_DEFAULT))
-	  high = evaluate_subexp (nullptr, exp, pos, noside);
-
-	result = rust_range (expect_type, exp, noside, kind, low, high);
-      }
-      break;
-
-    case UNOP_ADDR:
-      /* We might have &array[range], in which case we need to make a
-	 slice.  */
-      if (exp->elts[*pos + 1].opcode == BINOP_SUBSCRIPT)
-	{
-	  ++*pos;
-	  ++*pos;
-	  struct value *lhs = evaluate_subexp (nullptr, exp, pos, noside);
-	  struct value *rhs = evaluate_subexp (nullptr, exp, pos, noside);
-
-	  result = rust_subscript (expect_type, exp, noside, true, lhs, rhs);
-	  break;
-	}
-      /* Fall through.  */
-    default:
-      result = evaluate_subexp_standard (expect_type, exp, pos, noside);
-      break;
-    }
-
-  return result;
-}
-
 namespace expr
 {
 
@@ -1746,9 +1461,7 @@ rust_aggregate_operation::evaluate (struct type *expect_type,
 	}
     }
 
-  if (noside == EVAL_SKIP)
-    result = value_from_longest (builtin_type (exp->gdbarch)->builtin_int, 1);
-  else if (noside == EVAL_AVOID_SIDE_EFFECTS)
+  if (noside == EVAL_AVOID_SIDE_EFFECTS)
     result = allocate_value (type);
   else
     result = value_at_lazy (type, addr);
@@ -1808,226 +1521,8 @@ rust_structop::evaluate_funcall (struct type *expect_type,
 
 }
 
-/* operator_length implementation for Rust.  */
-
-static void
-rust_operator_length (const struct expression *exp, int pc, int *oplenp,
-		      int *argsp)
-{
-  int oplen = 1;
-  int args = 0;
-
-  switch (exp->elts[pc - 1].opcode)
-    {
-    case OP_AGGREGATE:
-      /* We handle aggregate as a type and argument count.  The first
-	 argument might be OP_OTHERS.  After that the arguments
-	 alternate: first an OP_NAME, then an expression.  */
-      oplen = 4;
-      args = longest_to_int (exp->elts[pc - 2].longconst);
-      break;
-
-    case OP_OTHERS:
-      oplen = 1;
-      args = 1;
-      break;
-
-    case STRUCTOP_ANONYMOUS:
-      oplen = 3;
-      args = 1;
-      break;
-
-    case OP_RUST_ARRAY:
-      oplen = 1;
-      args = 2;
-      break;
-
-    default:
-      operator_length_standard (exp, pc, oplenp, argsp);
-      return;
-    }
-
-  *oplenp = oplen;
-  *argsp = args;
-}
-
-/* dump_subexp_body implementation for Rust.  */
-
-static int
-rust_dump_subexp_body (struct expression *exp, struct ui_file *stream,
-		       int elt)
-{
-  switch (exp->elts[elt].opcode)
-    {
-    case OP_AGGREGATE:
-      {
-	int length = longest_to_int (exp->elts[elt + 2].longconst);
-	int i;
-
-	fprintf_filtered (stream, "Type @");
-	gdb_print_host_address (exp->elts[elt + 1].type, stream);
-	fprintf_filtered (stream, " (");
-	type_print (exp->elts[elt + 1].type, NULL, stream, 0);
-	fprintf_filtered (stream, "), length %d", length);
-
-	elt += 4;
-	for (i = 0; i < length; ++i)
-	  elt = dump_subexp (exp, stream, elt);
-      }
-      break;
-
-    case OP_STRING:
-    case OP_NAME:
-      {
-	LONGEST len = exp->elts[elt + 1].longconst;
-
-	fprintf_filtered (stream, "%s: %s",
-			  (exp->elts[elt].opcode == OP_STRING
-			   ? "string" : "name"),
-			  &exp->elts[elt + 2].string);
-	elt += 4 + BYTES_TO_EXP_ELEM (len + 1);
-      }
-      break;
-
-    case OP_OTHERS:
-      elt = dump_subexp (exp, stream, elt + 1);
-      break;
-
-    case STRUCTOP_ANONYMOUS:
-      {
-	int field_number;
-
-	field_number = longest_to_int (exp->elts[elt + 1].longconst);
-
-	fprintf_filtered (stream, "Field number: %d", field_number);
-	elt = dump_subexp (exp, stream, elt + 3);
-      }
-      break;
-
-    case OP_RUST_ARRAY:
-      ++elt;
-      break;
-
-    default:
-      elt = dump_subexp_body_standard (exp, stream, elt);
-      break;
-    }
-
-  return elt;
-}
-
-/* print_subexp implementation for Rust.  */
-
-static void
-rust_print_subexp (struct expression *exp, int *pos, struct ui_file *stream,
-		   enum precedence prec)
-{
-  switch (exp->elts[*pos].opcode)
-    {
-    case OP_AGGREGATE:
-      {
-	int length = longest_to_int (exp->elts[*pos + 2].longconst);
-	int i;
-
-	type_print (exp->elts[*pos + 1].type, "", stream, 0);
-	fputs_filtered (" { ", stream);
-
-	*pos += 4;
-	for (i = 0; i < length; ++i)
-	  {
-	    rust_print_subexp (exp, pos, stream, prec);
-	    fputs_filtered (", ", stream);
-	  }
-	fputs_filtered (" }", stream);
-      }
-      break;
-
-    case OP_NAME:
-      {
-	LONGEST len = exp->elts[*pos + 1].longconst;
-
-	fputs_filtered (&exp->elts[*pos + 2].string, stream);
-	*pos += 4 + BYTES_TO_EXP_ELEM (len + 1);
-      }
-      break;
-
-    case OP_OTHERS:
-      {
-	fputs_filtered ("<<others>> (", stream);
-	++*pos;
-	rust_print_subexp (exp, pos, stream, prec);
-	fputs_filtered (")", stream);
-      }
-      break;
-
-    case STRUCTOP_ANONYMOUS:
-      {
-	int tem = longest_to_int (exp->elts[*pos + 1].longconst);
-
-	(*pos) += 3;
-	print_subexp (exp, pos, stream, PREC_SUFFIX);
-	fprintf_filtered (stream, ".%d", tem);
-      }
-      break;
-
-    case OP_RUST_ARRAY:
-      ++*pos;
-      fprintf_filtered (stream, "[");
-      rust_print_subexp (exp, pos, stream, prec);
-      fprintf_filtered (stream, "; ");
-      rust_print_subexp (exp, pos, stream, prec);
-      fprintf_filtered (stream, "]");
-      break;
-
-    default:
-      print_subexp_standard (exp, pos, stream, prec);
-      break;
-    }
-}
-
-/* operator_check implementation for Rust.  */
-
-static int
-rust_operator_check (struct expression *exp, int pos,
-		     int (*objfile_func) (struct objfile *objfile,
-					  void *data),
-		     void *data)
-{
-  switch (exp->elts[pos].opcode)
-    {
-    case OP_AGGREGATE:
-      {
-	struct type *type = exp->elts[pos + 1].type;
-	struct objfile *objfile = TYPE_OBJFILE (type);
-
-	if (objfile != NULL && (*objfile_func) (objfile, data))
-	  return 1;
-      }
-      break;
-
-    case OP_OTHERS:
-    case OP_NAME:
-    case OP_RUST_ARRAY:
-      break;
-
-    default:
-      return operator_check_standard (exp, pos, objfile_func, data);
-    }
-
-  return 0;
-}
-
 \f
 
-const struct exp_descriptor rust_language::exp_descriptor_tab =
-{
-  rust_print_subexp,
-  rust_operator_length,
-  rust_operator_check,
-  rust_dump_subexp_body,
-  rust_evaluate_subexp
-};
-
 /* See language.h.  */
 
 void
diff --git a/gdb/rust-lang.h b/gdb/rust-lang.h
index fb27f60eeab..ec97cac3dae 100644
--- a/gdb/rust-lang.h
+++ b/gdb/rust-lang.h
@@ -211,21 +211,11 @@ class rust_language : public language_defn
 
   /* See language.h.  */
 
-  const struct exp_descriptor *expression_ops () const override
-  { return &exp_descriptor_tab; }
-
-  /* See language.h.  */
-
   const struct op_print *opcode_print_table () const override
   { return c_op_print_tab; }
 
 private:
 
-  /* Table of expression handling functions for use by EXPRESSION_OPS
-     member function.  */
-
-  static const struct exp_descriptor exp_descriptor_tab;
-
   /* Helper for value_print_inner, arguments are as for that function.
      Prints structs and untagged unions.  */
 
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 186/203] Remove now-unused Fortran evaluator code
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (184 preceding siblings ...)
  2021-01-01 21:47 ` [PATCH 185/203] Remove now-unused Rust evaluator code Tom Tromey
@ 2021-01-01 21:47 ` Tom Tromey
  2021-01-01 21:47 ` [PATCH 187/203] Remove now-unused Modula-2 " Tom Tromey
                   ` (17 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:47 UTC (permalink / raw)
  To: gdb-patches

Now that the Fortran parser has switched to the new style, there is no
need for the old Fortran evaluation code.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* f-lang.h (class f_language) <expresssion_ops>: Remove.
	<exp_descriptor_tab>: Remove.
	* f-lang.c (fortran_value_subarray, evaluate_subexp_f)
	(operator_length_f, print_unop_subexp_f, print_binop_subexp_f)
	(print_subexp_f, dump_subexp_body_f, operator_check_f)
	(f_language::exp_descriptor_tab): Remove.
---
 gdb/ChangeLog |   9 +
 gdb/f-lang.c  | 735 --------------------------------------------------
 gdb/f-lang.h  |  10 -
 3 files changed, 9 insertions(+), 745 deletions(-)

diff --git a/gdb/f-lang.c b/gdb/f-lang.c
index 207c2ecefd7..e5b66c7fa3b 100644
--- a/gdb/f-lang.c
+++ b/gdb/f-lang.c
@@ -292,417 +292,6 @@ class fortran_array_repacker_impl
   struct value *m_val;
 };
 
-/* Called from evaluate_subexp_standard to perform array indexing, and
-   sub-range extraction, for Fortran.  As well as arrays this function
-   also handles strings as they can be treated like arrays of characters.
-   ARRAY is the array or string being accessed.  EXP, POS, and NOSIDE are
-   as for evaluate_subexp_standard, and NARGS is the number of arguments
-   in this access (e.g. 'array (1,2,3)' would be NARGS 3).  */
-
-static struct value *
-fortran_value_subarray (struct value *array, struct expression *exp,
-			int *pos, int nargs, enum noside noside)
-{
-  type *original_array_type = check_typedef (value_type (array));
-  bool is_string_p = original_array_type->code () == TYPE_CODE_STRING;
-
-  /* Perform checks for ARRAY not being available.  The somewhat overly
-     complex logic here is just to keep backward compatibility with the
-     errors that we used to get before FORTRAN_VALUE_SUBARRAY was
-     rewritten.  Maybe a future task would streamline the error messages we
-     get here, and update all the expected test results.  */
-  if (exp->elts[*pos].opcode != OP_RANGE)
-    {
-      if (type_not_associated (original_array_type))
-	error (_("no such vector element (vector not associated)"));
-      else if (type_not_allocated (original_array_type))
-	error (_("no such vector element (vector not allocated)"));
-    }
-  else
-    {
-      if (type_not_associated (original_array_type))
-	error (_("array not associated"));
-      else if (type_not_allocated (original_array_type))
-	error (_("array not allocated"));
-    }
-
-  /* First check that the number of dimensions in the type we are slicing
-     matches the number of arguments we were passed.  */
-  int ndimensions = calc_f77_array_dims (original_array_type);
-  if (nargs != ndimensions)
-    error (_("Wrong number of subscripts"));
-
-  /* This will be initialised below with the type of the elements held in
-     ARRAY.  */
-  struct type *inner_element_type;
-
-  /* Extract the types of each array dimension from the original array
-     type.  We need these available so we can fill in the default upper and
-     lower bounds if the user requested slice doesn't provide that
-     information.  Additionally unpacking the dimensions like this gives us
-     the inner element type.  */
-  std::vector<struct type *> dim_types;
-  {
-    dim_types.reserve (ndimensions);
-    struct type *type = original_array_type;
-    for (int i = 0; i < ndimensions; ++i)
-      {
-	dim_types.push_back (type);
-	type = TYPE_TARGET_TYPE (type);
-      }
-    /* TYPE is now the inner element type of the array, we start the new
-       array slice off as this type, then as we process the requested slice
-       (from the user) we wrap new types around this to build up the final
-       slice type.  */
-    inner_element_type = type;
-  }
-
-  /* As we analyse the new slice type we need to understand if the data
-     being referenced is contiguous.  Do decide this we must track the size
-     of an element at each dimension of the new slice array.  Initially the
-     elements of the inner most dimension of the array are the same inner
-     most elements as the original ARRAY.  */
-  LONGEST slice_element_size = TYPE_LENGTH (inner_element_type);
-
-  /* Start off assuming all data is contiguous, this will be set to false
-     if access to any dimension results in non-contiguous data.  */
-  bool is_all_contiguous = true;
-
-  /* The TOTAL_OFFSET is the distance in bytes from the start of the
-     original ARRAY to the start of the new slice.  This is calculated as
-     we process the information from the user.  */
-  LONGEST total_offset = 0;
-
-  /* A structure representing information about each dimension of the
-     resulting slice.  */
-  struct slice_dim
-  {
-    /* Constructor.  */
-    slice_dim (LONGEST l, LONGEST h, LONGEST s, struct type *idx)
-      : low (l),
-	high (h),
-	stride (s),
-	index (idx)
-    { /* Nothing.  */ }
-
-    /* The low bound for this dimension of the slice.  */
-    LONGEST low;
-
-    /* The high bound for this dimension of the slice.  */
-    LONGEST high;
-
-    /* The byte stride for this dimension of the slice.  */
-    LONGEST stride;
-
-    struct type *index;
-  };
-
-  /* The dimensions of the resulting slice.  */
-  std::vector<slice_dim> slice_dims;
-
-  /* Process the incoming arguments.   These arguments are in the reverse
-     order to the array dimensions, that is the first argument refers to
-     the last array dimension.  */
-  if (fortran_array_slicing_debug)
-    debug_printf ("Processing array access:\n");
-  for (int i = 0; i < nargs; ++i)
-    {
-      /* For each dimension of the array the user will have either provided
-	 a ranged access with optional lower bound, upper bound, and
-	 stride, or the user will have supplied a single index.  */
-      struct type *dim_type = dim_types[ndimensions - (i + 1)];
-      if (exp->elts[*pos].opcode == OP_RANGE)
-	{
-	  int pc = (*pos) + 1;
-	  enum range_flag range_flag = (enum range_flag) exp->elts[pc].longconst;
-	  *pos += 3;
-
-	  LONGEST low, high, stride;
-	  low = high = stride = 0;
-
-	  if ((range_flag & RANGE_LOW_BOUND_DEFAULT) == 0)
-	    low = value_as_long (evaluate_subexp (nullptr, exp, pos, noside));
-	  else
-	    low = f77_get_lowerbound (dim_type);
-	  if ((range_flag & RANGE_HIGH_BOUND_DEFAULT) == 0)
-	    high = value_as_long (evaluate_subexp (nullptr, exp, pos, noside));
-	  else
-	    high = f77_get_upperbound (dim_type);
-	  if ((range_flag & RANGE_HAS_STRIDE) == RANGE_HAS_STRIDE)
-	    stride = value_as_long (evaluate_subexp (nullptr, exp, pos, noside));
-	  else
-	    stride = 1;
-
-	  if (stride == 0)
-	    error (_("stride must not be 0"));
-
-	  /* Get information about this dimension in the original ARRAY.  */
-	  struct type *target_type = TYPE_TARGET_TYPE (dim_type);
-	  struct type *index_type = dim_type->index_type ();
-	  LONGEST lb = f77_get_lowerbound (dim_type);
-	  LONGEST ub = f77_get_upperbound (dim_type);
-	  LONGEST sd = index_type->bit_stride ();
-	  if (sd == 0)
-	    sd = TYPE_LENGTH (target_type) * 8;
-
-	  if (fortran_array_slicing_debug)
-	    {
-	      debug_printf ("|-> Range access\n");
-	      std::string str = type_to_string (dim_type);
-	      debug_printf ("|   |-> Type: %s\n", str.c_str ());
-	      debug_printf ("|   |-> Array:\n");
-	      debug_printf ("|   |   |-> Low bound: %s\n", plongest (lb));
-	      debug_printf ("|   |   |-> High bound: %s\n", plongest (ub));
-	      debug_printf ("|   |   |-> Bit stride: %s\n", plongest (sd));
-	      debug_printf ("|   |   |-> Byte stride: %s\n", plongest (sd / 8));
-	      debug_printf ("|   |   |-> Type size: %s\n",
-			    pulongest (TYPE_LENGTH (dim_type)));
-	      debug_printf ("|   |   '-> Target type size: %s\n",
-			    pulongest (TYPE_LENGTH (target_type)));
-	      debug_printf ("|   |-> Accessing:\n");
-	      debug_printf ("|   |   |-> Low bound: %s\n",
-			    plongest (low));
-	      debug_printf ("|   |   |-> High bound: %s\n",
-			    plongest (high));
-	      debug_printf ("|   |   '-> Element stride: %s\n",
-			    plongest (stride));
-	    }
-
-	  /* Check the user hasn't asked for something invalid.  */
-	  if (high > ub || low < lb)
-	    error (_("array subscript out of bounds"));
-
-	  /* Calculate what this dimension of the new slice array will look
-	     like.  OFFSET is the byte offset from the start of the
-	     previous (more outer) dimension to the start of this
-	     dimension.  E_COUNT is the number of elements in this
-	     dimension.  REMAINDER is the number of elements remaining
-	     between the last included element and the upper bound.  For
-	     example an access '1:6:2' will include elements 1, 3, 5 and
-	     have a remainder of 1 (element #6).  */
-	  LONGEST lowest = std::min (low, high);
-	  LONGEST offset = (sd / 8) * (lowest - lb);
-	  LONGEST e_count = std::abs (high - low) + 1;
-	  e_count = (e_count + (std::abs (stride) - 1)) / std::abs (stride);
-	  LONGEST new_low = 1;
-	  LONGEST new_high = new_low + e_count - 1;
-	  LONGEST new_stride = (sd * stride) / 8;
-	  LONGEST last_elem = low + ((e_count - 1) * stride);
-	  LONGEST remainder = high - last_elem;
-	  if (low > high)
-	    {
-	      offset += std::abs (remainder) * TYPE_LENGTH (target_type);
-	      if (stride > 0)
-		error (_("incorrect stride and boundary combination"));
-	    }
-	  else if (stride < 0)
-	    error (_("incorrect stride and boundary combination"));
-
-	  /* Is the data within this dimension contiguous?  It is if the
-	     newly computed stride is the same size as a single element of
-	     this dimension.  */
-	  bool is_dim_contiguous = (new_stride == slice_element_size);
-	  is_all_contiguous &= is_dim_contiguous;
-
-	  if (fortran_array_slicing_debug)
-	    {
-	      debug_printf ("|   '-> Results:\n");
-	      debug_printf ("|       |-> Offset = %s\n", plongest (offset));
-	      debug_printf ("|       |-> Elements = %s\n", plongest (e_count));
-	      debug_printf ("|       |-> Low bound = %s\n", plongest (new_low));
-	      debug_printf ("|       |-> High bound = %s\n",
-			    plongest (new_high));
-	      debug_printf ("|       |-> Byte stride = %s\n",
-			    plongest (new_stride));
-	      debug_printf ("|       |-> Last element = %s\n",
-			    plongest (last_elem));
-	      debug_printf ("|       |-> Remainder = %s\n",
-			    plongest (remainder));
-	      debug_printf ("|       '-> Contiguous = %s\n",
-			    (is_dim_contiguous ? "Yes" : "No"));
-	    }
-
-	  /* Figure out how big (in bytes) an element of this dimension of
-	     the new array slice will be.  */
-	  slice_element_size = std::abs (new_stride * e_count);
-
-	  slice_dims.emplace_back (new_low, new_high, new_stride,
-				   index_type);
-
-	  /* Update the total offset.  */
-	  total_offset += offset;
-	}
-      else
-	{
-	  /* There is a single index for this dimension.  */
-	  LONGEST index
-	    = value_as_long (evaluate_subexp_with_coercion (exp, pos, noside));
-
-	  /* Get information about this dimension in the original ARRAY.  */
-	  struct type *target_type = TYPE_TARGET_TYPE (dim_type);
-	  struct type *index_type = dim_type->index_type ();
-	  LONGEST lb = f77_get_lowerbound (dim_type);
-	  LONGEST ub = f77_get_upperbound (dim_type);
-	  LONGEST sd = index_type->bit_stride () / 8;
-	  if (sd == 0)
-	    sd = TYPE_LENGTH (target_type);
-
-	  if (fortran_array_slicing_debug)
-	    {
-	      debug_printf ("|-> Index access\n");
-	      std::string str = type_to_string (dim_type);
-	      debug_printf ("|   |-> Type: %s\n", str.c_str ());
-	      debug_printf ("|   |-> Array:\n");
-	      debug_printf ("|   |   |-> Low bound: %s\n", plongest (lb));
-	      debug_printf ("|   |   |-> High bound: %s\n", plongest (ub));
-	      debug_printf ("|   |   |-> Byte stride: %s\n", plongest (sd));
-	      debug_printf ("|   |   |-> Type size: %s\n",
-			    pulongest (TYPE_LENGTH (dim_type)));
-	      debug_printf ("|   |   '-> Target type size: %s\n",
-			    pulongest (TYPE_LENGTH (target_type)));
-	      debug_printf ("|   '-> Accessing:\n");
-	      debug_printf ("|       '-> Index: %s\n",
-			    plongest (index));
-	    }
-
-	  /* If the array has actual content then check the index is in
-	     bounds.  An array without content (an unbound array) doesn't
-	     have a known upper bound, so don't error check in that
-	     situation.  */
-	  if (index < lb
-	      || (dim_type->index_type ()->bounds ()->high.kind () != PROP_UNDEFINED
-		  && index > ub)
-	      || (VALUE_LVAL (array) != lval_memory
-		  && dim_type->index_type ()->bounds ()->high.kind () == PROP_UNDEFINED))
-	    {
-	      if (type_not_associated (dim_type))
-		error (_("no such vector element (vector not associated)"));
-	      else if (type_not_allocated (dim_type))
-		error (_("no such vector element (vector not allocated)"));
-	      else
-		error (_("no such vector element"));
-	    }
-
-	  /* Calculate using the type stride, not the target type size.  */
-	  LONGEST offset = sd * (index - lb);
-	  total_offset += offset;
-	}
-    }
-
-  if (noside == EVAL_SKIP)
-    return array;
-
-  /* Build a type that represents the new array slice in the target memory
-     of the original ARRAY, this type makes use of strides to correctly
-     find only those elements that are part of the new slice.  */
-  struct type *array_slice_type = inner_element_type;
-  for (const auto &d : slice_dims)
-    {
-      /* Create the range.  */
-      dynamic_prop p_low, p_high, p_stride;
-
-      p_low.set_const_val (d.low);
-      p_high.set_const_val (d.high);
-      p_stride.set_const_val (d.stride);
-
-      struct type *new_range
-	= create_range_type_with_stride ((struct type *) NULL,
-					 TYPE_TARGET_TYPE (d.index),
-					 &p_low, &p_high, 0, &p_stride,
-					 true);
-      array_slice_type
-	= create_array_type (nullptr, array_slice_type, new_range);
-    }
-
-  if (fortran_array_slicing_debug)
-    {
-      debug_printf ("'-> Final result:\n");
-      debug_printf ("    |-> Type: %s\n",
-		    type_to_string (array_slice_type).c_str ());
-      debug_printf ("    |-> Total offset: %s\n",
-		    plongest (total_offset));
-      debug_printf ("    |-> Base address: %s\n",
-		    core_addr_to_string (value_address (array)));
-      debug_printf ("    '-> Contiguous = %s\n",
-		    (is_all_contiguous ? "Yes" : "No"));
-    }
-
-  /* Should we repack this array slice?  */
-  if (!is_all_contiguous && (repack_array_slices || is_string_p))
-    {
-      /* Build a type for the repacked slice.  */
-      struct type *repacked_array_type = inner_element_type;
-      for (const auto &d : slice_dims)
-	{
-	  /* Create the range.  */
-	  dynamic_prop p_low, p_high, p_stride;
-
-	  p_low.set_const_val (d.low);
-	  p_high.set_const_val (d.high);
-	  p_stride.set_const_val (TYPE_LENGTH (repacked_array_type));
-
-	  struct type *new_range
-	    = create_range_type_with_stride ((struct type *) NULL,
-					     TYPE_TARGET_TYPE (d.index),
-					     &p_low, &p_high, 0, &p_stride,
-					     true);
-	  repacked_array_type
-	    = create_array_type (nullptr, repacked_array_type, new_range);
-	}
-
-      /* Now copy the elements from the original ARRAY into the packed
-	 array value DEST.  */
-      struct value *dest = allocate_value (repacked_array_type);
-      if (value_lazy (array)
-	  || (total_offset + TYPE_LENGTH (array_slice_type)
-	      > TYPE_LENGTH (check_typedef (value_type (array)))))
-	{
-	  fortran_array_walker<fortran_lazy_array_repacker_impl> p
-	    (array_slice_type, value_address (array) + total_offset, dest);
-	  p.walk ();
-	}
-      else
-	{
-	  fortran_array_walker<fortran_array_repacker_impl> p
-	    (array_slice_type, value_address (array) + total_offset,
-	     total_offset, array, dest);
-	  p.walk ();
-	}
-      array = dest;
-    }
-  else
-    {
-      if (VALUE_LVAL (array) == lval_memory)
-	{
-	  /* If the value we're taking a slice from is not yet loaded, or
-	     the requested slice is outside the values content range then
-	     just create a new lazy value pointing at the memory where the
-	     contents we're looking for exist.  */
-	  if (value_lazy (array)
-	      || (total_offset + TYPE_LENGTH (array_slice_type)
-		  > TYPE_LENGTH (check_typedef (value_type (array)))))
-	    array = value_at_lazy (array_slice_type,
-				   value_address (array) + total_offset);
-	  else
-	    array = value_from_contents_and_address (array_slice_type,
-						     (value_contents (array)
-						      + total_offset),
-						     (value_address (array)
-						      + total_offset));
-	}
-      else if (!value_lazy (array))
-	{
-	  const void *valaddr = value_contents (array) + total_offset;
-	  array = allocate_value (array_slice_type);
-	  memcpy (value_contents_raw (array), valaddr, TYPE_LENGTH (array_slice_type));
-	}
-      else
-	error (_("cannot subscript arrays that are not in memory"));
-    }
-
-  return array;
-}
-
 /* A helper function for UNOP_ABS.  */
 
 struct value *
@@ -894,145 +483,6 @@ eval_op_f_kind (struct type *expect_type, struct expression *exp,
 			     TYPE_LENGTH (TYPE_TARGET_TYPE (type)));
 }
 
-/* Special expression evaluation cases for Fortran.  */
-
-static struct value *
-evaluate_subexp_f (struct type *expect_type, struct expression *exp,
-		   int *pos, enum noside noside)
-{
-  struct value *arg1 = NULL, *arg2 = NULL;
-  enum exp_opcode op;
-  int pc;
-  struct type *type;
-
-  pc = *pos;
-  *pos += 1;
-  op = exp->elts[pc].opcode;
-
-  switch (op)
-    {
-    default:
-      *pos -= 1;
-      return evaluate_subexp_standard (expect_type, exp, pos, noside);
-
-    case UNOP_ABS:
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      return eval_op_f_abs (expect_type, exp, noside, op, arg1);
-
-    case BINOP_MOD:
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      arg2 = evaluate_subexp (value_type (arg1), exp, pos, noside);
-      return eval_op_f_mod (expect_type, exp, noside, op, arg1, arg2);
-
-    case UNOP_FORTRAN_CEILING:
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      return eval_op_f_ceil (expect_type, exp, noside, op, arg1);
-
-    case UNOP_FORTRAN_FLOOR:
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      return eval_op_f_floor (expect_type, exp, noside, op, arg1);
-
-    case BINOP_FORTRAN_MODULO:
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      arg2 = evaluate_subexp (value_type (arg1), exp, pos, noside);
-      return eval_op_f_modulo (expect_type, exp, noside, op, arg1, arg2);
-
-    case BINOP_FORTRAN_CMPLX:
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      arg2 = evaluate_subexp (value_type (arg1), exp, pos, noside);
-      return eval_op_f_cmplx (expect_type, exp, noside, op, arg1, arg2);
-
-    case UNOP_FORTRAN_KIND:
-      arg1 = evaluate_subexp (NULL, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
-      return eval_op_f_kind (expect_type, exp, noside, op, arg1);
-
-    case OP_F77_UNDETERMINED_ARGLIST:
-      /* Remember that in F77, functions, substring ops and array subscript
-	 operations cannot be disambiguated at parse time.  We have made
-	 all array subscript operations, substring operations as well as
-	 function calls come here and we now have to discover what the heck
-	 this thing actually was.  If it is a function, we process just as
-	 if we got an OP_FUNCALL.  */
-      int nargs = longest_to_int (exp->elts[pc + 1].longconst);
-      (*pos) += 2;
-
-      /* First determine the type code we are dealing with.  */
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      type = check_typedef (value_type (arg1));
-      enum type_code code = type->code ();
-
-      if (code == TYPE_CODE_PTR)
-	{
-	  /* Fortran always passes variable to subroutines as pointer.
-	     So we need to look into its target type to see if it is
-	     array, string or function.  If it is, we need to switch
-	     to the target value the original one points to.  */
-	  struct type *target_type = check_typedef (TYPE_TARGET_TYPE (type));
-
-	  if (target_type->code () == TYPE_CODE_ARRAY
-	      || target_type->code () == TYPE_CODE_STRING
-	      || target_type->code () == TYPE_CODE_FUNC)
-	    {
-	      arg1 = value_ind (arg1);
-	      type = check_typedef (value_type (arg1));
-	      code = type->code ();
-	    }
-	}
-
-      switch (code)
-	{
-	case TYPE_CODE_ARRAY:
-	case TYPE_CODE_STRING:
-	  return fortran_value_subarray (arg1, exp, pos, nargs, noside);
-
-	case TYPE_CODE_PTR:
-	case TYPE_CODE_FUNC:
-	case TYPE_CODE_INTERNAL_FUNCTION:
-	  {
-	    /* It's a function call.  Allocate arg vector, including
-	    space for the function to be called in argvec[0] and a
-	    termination NULL.  */
-	    struct value **argvec = (struct value **)
-	      alloca (sizeof (struct value *) * (nargs + 2));
-	    argvec[0] = arg1;
-	    int tem = 1;
-	    for (; tem <= nargs; tem++)
-	      {
-		argvec[tem] = evaluate_subexp_with_coercion (exp, pos, noside);
-		/* Arguments in Fortran are passed by address.  Coerce the
-		   arguments here rather than in value_arg_coerce as
-		   otherwise the call to malloc to place the non-lvalue
-		   parameters in target memory is hit by this Fortran
-		   specific logic.  This results in malloc being called
-		   with a pointer to an integer followed by an attempt to
-		   malloc the arguments to malloc in target memory.
-		   Infinite recursion ensues.  */
-		if (code == TYPE_CODE_PTR || code == TYPE_CODE_FUNC)
-		  {
-		    bool is_artificial
-		      = TYPE_FIELD_ARTIFICIAL (value_type (arg1), tem - 1);
-		    argvec[tem] = fortran_argument_convert (argvec[tem],
-							    is_artificial);
-		  }
-	      }
-	    argvec[tem] = 0;	/* signal end of arglist */
-	    if (noside == EVAL_SKIP)
-	      return eval_skip_value (exp);
-	    return evaluate_subexp_do_call (exp, noside, argvec[0],
-					    gdb::make_array_view (argvec + 1,
-								  nargs),
-					    NULL, expect_type);
-	  }
-
-	default:
-	  error (_("Cannot perform substring on this type"));
-	}
-    }
-
-  /* Should be unreachable.  */
-  return nullptr;
-}
-
 namespace expr
 {
 
@@ -1519,191 +969,6 @@ fortran_undetermined::evaluate (struct type *expect_type,
 
 } /* namespace expr */
 
-/* Special expression lengths for Fortran.  */
-
-static void
-operator_length_f (const struct expression *exp, int pc, int *oplenp,
-		   int *argsp)
-{
-  int oplen = 1;
-  int args = 0;
-
-  switch (exp->elts[pc - 1].opcode)
-    {
-    default:
-      operator_length_standard (exp, pc, oplenp, argsp);
-      return;
-
-    case UNOP_FORTRAN_KIND:
-    case UNOP_FORTRAN_FLOOR:
-    case UNOP_FORTRAN_CEILING:
-      oplen = 1;
-      args = 1;
-      break;
-
-    case BINOP_FORTRAN_CMPLX:
-    case BINOP_FORTRAN_MODULO:
-      oplen = 1;
-      args = 2;
-      break;
-
-    case OP_F77_UNDETERMINED_ARGLIST:
-      oplen = 3;
-      args = 1 + longest_to_int (exp->elts[pc - 2].longconst);
-      break;
-    }
-
-  *oplenp = oplen;
-  *argsp = args;
-}
-
-/* Helper for PRINT_SUBEXP_F.  Arguments are as for PRINT_SUBEXP_F, except
-   the extra argument NAME which is the text that should be printed as the
-   name of this operation.  */
-
-static void
-print_unop_subexp_f (struct expression *exp, int *pos,
-		     struct ui_file *stream, enum precedence prec,
-		     const char *name)
-{
-  (*pos)++;
-  fprintf_filtered (stream, "%s(", name);
-  print_subexp (exp, pos, stream, PREC_SUFFIX);
-  fputs_filtered (")", stream);
-}
-
-/* Helper for PRINT_SUBEXP_F.  Arguments are as for PRINT_SUBEXP_F, except
-   the extra argument NAME which is the text that should be printed as the
-   name of this operation.  */
-
-static void
-print_binop_subexp_f (struct expression *exp, int *pos,
-		      struct ui_file *stream, enum precedence prec,
-		      const char *name)
-{
-  (*pos)++;
-  fprintf_filtered (stream, "%s(", name);
-  print_subexp (exp, pos, stream, PREC_SUFFIX);
-  fputs_filtered (",", stream);
-  print_subexp (exp, pos, stream, PREC_SUFFIX);
-  fputs_filtered (")", stream);
-}
-
-/* Special expression printing for Fortran.  */
-
-static void
-print_subexp_f (struct expression *exp, int *pos,
-		struct ui_file *stream, enum precedence prec)
-{
-  int pc = *pos;
-  enum exp_opcode op = exp->elts[pc].opcode;
-
-  switch (op)
-    {
-    default:
-      print_subexp_standard (exp, pos, stream, prec);
-      return;
-
-    case UNOP_FORTRAN_KIND:
-      print_unop_subexp_f (exp, pos, stream, prec, "KIND");
-      return;
-
-    case UNOP_FORTRAN_FLOOR:
-      print_unop_subexp_f (exp, pos, stream, prec, "FLOOR");
-      return;
-
-    case UNOP_FORTRAN_CEILING:
-      print_unop_subexp_f (exp, pos, stream, prec, "CEILING");
-      return;
-
-    case BINOP_FORTRAN_CMPLX:
-      print_binop_subexp_f (exp, pos, stream, prec, "CMPLX");
-      return;
-
-    case BINOP_FORTRAN_MODULO:
-      print_binop_subexp_f (exp, pos, stream, prec, "MODULO");
-      return;
-
-    case OP_F77_UNDETERMINED_ARGLIST:
-      (*pos)++;
-      print_subexp_funcall (exp, pos, stream);
-      return;
-    }
-}
-
-/* Special expression dumping for Fortran.  */
-
-static int
-dump_subexp_body_f (struct expression *exp,
-		    struct ui_file *stream, int elt)
-{
-  int opcode = exp->elts[elt].opcode;
-  int oplen, nargs, i;
-
-  switch (opcode)
-    {
-    default:
-      return dump_subexp_body_standard (exp, stream, elt);
-
-    case UNOP_FORTRAN_KIND:
-    case UNOP_FORTRAN_FLOOR:
-    case UNOP_FORTRAN_CEILING:
-    case BINOP_FORTRAN_CMPLX:
-    case BINOP_FORTRAN_MODULO:
-      operator_length_f (exp, (elt + 1), &oplen, &nargs);
-      break;
-
-    case OP_F77_UNDETERMINED_ARGLIST:
-      return dump_subexp_body_funcall (exp, stream, elt + 1);
-    }
-
-  elt += oplen;
-  for (i = 0; i < nargs; i += 1)
-    elt = dump_subexp (exp, stream, elt);
-
-  return elt;
-}
-
-/* Special expression checking for Fortran.  */
-
-static int
-operator_check_f (struct expression *exp, int pos,
-		  int (*objfile_func) (struct objfile *objfile,
-				       void *data),
-		  void *data)
-{
-  const union exp_element *const elts = exp->elts;
-
-  switch (elts[pos].opcode)
-    {
-    case UNOP_FORTRAN_KIND:
-    case UNOP_FORTRAN_FLOOR:
-    case UNOP_FORTRAN_CEILING:
-    case BINOP_FORTRAN_CMPLX:
-    case BINOP_FORTRAN_MODULO:
-      /* Any references to objfiles are held in the arguments to this
-	 expression, not within the expression itself, so no additional
-	 checking is required here, the outer expression iteration code
-	 will take care of checking each argument.  */
-      break;
-
-    default:
-      return operator_check_standard (exp, pos, objfile_func, data);
-    }
-
-  return 0;
-}
-
-/* Expression processing for Fortran.  */
-const struct exp_descriptor f_language::exp_descriptor_tab =
-{
-  print_subexp_f,
-  operator_length_f,
-  operator_check_f,
-  dump_subexp_body_f,
-  evaluate_subexp_f
-};
-
 /* See language.h.  */
 
 void
diff --git a/gdb/f-lang.h b/gdb/f-lang.h
index 9174d8df899..03b59102139 100644
--- a/gdb/f-lang.h
+++ b/gdb/f-lang.h
@@ -220,11 +220,6 @@ class f_language : public language_defn
 
   /* See language.h.  */
 
-  const struct exp_descriptor *expression_ops () const override
-  { return &exp_descriptor_tab; }
-
-  /* See language.h.  */
-
   const struct op_print *opcode_print_table () const override
   { return op_print_tab; }
 
@@ -236,11 +231,6 @@ class f_language : public language_defn
 	(const lookup_name_info &lookup_name) const override;
 
 private:
-  /* Table of expression handling functions for use by EXPRESSION_OPS
-     member function.  */
-
-  static const struct exp_descriptor exp_descriptor_tab;
-
   /* Table of opcode data for use by OPCODE_PRINT_TABLE member function.  */
 
   static const struct op_print op_print_tab[];
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 187/203] Remove now-unused Modula-2 evaluator code
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (185 preceding siblings ...)
  2021-01-01 21:47 ` [PATCH 186/203] Remove now-unused Fortran " Tom Tromey
@ 2021-01-01 21:47 ` Tom Tromey
  2021-01-01 21:47 ` [PATCH 188/203] Remove now-unused Ada " Tom Tromey
                   ` (16 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:47 UTC (permalink / raw)
  To: gdb-patches

Now that the Modula-2 parser has switched to the new style, there is
no need for the old Modula-2 evaluation code.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* m2-lang.h (class m2_language) <expresssion_ops,
	exp_descriptor_modula2>: Remove.
	* m2-lang.c (evaluate_subexp_modula2)
	(m2_language::exp_descriptor_modula2): Remove.
---
 gdb/ChangeLog |  7 +++++++
 gdb/m2-lang.c | 34 ----------------------------------
 gdb/m2-lang.h |  9 ---------
 3 files changed, 7 insertions(+), 43 deletions(-)

diff --git a/gdb/m2-lang.c b/gdb/m2-lang.c
index 60d373ec2b9..281fa8b9218 100644
--- a/gdb/m2-lang.c
+++ b/gdb/m2-lang.c
@@ -111,31 +111,6 @@ eval_op_m2_subscript (struct type *expect_type, struct expression *exp,
     return value_subscript (arg1, value_as_long (arg2));
 }
 
-static struct value *
-evaluate_subexp_modula2 (struct type *expect_type, struct expression *exp,
-			 int *pos, enum noside noside)
-{
-  enum exp_opcode op = exp->elts[*pos].opcode;
-  struct value *arg1;
-  struct value *arg2;
-
-  switch (op)
-    {
-    case UNOP_HIGH:
-      (*pos)++;
-      arg1 = evaluate_subexp_with_coercion (exp, pos, noside);
-      return eval_op_m2_high (expect_type, exp, noside, arg1);
-
-    case BINOP_SUBSCRIPT:
-      (*pos)++;
-      arg1 = evaluate_subexp_with_coercion (exp, pos, noside);
-      arg2 = evaluate_subexp_with_coercion (exp, pos, noside);
-      return eval_op_m2_subscript (expect_type, exp, noside, arg1, arg2);
-
-    default:
-      return evaluate_subexp_standard (expect_type, exp, pos, noside);
-    }
-}
 \f
 
 /* Table of operators and their precedences for printing expressions.  */
@@ -175,15 +150,6 @@ const struct op_print m2_language::op_print_tab[] =
 };
 \f
 
-const struct exp_descriptor m2_language::exp_descriptor_modula2 =
-{
-  print_subexp_standard,
-  operator_length_standard,
-  operator_check_standard,
-  dump_subexp_body_standard,
-  evaluate_subexp_modula2
-};
-
 /* Single instance of the M2 language.  */
 
 static m2_language m2_language_defn;
diff --git a/gdb/m2-lang.h b/gdb/m2-lang.h
index 650942b67b7..20941429ff0 100644
--- a/gdb/m2-lang.h
+++ b/gdb/m2-lang.h
@@ -150,19 +150,10 @@ class m2_language : public language_defn
 
   /* See language.h.  */
 
-  const struct exp_descriptor *expression_ops () const override
-  { return &exp_descriptor_modula2; }
-
-  /* See language.h.  */
-
   const struct op_print *opcode_print_table () const override
   { return op_print_tab; }
 
 private:
-  /* Table of expression handling functions for use by EXPRESSION_OPS
-     member function.  */
-  static const struct exp_descriptor exp_descriptor_modula2;
-
   /* Table of opcode data for use by OPCODE_PRINT_TABLE member function.  */
   static const struct op_print op_print_tab[];
 };
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 188/203] Remove now-unused Ada evaluator code
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (186 preceding siblings ...)
  2021-01-01 21:47 ` [PATCH 187/203] Remove now-unused Modula-2 " Tom Tromey
@ 2021-01-01 21:47 ` Tom Tromey
  2021-01-01 21:47 ` [PATCH 189/203] Remove now-unused C " Tom Tromey
                   ` (15 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:47 UTC (permalink / raw)
  To: gdb-patches

Now that the Ada parser has switched to the new style, there is no
need for the old Ada evaluation code.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* ada-lang.c (resolve_subexp, replace_operator_with_call)
	(evaluate_subexp_type, assign_aggregate)
	(aggregate_assign_positional, aggregate_assign_from_choices)
	(aggregate_assign_others, ada_evaluate_subexp_for_cast)
	(ada_evaluate_subexp, ADA_OPERATORS, ada_operator_length)
	(ada_operator_check, ada_forward_operator_length)
	(ada_dump_subexp_body, ada_print_subexp, ada_exp_descriptor):
	Remove.
	(post_parser): Update.
	(class ada_language) <expresssion_ops>: Remove.
---
 gdb/ChangeLog  |   13 +
 gdb/ada-lang.c | 2060 ++++--------------------------------------------
 2 files changed, 174 insertions(+), 1899 deletions(-)

diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 657ef37dca7..c7d9540798d 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -119,13 +119,6 @@ static int num_defns_collected (struct obstack *);
 
 static struct block_symbol *defns_collected (struct obstack *, int);
 
-static struct value *resolve_subexp (expression_up *, int *, int,
-				     struct type *, int,
-				     innermost_block_tracker *);
-
-static void replace_operator_with_call (expression_up *, int, int, int,
-					struct symbol *, const struct block *);
-
 static int possible_user_operator_p (enum exp_opcode, struct value **);
 
 static const char *ada_decoded_op_name (enum exp_opcode);
@@ -141,8 +134,6 @@ static int discrete_type_p (struct type *);
 static struct type *ada_lookup_struct_elt_type (struct type *, const char *,
 						int, int);
 
-static struct value *evaluate_subexp_type (struct expression *, int *);
-
 static struct type *ada_find_parallel_type_with_name (struct type *,
 						      const char *);
 
@@ -211,36 +202,9 @@ static int ada_is_direct_array_type (struct type *);
 static struct value *ada_index_struct_field (int, struct value *, int,
 					     struct type *);
 
-static struct value *assign_aggregate (struct value *, struct value *, 
-				       struct expression *,
-				       int *, enum noside);
-
-static void aggregate_assign_from_choices (struct value *, struct value *,
-					   struct expression *,
-					   int *, std::vector<LONGEST> &,
-					   LONGEST, LONGEST);
-
-static void aggregate_assign_positional (struct value *, struct value *,
-					 struct expression *,
-					 int *, std::vector<LONGEST> &,
-					 LONGEST, LONGEST);
-
-
-static void aggregate_assign_others (struct value *, struct value *,
-				     struct expression *,
-				     int *, std::vector<LONGEST> &,
-				     LONGEST, LONGEST);
-
-
 static void add_component_interval (LONGEST, LONGEST, std::vector<LONGEST> &);
 
 
-static struct value *ada_evaluate_subexp (struct type *, struct expression *,
-					  int *, enum noside);
-
-static void ada_forward_operator_length (struct expression *, int, int *,
-					 int *);
-
 static struct type *ada_find_any_type (const char *name);
 
 static symbol_name_matcher_ftype *ada_get_symbol_name_matcher
@@ -3576,277 +3540,6 @@ ada_resolve_variable (struct symbol *sym, const struct block *block,
   return candidates[i];
 }
 
-/* Resolve the operator of the subexpression beginning at
-   position *POS of *EXPP.  "Resolving" consists of replacing
-   the symbols that have undefined namespaces in OP_VAR_VALUE nodes
-   with their resolutions, replacing built-in operators with
-   function calls to user-defined operators, where appropriate, and,
-   when DEPROCEDURE_P is non-zero, converting function-valued variables
-   into parameterless calls.  May expand *EXPP.  The CONTEXT_TYPE functions
-   are as in ada_resolve, above.  */
-
-static struct value *
-resolve_subexp (expression_up *expp, int *pos, int deprocedure_p,
-		struct type *context_type, int parse_completion,
-		innermost_block_tracker *tracker)
-{
-  int pc = *pos;
-  int i;
-  struct expression *exp;       /* Convenience: == *expp.  */
-  enum exp_opcode op = (*expp)->elts[pc].opcode;
-  struct value **argvec;        /* Vector of operand types (alloca'ed).  */
-  int nargs;                    /* Number of operands.  */
-  int oplen;
-
-  argvec = NULL;
-  nargs = 0;
-  exp = expp->get ();
-
-  /* Pass one: resolve operands, saving their types and updating *pos,
-     if needed.  */
-  switch (op)
-    {
-    case OP_FUNCALL:
-      if (exp->elts[pc + 3].opcode == OP_VAR_VALUE
-	  && SYMBOL_DOMAIN (exp->elts[pc + 5].symbol) == UNDEF_DOMAIN)
-	*pos += 7;
-      else
-	{
-	  *pos += 3;
-	  resolve_subexp (expp, pos, 0, NULL, parse_completion, tracker);
-	}
-      nargs = longest_to_int (exp->elts[pc + 1].longconst);
-      break;
-
-    case UNOP_ADDR:
-      *pos += 1;
-      resolve_subexp (expp, pos, 0, NULL, parse_completion, tracker);
-      break;
-
-    case UNOP_QUAL:
-      *pos += 3;
-      resolve_subexp (expp, pos, 1, check_typedef (exp->elts[pc + 1].type),
-		      parse_completion, tracker);
-      break;
-
-    case OP_ATR_MODULUS:
-    case OP_ATR_SIZE:
-    case OP_ATR_TAG:
-    case OP_ATR_FIRST:
-    case OP_ATR_LAST:
-    case OP_ATR_LENGTH:
-    case OP_ATR_POS:
-    case OP_ATR_VAL:
-    case OP_ATR_MIN:
-    case OP_ATR_MAX:
-    case TERNOP_IN_RANGE:
-    case BINOP_IN_BOUNDS:
-    case UNOP_IN_RANGE:
-    case OP_AGGREGATE:
-    case OP_OTHERS:
-    case OP_CHOICES:
-    case OP_POSITIONAL:
-    case OP_DISCRETE_RANGE:
-    case OP_NAME:
-      ada_forward_operator_length (exp, pc, &oplen, &nargs);
-      *pos += oplen;
-      break;
-
-    case BINOP_ASSIGN:
-      {
-	struct value *arg1;
-
-	*pos += 1;
-	arg1 = resolve_subexp (expp, pos, 0, NULL, parse_completion, tracker);
-	if (arg1 == NULL)
-	  resolve_subexp (expp, pos, 1, NULL, parse_completion, tracker);
-	else
-	  resolve_subexp (expp, pos, 1, value_type (arg1), parse_completion,
-			  tracker);
-	break;
-      }
-
-    case UNOP_CAST:
-      *pos += 3;
-      nargs = 1;
-      break;
-
-    case BINOP_ADD:
-    case BINOP_SUB:
-    case BINOP_MUL:
-    case BINOP_DIV:
-    case BINOP_REM:
-    case BINOP_MOD:
-    case BINOP_EXP:
-    case BINOP_CONCAT:
-    case BINOP_LOGICAL_AND:
-    case BINOP_LOGICAL_OR:
-    case BINOP_BITWISE_AND:
-    case BINOP_BITWISE_IOR:
-    case BINOP_BITWISE_XOR:
-
-    case BINOP_EQUAL:
-    case BINOP_NOTEQUAL:
-    case BINOP_LESS:
-    case BINOP_GTR:
-    case BINOP_LEQ:
-    case BINOP_GEQ:
-
-    case BINOP_REPEAT:
-    case BINOP_SUBSCRIPT:
-    case BINOP_COMMA:
-      *pos += 1;
-      nargs = 2;
-      break;
-
-    case UNOP_NEG:
-    case UNOP_PLUS:
-    case UNOP_LOGICAL_NOT:
-    case UNOP_ABS:
-    case UNOP_IND:
-      *pos += 1;
-      nargs = 1;
-      break;
-
-    case OP_LONG:
-    case OP_FLOAT:
-    case OP_VAR_VALUE:
-    case OP_VAR_MSYM_VALUE:
-      *pos += 4;
-      break;
-
-    case OP_TYPE:
-    case OP_BOOL:
-    case OP_LAST:
-    case OP_INTERNALVAR:
-      *pos += 3;
-      break;
-
-    case UNOP_MEMVAL:
-      *pos += 3;
-      nargs = 1;
-      break;
-
-    case OP_REGISTER:
-      *pos += 4 + BYTES_TO_EXP_ELEM (exp->elts[pc + 1].longconst + 1);
-      break;
-
-    case STRUCTOP_STRUCT:
-      *pos += 4 + BYTES_TO_EXP_ELEM (exp->elts[pc + 1].longconst + 1);
-      nargs = 1;
-      break;
-
-    case TERNOP_SLICE:
-      *pos += 1;
-      nargs = 3;
-      break;
-
-    case OP_STRING:
-      break;
-
-    default:
-      error (_("Unexpected operator during name resolution"));
-    }
-
-  argvec = XALLOCAVEC (struct value *, nargs + 1);
-  for (i = 0; i < nargs; i += 1)
-    argvec[i] = resolve_subexp (expp, pos, 1, NULL, parse_completion,
-				tracker);
-  argvec[i] = NULL;
-  exp = expp->get ();
-
-  /* Pass two: perform any resolution on principal operator.  */
-  switch (op)
-    {
-    default:
-      break;
-
-    case OP_VAR_VALUE:
-      if (SYMBOL_DOMAIN (exp->elts[pc + 2].symbol) == UNDEF_DOMAIN)
-	{
-	  block_symbol resolved
-	    = ada_resolve_variable (exp->elts[pc + 2].symbol,
-				    exp->elts[pc + 1].block,
-				    context_type, parse_completion,
-				    deprocedure_p, tracker);
-	  exp->elts[pc + 1].block = resolved.block;
-	  exp->elts[pc + 2].symbol = resolved.symbol;
-	}
-
-      if (deprocedure_p
-	  && (SYMBOL_TYPE (exp->elts[pc + 2].symbol)->code ()
-	      == TYPE_CODE_FUNC))
-	{
-	  replace_operator_with_call (expp, pc, 0, 4,
-				      exp->elts[pc + 2].symbol,
-				      exp->elts[pc + 1].block);
-	  exp = expp->get ();
-	}
-      break;
-
-    case OP_FUNCALL:
-      {
-	if (exp->elts[pc + 3].opcode == OP_VAR_VALUE
-	    && SYMBOL_DOMAIN (exp->elts[pc + 5].symbol) == UNDEF_DOMAIN)
-	  {
-	    block_symbol resolved
-	      = ada_resolve_funcall (exp->elts[pc + 5].symbol,
-				     exp->elts[pc + 4].block,
-				     context_type, parse_completion,
-				     nargs, argvec,
-				     tracker);
-	    exp->elts[pc + 4].block = resolved.block;
-	    exp->elts[pc + 5].symbol = resolved.symbol;
-	  }
-      }
-      break;
-    case BINOP_ADD:
-    case BINOP_SUB:
-    case BINOP_MUL:
-    case BINOP_DIV:
-    case BINOP_REM:
-    case BINOP_MOD:
-    case BINOP_CONCAT:
-    case BINOP_BITWISE_AND:
-    case BINOP_BITWISE_IOR:
-    case BINOP_BITWISE_XOR:
-    case BINOP_EQUAL:
-    case BINOP_NOTEQUAL:
-    case BINOP_LESS:
-    case BINOP_GTR:
-    case BINOP_LEQ:
-    case BINOP_GEQ:
-    case BINOP_EXP:
-    case UNOP_NEG:
-    case UNOP_PLUS:
-    case UNOP_LOGICAL_NOT:
-    case UNOP_ABS:
-      {
-	block_symbol found = ada_find_operator_symbol (op, parse_completion,
-						       nargs, argvec);
-	if (found.symbol == nullptr)
-	  break;
-
-	replace_operator_with_call (expp, pc, nargs, 1,
-				    found.symbol, found.block);
-	exp = expp->get ();
-      }
-      break;
-
-    case OP_TYPE:
-    case OP_REGISTER:
-      return NULL;
-    }
-
-  *pos = pc;
-  if (exp->elts[pc].opcode == OP_VAR_MSYM_VALUE)
-    return evaluate_var_msym_value (EVAL_AVOID_SIDE_EFFECTS,
-				    exp->elts[pc + 1].objfile,
-				    exp->elts[pc + 2].msymbol);
-  else
-    return evaluate_subexp_type (exp, pos);
-}
-
 /* Return non-zero if formal type FTYPE matches actual type ATYPE.  If
    MAY_DEREF is non-zero, the formal may be a pointer and the actual
    a non-pointer.  */
@@ -4029,38 +3722,6 @@ ada_resolve_function (struct block_symbol syms[],
   return 0;
 }
 
-/* Replace the operator of length OPLEN at position PC in *EXPP with a call
-   on the function identified by SYM and BLOCK, and taking NARGS
-   arguments.  Update *EXPP as needed to hold more space.  */
-
-static void
-replace_operator_with_call (expression_up *expp, int pc, int nargs,
-			    int oplen, struct symbol *sym,
-			    const struct block *block)
-{
-  /* We want to add 6 more elements (3 for funcall, 4 for function
-     symbol, -OPLEN for operator being replaced) to the
-     expression.  */
-  struct expression *exp = expp->get ();
-  int save_nelts = exp->nelts;
-  int extra_elts = 7 - oplen;
-  exp->nelts += extra_elts;
-
-  if (extra_elts > 0)
-    exp->resize (exp->nelts);
-  memmove (exp->elts + pc + 7, exp->elts + pc + oplen,
-	   EXP_ELEM_TO_BYTES (save_nelts - pc - oplen));
-  if (extra_elts < 0)
-    exp->resize (exp->nelts);
-
-  exp->elts[pc].opcode = exp->elts[pc + 2].opcode = OP_FUNCALL;
-  exp->elts[pc + 1].longconst = (LONGEST) nargs;
-
-  exp->elts[pc + 3].opcode = exp->elts[pc + 6].opcode = OP_VAR_VALUE;
-  exp->elts[pc + 4].block = block;
-  exp->elts[pc + 5].symbol = sym;
-}
-
 /* Type-class predicates */
 
 /* True iff TYPE is numeric (i.e., an INT, RANGE (of numeric type),
@@ -9237,16 +8898,6 @@ ada_enum_name (const char *name)
     }
 }
 
-/* Evaluate the subexpression of EXP starting at *POS as for
-   evaluate_type, updating *POS to point just past the evaluated
-   expression.  */
-
-static struct value *
-evaluate_subexp_type (struct expression *exp, int *pos)
-{
-  return evaluate_subexp (nullptr, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
-}
-
 /* If VAL is wrapped in an aligner or subtype wrapper, return the
    value it wraps.  */
 
@@ -9525,17 +9176,27 @@ ada_value_equal (struct value *arg1, struct value *arg2)
   return value_equal (arg1, arg2);
 }
 
-/* Assign the result of evaluating EXP starting at *POS to the INDEXth 
-   component of LHS (a simple array or a record), updating *POS past
-   the expression, assuming that LHS is contained in CONTAINER.  Does
-   not modify the inferior's memory, nor does it modify LHS (unless
-   LHS == CONTAINER).  */
+namespace expr
+{
+
+bool
+check_objfile (const std::unique_ptr<ada_component> &comp,
+	       struct objfile *objfile)
+{
+  return comp->uses_objfile (objfile);
+}
+
+/* Assign the result of evaluating ARG starting at *POS to the INDEXth
+   component of LHS (a simple array or a record).  Does not modify the
+   inferior's memory, nor does it modify LHS (unless LHS ==
+   CONTAINER).  */
 
 static void
 assign_component (struct value *container, struct value *lhs, LONGEST index,
-		  struct expression *exp, int *pos)
+		  struct expression *exp, operation_up &arg)
 {
-  struct value *mark = value_mark ();
+  scoped_value_mark mark;
+
   struct value *elt;
   struct type *lhs_type = check_typedef (value_type (lhs));
 
@@ -9552,41 +9213,56 @@ assign_component (struct value *container, struct value *lhs, LONGEST index,
       elt = ada_to_fixed_value (elt);
     }
 
-  if (exp->elts[*pos].opcode == OP_AGGREGATE)
-    assign_aggregate (container, elt, exp, pos, EVAL_NORMAL);
+  ada_aggregate_operation *ag_op
+    = dynamic_cast<ada_aggregate_operation *> (arg.get ());
+  if (ag_op != nullptr)
+    ag_op->assign_aggregate (container, elt, exp);
   else
-    value_assign_to_component (container, elt, 
-			       ada_evaluate_subexp (NULL, exp, pos, 
-						    EVAL_NORMAL));
+    value_assign_to_component (container, elt,
+			       arg->evaluate (nullptr, exp,
+					      EVAL_NORMAL));
+}
 
-  value_free_to_mark (mark);
+bool
+ada_aggregate_component::uses_objfile (struct objfile *objfile)
+{
+  for (const auto &item : m_components)
+    if (item->uses_objfile (objfile))
+      return true;
+  return false;
+}
+
+void
+ada_aggregate_component::dump (ui_file *stream, int depth)
+{
+  fprintf_filtered (stream, _("%*sAggregate\n"), depth, "");
+  for (const auto &item : m_components)
+    item->dump (stream, depth + 1);
+}
+
+void
+ada_aggregate_component::assign (struct value *container,
+				 struct value *lhs, struct expression *exp,
+				 std::vector<LONGEST> &indices,
+				 LONGEST low, LONGEST high)
+{
+  for (auto &item : m_components)
+    item->assign (container, lhs, exp, indices, low, high);
 }
 
 /* Assuming that LHS represents an lvalue having a record or array
-   type, and EXP->ELTS[*POS] is an OP_AGGREGATE, evaluate an assignment
-   of that aggregate's value to LHS, advancing *POS past the
-   aggregate.  NOSIDE is as for evaluate_subexp.  CONTAINER is an
-   lvalue containing LHS (possibly LHS itself).  Does not modify
-   the inferior's memory, nor does it modify the contents of 
-   LHS (unless == CONTAINER).  Returns the modified CONTAINER.  */
+   type, evaluate an assignment of this aggregate's value to LHS.
+   CONTAINER is an lvalue containing LHS (possibly LHS itself).  Does
+   not modify the inferior's memory, nor does it modify the contents
+   of LHS (unless == CONTAINER).  */
 
-static struct value *
-assign_aggregate (struct value *container, 
-		  struct value *lhs, struct expression *exp, 
-		  int *pos, enum noside noside)
+void
+ada_aggregate_operation::assign_aggregate (struct value *container,
+					   struct value *lhs,
+					   struct expression *exp)
 {
   struct type *lhs_type;
-  int n = exp->elts[*pos+1].longconst;
   LONGEST low_index, high_index;
-  int i;
-
-  *pos += 3;
-  if (noside != EVAL_NORMAL)
-    {
-      for (i = 0; i < n; i += 1)
-	ada_evaluate_subexp (NULL, exp, pos, noside);
-      return container;
-    }
 
   container = ada_coerce_ref (container);
   if (ada_is_direct_array_type (value_type (container)))
@@ -9615,317 +9291,47 @@ assign_aggregate (struct value *container,
   indices[0] = indices[1] = low_index - 1;
   indices[2] = indices[3] = high_index + 1;
 
-  for (i = 0; i < n; i += 1)
-    {
-      switch (exp->elts[*pos].opcode)
-	{
-	  case OP_CHOICES:
-	    aggregate_assign_from_choices (container, lhs, exp, pos, indices,
-					   low_index, high_index);
-	    break;
-	  case OP_POSITIONAL:
-	    aggregate_assign_positional (container, lhs, exp, pos, indices,
-					 low_index, high_index);
-	    break;
-	  case OP_OTHERS:
-	    if (i != n-1)
-	      error (_("Misplaced 'others' clause"));
-	    aggregate_assign_others (container, lhs, exp, pos, indices,
-				     low_index, high_index);
-	    break;
-	  default:
-	    error (_("Internal error: bad aggregate clause"));
-	}
-    }
+  std::get<0> (m_storage)->assign (container, lhs, exp, indices,
+				   low_index, high_index);
+}
+
+bool
+ada_positional_component::uses_objfile (struct objfile *objfile)
+{
+  return m_op->uses_objfile (objfile);
+}
 
-  return container;
+void
+ada_positional_component::dump (ui_file *stream, int depth)
+{
+  fprintf_filtered (stream, _("%*sPositional, index = %d\n"),
+		    depth, "", m_index);
+  m_op->dump (stream, depth + 1);
 }
-	      
+
 /* Assign into the component of LHS indexed by the OP_POSITIONAL
-   construct at *POS, updating *POS past the construct, given that
-   the positions are relative to lower bound LOW, where HIGH is the
-   upper bound.  Record the position in INDICES.  CONTAINER is as for
-   assign_aggregate.  */
-static void
-aggregate_assign_positional (struct value *container,
-			     struct value *lhs, struct expression *exp,
-			     int *pos, std::vector<LONGEST> &indices,
-			     LONGEST low, LONGEST high)
+   construct, given that the positions are relative to lower bound
+   LOW, where HIGH is the upper bound.  Record the position in
+   INDICES.  CONTAINER is as for assign_aggregate.  */
+void
+ada_positional_component::assign (struct value *container,
+				  struct value *lhs, struct expression *exp,
+				  std::vector<LONGEST> &indices,
+				  LONGEST low, LONGEST high)
 {
-  LONGEST ind = longest_to_int (exp->elts[*pos + 1].longconst) + low;
-  
+  LONGEST ind = m_index + low;
+
   if (ind - 1 == high)
     warning (_("Extra components in aggregate ignored."));
   if (ind <= high)
     {
       add_component_interval (ind, ind, indices);
-      *pos += 3;
-      assign_component (container, lhs, ind, exp, pos);
+      assign_component (container, lhs, ind, exp, m_op);
     }
-  else
-    ada_evaluate_subexp (NULL, exp, pos, EVAL_SKIP);
 }
 
-/* Assign into the components of LHS indexed by the OP_CHOICES
-   construct at *POS, updating *POS past the construct, given that
-   the allowable indices are LOW..HIGH.  Record the indices assigned
-   to in INDICES.  CONTAINER is as for assign_aggregate.  */
-static void
-aggregate_assign_from_choices (struct value *container,
-			       struct value *lhs, struct expression *exp,
-			       int *pos, std::vector<LONGEST> &indices,
-			       LONGEST low, LONGEST high)
-{
-  int j;
-  int n_choices = longest_to_int (exp->elts[*pos+1].longconst);
-  int choice_pos, expr_pc;
-  int is_array = ada_is_direct_array_type (value_type (lhs));
-
-  choice_pos = *pos += 3;
-
-  for (j = 0; j < n_choices; j += 1)
-    ada_evaluate_subexp (NULL, exp, pos, EVAL_SKIP);
-  expr_pc = *pos;
-  ada_evaluate_subexp (NULL, exp, pos, EVAL_SKIP);
-  
-  for (j = 0; j < n_choices; j += 1)
-    {
-      LONGEST lower, upper;
-      enum exp_opcode op = exp->elts[choice_pos].opcode;
-
-      if (op == OP_DISCRETE_RANGE)
-	{
-	  choice_pos += 1;
-	  lower = value_as_long (ada_evaluate_subexp (NULL, exp, pos,
-						      EVAL_NORMAL));
-	  upper = value_as_long (ada_evaluate_subexp (NULL, exp, pos, 
-						      EVAL_NORMAL));
-	}
-      else if (is_array)
-	{
-	  lower = value_as_long (ada_evaluate_subexp (NULL, exp, &choice_pos, 
-						      EVAL_NORMAL));
-	  upper = lower;
-	}
-      else
-	{
-	  int ind;
-	  const char *name;
-
-	  switch (op)
-	    {
-	    case OP_NAME:
-	      name = &exp->elts[choice_pos + 2].string;
-	      break;
-	    case OP_VAR_VALUE:
-	      name = exp->elts[choice_pos + 2].symbol->natural_name ();
-	      break;
-	    default:
-	      error (_("Invalid record component association."));
-	    }
-	  ada_evaluate_subexp (NULL, exp, &choice_pos, EVAL_SKIP);
-	  ind = 0;
-	  if (! find_struct_field (name, value_type (lhs), 0, 
-				   NULL, NULL, NULL, NULL, &ind))
-	    error (_("Unknown component name: %s."), name);
-	  lower = upper = ind;
-	}
-
-      if (lower <= upper && (lower < low || upper > high))
-	error (_("Index in component association out of bounds."));
-
-      add_component_interval (lower, upper, indices);
-      while (lower <= upper)
-	{
-	  int pos1;
-
-	  pos1 = expr_pc;
-	  assign_component (container, lhs, lower, exp, &pos1);
-	  lower += 1;
-	}
-    }
-}
-
-/* Assign the value of the expression in the OP_OTHERS construct in
-   EXP at *POS into the components of LHS indexed from LOW .. HIGH that
-   have not been previously assigned.  The index intervals already assigned
-   are in INDICES.  Updates *POS to after the OP_OTHERS clause.
-   CONTAINER is as for assign_aggregate.  */
-static void
-aggregate_assign_others (struct value *container,
-			 struct value *lhs, struct expression *exp,
-			 int *pos, std::vector<LONGEST> &indices,
-			 LONGEST low, LONGEST high) 
-{
-  int i;
-  int expr_pc = *pos + 1;
-  
-  int num_indices = indices.size ();
-  for (i = 0; i < num_indices - 2; i += 2)
-    {
-      LONGEST ind;
-
-      for (ind = indices[i + 1] + 1; ind < indices[i + 2]; ind += 1)
-	{
-	  int localpos;
-
-	  localpos = expr_pc;
-	  assign_component (container, lhs, ind, exp, &localpos);
-	}
-    }
-  ada_evaluate_subexp (NULL, exp, pos, EVAL_SKIP);
-}
-
-namespace expr
-{
-
-bool
-check_objfile (const std::unique_ptr<ada_component> &comp,
-	       struct objfile *objfile)
-{
-  return comp->uses_objfile (objfile);
-}
-
-/* Assign the result of evaluating ARG starting at *POS to the INDEXth
-   component of LHS (a simple array or a record).  Does not modify the
-   inferior's memory, nor does it modify LHS (unless LHS ==
-   CONTAINER).  */
-
-static void
-assign_component (struct value *container, struct value *lhs, LONGEST index,
-		  struct expression *exp, operation_up &arg)
-{
-  scoped_value_mark mark;
-
-  struct value *elt;
-  struct type *lhs_type = check_typedef (value_type (lhs));
-
-  if (lhs_type->code () == TYPE_CODE_ARRAY)
-    {
-      struct type *index_type = builtin_type (exp->gdbarch)->builtin_int;
-      struct value *index_val = value_from_longest (index_type, index);
-
-      elt = unwrap_value (ada_value_subscript (lhs, 1, &index_val));
-    }
-  else
-    {
-      elt = ada_index_struct_field (index, lhs, 0, value_type (lhs));
-      elt = ada_to_fixed_value (elt);
-    }
-
-  ada_aggregate_operation *ag_op
-    = dynamic_cast<ada_aggregate_operation *> (arg.get ());
-  if (ag_op != nullptr)
-    ag_op->assign_aggregate (container, elt, exp);
-  else
-    value_assign_to_component (container, elt,
-			       arg->evaluate (nullptr, exp,
-					      EVAL_NORMAL));
-}
-
-bool
-ada_aggregate_component::uses_objfile (struct objfile *objfile)
-{
-  for (const auto &item : m_components)
-    if (item->uses_objfile (objfile))
-      return true;
-  return false;
-}
-
-void
-ada_aggregate_component::dump (ui_file *stream, int depth)
-{
-  fprintf_filtered (stream, _("%*sAggregate\n"), depth, "");
-  for (const auto &item : m_components)
-    item->dump (stream, depth + 1);
-}
-
-void
-ada_aggregate_component::assign (struct value *container,
-				 struct value *lhs, struct expression *exp,
-				 std::vector<LONGEST> &indices,
-				 LONGEST low, LONGEST high)
-{
-  for (auto &item : m_components)
-    item->assign (container, lhs, exp, indices, low, high);
-}
-
-void
-ada_aggregate_operation::assign_aggregate (struct value *container,
-					   struct value *lhs,
-					   struct expression *exp)
-{
-  struct type *lhs_type;
-  LONGEST low_index, high_index;
-
-  container = ada_coerce_ref (container);
-  if (ada_is_direct_array_type (value_type (container)))
-    container = ada_coerce_to_simple_array (container);
-  lhs = ada_coerce_ref (lhs);
-  if (!deprecated_value_modifiable (lhs))
-    error (_("Left operand of assignment is not a modifiable lvalue."));
-
-  lhs_type = check_typedef (value_type (lhs));
-  if (ada_is_direct_array_type (lhs_type))
-    {
-      lhs = ada_coerce_to_simple_array (lhs);
-      lhs_type = check_typedef (value_type (lhs));
-      low_index = lhs_type->bounds ()->low.const_val ();
-      high_index = lhs_type->bounds ()->high.const_val ();
-    }
-  else if (lhs_type->code () == TYPE_CODE_STRUCT)
-    {
-      low_index = 0;
-      high_index = num_visible_fields (lhs_type) - 1;
-    }
-  else
-    error (_("Left-hand side must be array or record."));
-
-  std::vector<LONGEST> indices (4);
-  indices[0] = indices[1] = low_index - 1;
-  indices[2] = indices[3] = high_index + 1;
-
-  std::get<0> (m_storage)->assign (container, lhs, exp, indices,
-				   low_index, high_index);
-}
-
-bool
-ada_positional_component::uses_objfile (struct objfile *objfile)
-{
-  return m_op->uses_objfile (objfile);
-}
-
-void
-ada_positional_component::dump (ui_file *stream, int depth)
-{
-  fprintf_filtered (stream, _("%*sPositional, index = %d\n"),
-		    depth, "", m_index);
-  m_op->dump (stream, depth + 1);
-}
-
-/* Assign into the component of LHS indexed by the OP_POSITIONAL
-   construct, given that the positions are relative to lower bound
-   LOW, where HIGH is the upper bound.  Record the position in
-   INDICES.  CONTAINER is as for assign_aggregate.  */
-void
-ada_positional_component::assign (struct value *container,
-				  struct value *lhs, struct expression *exp,
-				  std::vector<LONGEST> &indices,
-				  LONGEST low, LONGEST high)
-{
-  LONGEST ind = m_index + low;
-
-  if (ind - 1 == high)
-    warning (_("Extra components in aggregate ignored."));
-  if (ind <= high)
-    {
-      add_component_interval (ind, ind, indices);
-      assign_component (container, lhs, ind, exp, m_op);
-    }
-}
-
-bool
-ada_discrete_range_association::uses_objfile (struct objfile *objfile)
+bool
+ada_discrete_range_association::uses_objfile (struct objfile *objfile)
 {
   return m_low->uses_objfile (objfile) || m_high->uses_objfile (objfile);
 }
@@ -10430,58 +9836,6 @@ ada_value_cast (struct type *type, struct value *arg2)
     entity.  Results in this case are unpredictable, as we usually read
     past the buffer containing the data =:-o.  */
 
-/* Evaluate a subexpression of EXP, at index *POS, and return a value
-   for that subexpression cast to TO_TYPE.  Advance *POS over the
-   subexpression.  */
-
-static value *
-ada_evaluate_subexp_for_cast (expression *exp, int *pos,
-			      enum noside noside, struct type *to_type)
-{
-  int pc = *pos;
-
-  if (exp->elts[pc].opcode == OP_VAR_MSYM_VALUE
-      || exp->elts[pc].opcode == OP_VAR_VALUE)
-    {
-      (*pos) += 4;
-
-      value *val;
-      if (exp->elts[pc].opcode == OP_VAR_MSYM_VALUE)
-	{
-	  if (noside == EVAL_AVOID_SIDE_EFFECTS)
-	    return value_zero (to_type, not_lval);
-
-	  val = evaluate_var_msym_value (noside,
-					 exp->elts[pc + 1].objfile,
-					 exp->elts[pc + 2].msymbol);
-	}
-      else
-	val = evaluate_var_value (noside,
-				  exp->elts[pc + 1].block,
-				  exp->elts[pc + 2].symbol);
-
-      if (noside == EVAL_SKIP)
-	return eval_skip_value (exp);
-
-      val = ada_value_cast (to_type, val);
-
-      /* Follow the Ada language semantics that do not allow taking
-	 an address of the result of a cast (view conversion in Ada).  */
-      if (VALUE_LVAL (val) == lval_memory)
-	{
-	  if (value_lazy (val))
-	    value_fetch_lazy (val);
-	  VALUE_LVAL (val) = not_lval;
-	}
-      return val;
-    }
-
-  value *val = evaluate_subexp (to_type, exp, pos, noside);
-  if (noside == EVAL_SKIP)
-    return eval_skip_value (exp);
-  return ada_value_cast (to_type, val);
-}
-
 /* A helper function for TERNOP_IN_RANGE.  */
 
 static value *
@@ -11442,841 +10796,100 @@ ada_funcall_operation::evaluate (struct type *expect_type,
 	   something.  */
 	return value_zero (builtin_type (exp->gdbarch)->builtin_int,
 			   not_lval);
-      else
-	return call_internal_function (exp->gdbarch, exp->language_defn,
-				       callee, nargs,
-				       argvec.data ());
-
-    case TYPE_CODE_STRUCT:
-      {
-	int arity;
-
-	arity = ada_array_arity (type);
-	type = ada_array_element_type (type, nargs);
-	if (type == NULL)
-	  error (_("cannot subscript or call a record"));
-	if (arity != nargs)
-	  error (_("wrong number of subscripts; expecting %d"), arity);
-	if (noside == EVAL_AVOID_SIDE_EFFECTS)
-	  return value_zero (ada_aligned_type (type), lval_memory);
-	return
-	  unwrap_value (ada_value_subscript
-			(callee, nargs, argvec.data ()));
-      }
-    case TYPE_CODE_ARRAY:
-      if (noside == EVAL_AVOID_SIDE_EFFECTS)
-	{
-	  type = ada_array_element_type (type, nargs);
-	  if (type == NULL)
-	    error (_("element type of array unknown"));
-	  else
-	    return value_zero (ada_aligned_type (type), lval_memory);
-	}
-      return
-	unwrap_value (ada_value_subscript
-		      (ada_coerce_to_simple_array (callee),
-		       nargs, argvec.data ()));
-    case TYPE_CODE_PTR:     /* Pointer to array */
-      if (noside == EVAL_AVOID_SIDE_EFFECTS)
-	{
-	  type = to_fixed_array_type (TYPE_TARGET_TYPE (type), NULL, 1);
-	  type = ada_array_element_type (type, nargs);
-	  if (type == NULL)
-	    error (_("element type of array unknown"));
-	  else
-	    return value_zero (ada_aligned_type (type), lval_memory);
-	}
-      return
-	unwrap_value (ada_value_ptr_subscript (callee, nargs,
-					       argvec.data ()));
-
-    default:
-      error (_("Attempt to index or call something other than an "
-	       "array or function"));
-    }
-}
-
-bool
-ada_funcall_operation::resolve (struct expression *exp,
-				bool deprocedure_p,
-				bool parse_completion,
-				innermost_block_tracker *tracker,
-				struct type *context_type)
-{
-  operation_up &callee_op = std::get<0> (m_storage);
-
-  ada_var_value_operation *avv
-    = dynamic_cast<ada_var_value_operation *> (callee_op.get ());
-  if (avv == nullptr)
-    return false;
-
-  symbol *sym = avv->get_symbol ();
-  if (SYMBOL_DOMAIN (sym) != UNDEF_DOMAIN)
-    return false;
-
-  const std::vector<operation_up> &args_up = std::get<1> (m_storage);
-  int nargs = args_up.size ();
-  std::vector<value *> argvec (nargs);
-
-  for (int i = 0; i < args_up.size (); ++i)
-    argvec[i] = args_up[i]->evaluate (nullptr, exp, EVAL_AVOID_SIDE_EFFECTS);
-
-  const block *block = avv->get_block ();
-  block_symbol resolved
-    = ada_resolve_funcall (sym, block,
-			   context_type, parse_completion,
-			   nargs, argvec.data (),
-			   tracker);
-
-  std::get<0> (m_storage)
-    = make_operation<ada_var_value_operation> (resolved.symbol,
-					       resolved.block);
-  return false;
-}
-
-}
-
-/* Implement the evaluate_exp routine in the exp_descriptor structure
-   for the Ada language.  */
-
-static struct value *
-ada_evaluate_subexp (struct type *expect_type, struct expression *exp,
-		     int *pos, enum noside noside)
-{
-  enum exp_opcode op;
-  int tem;
-  int pc;
-  int preeval_pos;
-  struct value *arg1 = NULL, *arg2 = NULL, *arg3;
-  struct type *type;
-  int nargs, oplen;
-  struct value **argvec;
-
-  pc = *pos;
-  *pos += 1;
-  op = exp->elts[pc].opcode;
-
-  switch (op)
-    {
-    default:
-      *pos -= 1;
-      arg1 = evaluate_subexp_standard (expect_type, exp, pos, noside);
-
-      if (noside == EVAL_NORMAL)
-	arg1 = unwrap_value (arg1);
-
-      /* If evaluating an OP_FLOAT and an EXPECT_TYPE was provided,
-	 then we need to perform the conversion manually, because
-	 evaluate_subexp_standard doesn't do it.  This conversion is
-	 necessary in Ada because the different kinds of float/fixed
-	 types in Ada have different representations.
-
-	 Similarly, we need to perform the conversion from OP_LONG
-	 ourselves.  */
-      if ((op == OP_FLOAT || op == OP_LONG) && expect_type != NULL)
-	arg1 = ada_value_cast (expect_type, arg1);
-
-      return arg1;
-
-    case OP_STRING:
-      {
-	struct value *result;
-
-	*pos -= 1;
-	result = evaluate_subexp_standard (expect_type, exp, pos, noside);
-	/* The result type will have code OP_STRING, bashed there from 
-	   OP_ARRAY.  Bash it back.  */
-	if (value_type (result)->code () == TYPE_CODE_STRING)
-	  value_type (result)->set_code (TYPE_CODE_ARRAY);
-	return result;
-      }
-
-    case UNOP_CAST:
-      (*pos) += 2;
-      type = exp->elts[pc + 1].type;
-      return ada_evaluate_subexp_for_cast (exp, pos, noside, type);
-
-    case UNOP_QUAL:
-      (*pos) += 2;
-      type = exp->elts[pc + 1].type;
-      return ada_evaluate_subexp (type, exp, pos, noside);
-
-    case BINOP_ASSIGN:
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      if (exp->elts[*pos].opcode == OP_AGGREGATE)
-	{
-	  arg1 = assign_aggregate (arg1, arg1, exp, pos, noside);
-	  if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS)
-	    return arg1;
-	  return ada_value_assign (arg1, arg1);
-	}
-      /* Force the evaluation of the rhs ARG2 to the type of the lhs ARG1,
-	 except if the lhs of our assignment is a convenience variable.
-	 In the case of assigning to a convenience variable, the lhs
-	 should be exactly the result of the evaluation of the rhs.  */
-      type = value_type (arg1);
-      if (VALUE_LVAL (arg1) == lval_internalvar)
-	 type = NULL;
-      arg2 = evaluate_subexp (type, exp, pos, noside);
-      if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS)
-	return arg1;
-      if (VALUE_LVAL (arg1) == lval_internalvar)
-	{
-	  /* Nothing.  */
-	}
-      else if (ada_is_gnat_encoded_fixed_point_type (value_type (arg1)))
-	arg2 = cast_to_gnat_encoded_fixed_point_type (value_type (arg1), arg2);
-      else if (ada_is_gnat_encoded_fixed_point_type (value_type (arg2)))
-	error
-	  (_("Fixed-point values must be assigned to fixed-point variables"));
-      else
-	arg2 = coerce_for_assign (value_type (arg1), arg2);
-      return ada_value_assign (arg1, arg2);
-
-    case BINOP_ADD:
-      arg1 = evaluate_subexp_with_coercion (exp, pos, noside);
-      arg2 = evaluate_subexp_with_coercion (exp, pos, noside);
-      if (noside == EVAL_SKIP)
-	goto nosideret;
-      if (value_type (arg1)->code () == TYPE_CODE_PTR)
-	return (value_from_longest
-		 (value_type (arg1),
-		  value_as_long (arg1) + value_as_long (arg2)));
-      if (value_type (arg2)->code () == TYPE_CODE_PTR)
-	return (value_from_longest
-		 (value_type (arg2),
-		  value_as_long (arg1) + value_as_long (arg2)));
-      if ((ada_is_gnat_encoded_fixed_point_type (value_type (arg1))
-	   || ada_is_gnat_encoded_fixed_point_type (value_type (arg2)))
-	  && value_type (arg1) != value_type (arg2))
-	error (_("Operands of fixed-point addition must have the same type"));
-      /* Do the addition, and cast the result to the type of the first
-	 argument.  We cannot cast the result to a reference type, so if
-	 ARG1 is a reference type, find its underlying type.  */
-      type = value_type (arg1);
-      while (type->code () == TYPE_CODE_REF)
-	type = TYPE_TARGET_TYPE (type);
-      binop_promote (exp->language_defn, exp->gdbarch, &arg1, &arg2);
-      return value_cast (type, value_binop (arg1, arg2, BINOP_ADD));
-
-    case BINOP_SUB:
-      arg1 = evaluate_subexp_with_coercion (exp, pos, noside);
-      arg2 = evaluate_subexp_with_coercion (exp, pos, noside);
-      if (noside == EVAL_SKIP)
-	goto nosideret;
-      if (value_type (arg1)->code () == TYPE_CODE_PTR)
-	return (value_from_longest
-		 (value_type (arg1),
-		  value_as_long (arg1) - value_as_long (arg2)));
-      if (value_type (arg2)->code () == TYPE_CODE_PTR)
-	return (value_from_longest
-		 (value_type (arg2),
-		  value_as_long (arg1) - value_as_long (arg2)));
-      if ((ada_is_gnat_encoded_fixed_point_type (value_type (arg1))
-	   || ada_is_gnat_encoded_fixed_point_type (value_type (arg2)))
-	  && value_type (arg1) != value_type (arg2))
-	error (_("Operands of fixed-point subtraction "
-		 "must have the same type"));
-      /* Do the substraction, and cast the result to the type of the first
-	 argument.  We cannot cast the result to a reference type, so if
-	 ARG1 is a reference type, find its underlying type.  */
-      type = value_type (arg1);
-      while (type->code () == TYPE_CODE_REF)
-	type = TYPE_TARGET_TYPE (type);
-      binop_promote (exp->language_defn, exp->gdbarch, &arg1, &arg2);
-      return value_cast (type, value_binop (arg1, arg2, BINOP_SUB));
-
-    case BINOP_MUL:
-    case BINOP_DIV:
-    case BINOP_REM:
-    case BINOP_MOD:
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      arg2 = evaluate_subexp (nullptr, exp, pos, noside);
-      if (noside == EVAL_SKIP)
-	goto nosideret;
-      return ada_mult_binop (expect_type, exp, noside, op,
-			     arg1, arg2);
-
-    case BINOP_EQUAL:
-    case BINOP_NOTEQUAL:
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      arg2 = evaluate_subexp (value_type (arg1), exp, pos, noside);
-      if (noside == EVAL_SKIP)
-	goto nosideret;
-      return ada_equal_binop (expect_type, exp, noside, op, arg1, arg2);
-
-    case UNOP_NEG:
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      return ada_unop_neg (expect_type, exp, noside, op, arg1);
-
-    case BINOP_LOGICAL_AND:
-    case BINOP_LOGICAL_OR:
-    case UNOP_LOGICAL_NOT:
-      {
-	struct value *val;
-
-	*pos -= 1;
-	val = evaluate_subexp_standard (expect_type, exp, pos, noside);
-	type = language_bool_type (exp->language_defn, exp->gdbarch);
-	return value_cast (type, val);
-      }
-
-    case BINOP_BITWISE_AND:
-    case BINOP_BITWISE_IOR:
-    case BINOP_BITWISE_XOR:
-      {
-	struct value *val;
-
-	arg1 = evaluate_subexp (nullptr, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
-	*pos = pc;
-	val = evaluate_subexp_standard (expect_type, exp, pos, noside);
-
-	return value_cast (value_type (arg1), val);
-      }
-
-    case OP_VAR_VALUE:
-      *pos -= 1;
-
-      if (noside == EVAL_SKIP)
-	{
-	  *pos += 4;
-	  goto nosideret;
-	}
-
-      if (SYMBOL_DOMAIN (exp->elts[pc + 2].symbol) == UNDEF_DOMAIN)
-	/* Only encountered when an unresolved symbol occurs in a
-	   context other than a function call, in which case, it is
-	   invalid.  */
-	error (_("Unexpected unresolved symbol, %s, during evaluation"),
-	       exp->elts[pc + 2].symbol->print_name ());
-
-      if (noside == EVAL_AVOID_SIDE_EFFECTS)
-	{
-	  type = static_unwrap_type (SYMBOL_TYPE (exp->elts[pc + 2].symbol));
-	  /* Check to see if this is a tagged type.  We also need to handle
-	     the case where the type is a reference to a tagged type, but
-	     we have to be careful to exclude pointers to tagged types.
-	     The latter should be shown as usual (as a pointer), whereas
-	     a reference should mostly be transparent to the user.  */
-	  if (ada_is_tagged_type (type, 0)
-	      || (type->code () == TYPE_CODE_REF
-		  && ada_is_tagged_type (TYPE_TARGET_TYPE (type), 0)))
-	    {
-	      /* Tagged types are a little special in the fact that the real
-		 type is dynamic and can only be determined by inspecting the
-		 object's tag.  This means that we need to get the object's
-		 value first (EVAL_NORMAL) and then extract the actual object
-		 type from its tag.
-
-		 Note that we cannot skip the final step where we extract
-		 the object type from its tag, because the EVAL_NORMAL phase
-		 results in dynamic components being resolved into fixed ones.
-		 This can cause problems when trying to print the type
-		 description of tagged types whose parent has a dynamic size:
-		 We use the type name of the "_parent" component in order
-		 to print the name of the ancestor type in the type description.
-		 If that component had a dynamic size, the resolution into
-		 a fixed type would result in the loss of that type name,
-		 thus preventing us from printing the name of the ancestor
-		 type in the type description.  */
-	      arg1 = evaluate_subexp (nullptr, exp, pos, EVAL_NORMAL);
-
-	      if (type->code () != TYPE_CODE_REF)
-		{
-		  struct type *actual_type;
-
-		  actual_type = type_from_tag (ada_value_tag (arg1));
-		  if (actual_type == NULL)
-		    /* If, for some reason, we were unable to determine
-		       the actual type from the tag, then use the static
-		       approximation that we just computed as a fallback.
-		       This can happen if the debugging information is
-		       incomplete, for instance.  */
-		    actual_type = type;
-		  return value_zero (actual_type, not_lval);
-		}
-	      else
-		{
-		  /* In the case of a ref, ada_coerce_ref takes care
-		     of determining the actual type.  But the evaluation
-		     should return a ref as it should be valid to ask
-		     for its address; so rebuild a ref after coerce.  */
-		  arg1 = ada_coerce_ref (arg1);
-		  return value_ref (arg1, TYPE_CODE_REF);
-		}
-	    }
-
-	  /* Records and unions for which GNAT encodings have been
-	     generated need to be statically fixed as well.
-	     Otherwise, non-static fixing produces a type where
-	     all dynamic properties are removed, which prevents "ptype"
-	     from being able to completely describe the type.
-	     For instance, a case statement in a variant record would be
-	     replaced by the relevant components based on the actual
-	     value of the discriminants.  */
-	  if ((type->code () == TYPE_CODE_STRUCT
-	       && dynamic_template_type (type) != NULL)
-	      || (type->code () == TYPE_CODE_UNION
-		  && ada_find_parallel_type (type, "___XVU") != NULL))
-	    {
-	      *pos += 4;
-	      return value_zero (to_static_fixed_type (type), not_lval);
-	    }
-	}
-
-      arg1 = evaluate_subexp_standard (expect_type, exp, pos, noside);
-      return ada_to_fixed_value (arg1);
-
-    case OP_FUNCALL:
-      (*pos) += 2;
-
-      /* Allocate arg vector, including space for the function to be
-	 called in argvec[0] and a terminating NULL.  */
-      nargs = longest_to_int (exp->elts[pc + 1].longconst);
-      argvec = XALLOCAVEC (struct value *, nargs + 2);
-
-      if (exp->elts[*pos].opcode == OP_VAR_VALUE
-	  && SYMBOL_DOMAIN (exp->elts[pc + 5].symbol) == UNDEF_DOMAIN)
-	error (_("Unexpected unresolved symbol, %s, during evaluation"),
-	       exp->elts[pc + 5].symbol->print_name ());
-      else
-	{
-	  for (tem = 0; tem <= nargs; tem += 1)
-	    argvec[tem] = evaluate_subexp (nullptr, exp, pos, noside);
-	  argvec[tem] = 0;
-
-	  if (noside == EVAL_SKIP)
-	    goto nosideret;
-	}
-
-      if (ada_is_constrained_packed_array_type
-	  (desc_base_type (value_type (argvec[0]))))
-	argvec[0] = ada_coerce_to_simple_array (argvec[0]);
-      else if (value_type (argvec[0])->code () == TYPE_CODE_ARRAY
-	       && TYPE_FIELD_BITSIZE (value_type (argvec[0]), 0) != 0)
-	/* This is a packed array that has already been fixed, and
-	   therefore already coerced to a simple array.  Nothing further
-	   to do.  */
-	;
-      else if (value_type (argvec[0])->code () == TYPE_CODE_REF)
-	{
-	  /* Make sure we dereference references so that all the code below
-	     feels like it's really handling the referenced value.  Wrapping
-	     types (for alignment) may be there, so make sure we strip them as
-	     well.  */
-	  argvec[0] = ada_to_fixed_value (coerce_ref (argvec[0]));
-	}
-      else if (value_type (argvec[0])->code () == TYPE_CODE_ARRAY
-	       && VALUE_LVAL (argvec[0]) == lval_memory)
-	argvec[0] = value_addr (argvec[0]);
-
-      type = ada_check_typedef (value_type (argvec[0]));
-
-      /* Ada allows us to implicitly dereference arrays when subscripting
-	 them.  So, if this is an array typedef (encoding use for array
-	 access types encoded as fat pointers), strip it now.  */
-      if (type->code () == TYPE_CODE_TYPEDEF)
-	type = ada_typedef_target_type (type);
-
-      if (type->code () == TYPE_CODE_PTR)
-	{
-	  switch (ada_check_typedef (TYPE_TARGET_TYPE (type))->code ())
-	    {
-	    case TYPE_CODE_FUNC:
-	      type = ada_check_typedef (TYPE_TARGET_TYPE (type));
-	      break;
-	    case TYPE_CODE_ARRAY:
-	      break;
-	    case TYPE_CODE_STRUCT:
-	      if (noside != EVAL_AVOID_SIDE_EFFECTS)
-		argvec[0] = ada_value_ind (argvec[0]);
-	      type = ada_check_typedef (TYPE_TARGET_TYPE (type));
-	      break;
-	    default:
-	      error (_("cannot subscript or call something of type `%s'"),
-		     ada_type_name (value_type (argvec[0])));
-	      break;
-	    }
-	}
-
-      switch (type->code ())
-	{
-	case TYPE_CODE_FUNC:
-	  if (noside == EVAL_AVOID_SIDE_EFFECTS)
-	    {
-	      if (TYPE_TARGET_TYPE (type) == NULL)
-		error_call_unknown_return_type (NULL);
-	      return allocate_value (TYPE_TARGET_TYPE (type));
-	    }
-	  return call_function_by_hand (argvec[0], NULL,
-					gdb::make_array_view (argvec + 1,
-							      nargs));
-	case TYPE_CODE_INTERNAL_FUNCTION:
-	  if (noside == EVAL_AVOID_SIDE_EFFECTS)
-	    /* We don't know anything about what the internal
-	       function might return, but we have to return
-	       something.  */
-	    return value_zero (builtin_type (exp->gdbarch)->builtin_int,
-			       not_lval);
-	  else
-	    return call_internal_function (exp->gdbarch, exp->language_defn,
-					   argvec[0], nargs, argvec + 1);
-
-	case TYPE_CODE_STRUCT:
-	  {
-	    int arity;
-
-	    arity = ada_array_arity (type);
-	    type = ada_array_element_type (type, nargs);
-	    if (type == NULL)
-	      error (_("cannot subscript or call a record"));
-	    if (arity != nargs)
-	      error (_("wrong number of subscripts; expecting %d"), arity);
-	    if (noside == EVAL_AVOID_SIDE_EFFECTS)
-	      return value_zero (ada_aligned_type (type), lval_memory);
-	    return
-	      unwrap_value (ada_value_subscript
-			    (argvec[0], nargs, argvec + 1));
-	  }
-	case TYPE_CODE_ARRAY:
-	  if (noside == EVAL_AVOID_SIDE_EFFECTS)
-	    {
-	      type = ada_array_element_type (type, nargs);
-	      if (type == NULL)
-		error (_("element type of array unknown"));
-	      else
-		return value_zero (ada_aligned_type (type), lval_memory);
-	    }
-	  return
-	    unwrap_value (ada_value_subscript
-			  (ada_coerce_to_simple_array (argvec[0]),
-			   nargs, argvec + 1));
-	case TYPE_CODE_PTR:     /* Pointer to array */
-	  if (noside == EVAL_AVOID_SIDE_EFFECTS)
-	    {
-	      type = to_fixed_array_type (TYPE_TARGET_TYPE (type), NULL, 1);
-	      type = ada_array_element_type (type, nargs);
-	      if (type == NULL)
-		error (_("element type of array unknown"));
-	      else
-		return value_zero (ada_aligned_type (type), lval_memory);
-	    }
-	  return
-	    unwrap_value (ada_value_ptr_subscript (argvec[0],
-						   nargs, argvec + 1));
-
-	default:
-	  error (_("Attempt to index or call something other than an "
-		   "array or function"));
-	}
-
-    case TERNOP_SLICE:
-      {
-	struct value *array = evaluate_subexp (nullptr, exp, pos, noside);
-	struct value *low_bound_val
-	  = evaluate_subexp (nullptr, exp, pos, noside);
-	struct value *high_bound_val
-	  = evaluate_subexp (nullptr, exp, pos, noside);
-
-	if (noside == EVAL_SKIP)
-	  goto nosideret;
-
-	return ada_ternop_slice (exp, noside, array, low_bound_val,
-				 high_bound_val);
-      }
-
-    case UNOP_IN_RANGE:
-      (*pos) += 2;
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      type = check_typedef (exp->elts[pc + 1].type);
-      return ada_unop_in_range (expect_type, exp, noside, op, arg1, type);
-
-    case BINOP_IN_BOUNDS:
-      (*pos) += 2;
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      arg2 = evaluate_subexp (nullptr, exp, pos, noside);
-
-      if (noside == EVAL_SKIP)
-	goto nosideret;
-
-      tem = longest_to_int (exp->elts[pc + 1].longconst);
-
-      return ada_binop_in_bounds (exp, noside, arg1, arg2, tem);
-
-    case TERNOP_IN_RANGE:
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      arg2 = evaluate_subexp (nullptr, exp, pos, noside);
-      arg3 = evaluate_subexp (nullptr, exp, pos, noside);
-
-      return eval_ternop_in_range (expect_type, exp, noside, arg1, arg2, arg3);
-
-    case OP_ATR_FIRST:
-    case OP_ATR_LAST:
-    case OP_ATR_LENGTH:
-      {
-	struct type *type_arg;
-
-	if (exp->elts[*pos].opcode == OP_TYPE)
-	  {
-	    evaluate_subexp (nullptr, exp, pos, EVAL_SKIP);
-	    arg1 = NULL;
-	    type_arg = check_typedef (exp->elts[pc + 2].type);
-	  }
-	else
-	  {
-	    arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-	    type_arg = NULL;
-	  }
-
-	if (exp->elts[*pos].opcode != OP_LONG)
-	  error (_("Invalid operand to '%s"), ada_attribute_name (op));
-	tem = longest_to_int (exp->elts[*pos + 2].longconst);
-	*pos += 4;
-
-	if (noside == EVAL_SKIP)
-	  goto nosideret;
-
-	return ada_unop_atr (exp, noside, op, arg1, type_arg, tem);
-      }
+      else
+	return call_internal_function (exp->gdbarch, exp->language_defn,
+				       callee, nargs,
+				       argvec.data ());
 
-    case OP_ATR_TAG:
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      if (noside == EVAL_SKIP)
-	goto nosideret;
-      return ada_atr_tag (expect_type, exp, noside, op, arg1);
-
-    case OP_ATR_MIN:
-    case OP_ATR_MAX:
-      evaluate_subexp (nullptr, exp, pos, EVAL_SKIP);
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      arg2 = evaluate_subexp (nullptr, exp, pos, noside);
-      if (noside == EVAL_SKIP)
-	goto nosideret;
-      return ada_binop_minmax (expect_type, exp, noside, op, arg1, arg2);
-
-    case OP_ATR_MODULUS:
+    case TYPE_CODE_STRUCT:
       {
-	struct type *type_arg = check_typedef (exp->elts[pc + 2].type);
-
-	evaluate_subexp (nullptr, exp, pos, EVAL_SKIP);
-	if (noside == EVAL_SKIP)
-	  goto nosideret;
-
-	if (!ada_is_modular_type (type_arg))
-	  error (_("'modulus must be applied to modular type"));
+	int arity;
 
-	return value_from_longest (TYPE_TARGET_TYPE (type_arg),
-				   ada_modulus (type_arg));
+	arity = ada_array_arity (type);
+	type = ada_array_element_type (type, nargs);
+	if (type == NULL)
+	  error (_("cannot subscript or call a record"));
+	if (arity != nargs)
+	  error (_("wrong number of subscripts; expecting %d"), arity);
+	if (noside == EVAL_AVOID_SIDE_EFFECTS)
+	  return value_zero (ada_aligned_type (type), lval_memory);
+	return
+	  unwrap_value (ada_value_subscript
+			(callee, nargs, argvec.data ()));
       }
-
-
-    case OP_ATR_POS:
-      evaluate_subexp (nullptr, exp, pos, EVAL_SKIP);
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      if (noside == EVAL_SKIP)
-	goto nosideret;
-      return ada_pos_atr (expect_type, exp, noside, op, arg1);
-
-    case OP_ATR_SIZE:
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      return ada_atr_size (expect_type, exp, noside, op, arg1);
-
-    case OP_ATR_VAL:
-      evaluate_subexp (nullptr, exp, pos, EVAL_SKIP);
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      type = exp->elts[pc + 2].type;
-      if (noside == EVAL_SKIP)
-	goto nosideret;
-      return ada_val_atr (noside, type, arg1);
-
-    case BINOP_EXP:
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      arg2 = evaluate_subexp (nullptr, exp, pos, noside);
-      if (noside == EVAL_SKIP)
-	goto nosideret;
-      return ada_binop_exp (expect_type, exp, noside, op, arg1, arg2);
-
-    case UNOP_PLUS:
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      if (noside == EVAL_SKIP)
-	goto nosideret;
-      else
-	return arg1;
-
-    case UNOP_ABS:
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      if (noside == EVAL_SKIP)
-	goto nosideret;
-      return ada_abs (expect_type, exp, noside, op, arg1);
-
-    case UNOP_IND:
-      preeval_pos = *pos;
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      if (noside == EVAL_SKIP)
-	goto nosideret;
-      type = ada_check_typedef (value_type (arg1));
+    case TYPE_CODE_ARRAY:
       if (noside == EVAL_AVOID_SIDE_EFFECTS)
 	{
-	  if (ada_is_array_descriptor_type (type))
-	    /* GDB allows dereferencing GNAT array descriptors.  */
-	    {
-	      struct type *arrType = ada_type_of_array (arg1, 0);
-
-	      if (arrType == NULL)
-		error (_("Attempt to dereference null array pointer."));
-	      return value_at_lazy (arrType, 0);
-	    }
-	  else if (type->code () == TYPE_CODE_PTR
-		   || type->code () == TYPE_CODE_REF
-		   /* In C you can dereference an array to get the 1st elt.  */
-		   || type->code () == TYPE_CODE_ARRAY)
-	    {
-	    /* As mentioned in the OP_VAR_VALUE case, tagged types can
-	       only be determined by inspecting the object's tag.
-	       This means that we need to evaluate completely the
-	       expression in order to get its type.  */
-
-	      if ((type->code () == TYPE_CODE_REF
-		   || type->code () == TYPE_CODE_PTR)
-		  && ada_is_tagged_type (TYPE_TARGET_TYPE (type), 0))
-		{
-		  arg1
-		    = evaluate_subexp (nullptr, exp, &preeval_pos, EVAL_NORMAL);
-		  type = value_type (ada_value_ind (arg1));
-		}
-	      else
-		{
-		  type = to_static_fixed_type
-		    (ada_aligned_type
-		     (ada_check_typedef (TYPE_TARGET_TYPE (type))));
-		}
-	      ada_ensure_varsize_limit (type);
-	      return value_zero (type, lval_memory);
-	    }
-	  else if (type->code () == TYPE_CODE_INT)
-	    {
-	      /* GDB allows dereferencing an int.  */
-	      if (expect_type == NULL)
-		return value_zero (builtin_type (exp->gdbarch)->builtin_int,
-				   lval_memory);
-	      else
-		{
-		  expect_type = 
-		    to_static_fixed_type (ada_aligned_type (expect_type));
-		  return value_zero (expect_type, lval_memory);
-		}
-	    }
+	  type = ada_array_element_type (type, nargs);
+	  if (type == NULL)
+	    error (_("element type of array unknown"));
 	  else
-	    error (_("Attempt to take contents of a non-pointer value."));
+	    return value_zero (ada_aligned_type (type), lval_memory);
 	}
-      arg1 = ada_coerce_ref (arg1);     /* FIXME: What is this for??  */
-      type = ada_check_typedef (value_type (arg1));
-
-      if (type->code () == TYPE_CODE_INT)
-	  /* GDB allows dereferencing an int.  If we were given
-	     the expect_type, then use that as the target type.
-	     Otherwise, assume that the target type is an int.  */
+      return
+	unwrap_value (ada_value_subscript
+		      (ada_coerce_to_simple_array (callee),
+		       nargs, argvec.data ()));
+    case TYPE_CODE_PTR:     /* Pointer to array */
+      if (noside == EVAL_AVOID_SIDE_EFFECTS)
 	{
-	  if (expect_type != NULL)
-	    return ada_value_ind (value_cast (lookup_pointer_type (expect_type),
-					      arg1));
+	  type = to_fixed_array_type (TYPE_TARGET_TYPE (type), NULL, 1);
+	  type = ada_array_element_type (type, nargs);
+	  if (type == NULL)
+	    error (_("element type of array unknown"));
 	  else
-	    return value_at_lazy (builtin_type (exp->gdbarch)->builtin_int,
-				  (CORE_ADDR) value_as_address (arg1));
+	    return value_zero (ada_aligned_type (type), lval_memory);
 	}
+      return
+	unwrap_value (ada_value_ptr_subscript (callee, nargs,
+					       argvec.data ()));
 
-      if (ada_is_array_descriptor_type (type))
-	/* GDB allows dereferencing GNAT array descriptors.  */
-	return ada_coerce_to_simple_array (arg1);
-      else
-	return ada_value_ind (arg1);
-
-    case STRUCTOP_STRUCT:
-      tem = longest_to_int (exp->elts[pc + 1].longconst);
-      (*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1);
-      preeval_pos = *pos;
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      if (noside == EVAL_SKIP)
-	goto nosideret;
-      if (noside == EVAL_AVOID_SIDE_EFFECTS)
-	{
-	  struct type *type1 = value_type (arg1);
+    default:
+      error (_("Attempt to index or call something other than an "
+	       "array or function"));
+    }
+}
 
-	  if (ada_is_tagged_type (type1, 1))
-	    {
-	      type = ada_lookup_struct_elt_type (type1,
-						 &exp->elts[pc + 2].string,
-						 1, 1);
+bool
+ada_funcall_operation::resolve (struct expression *exp,
+				bool deprocedure_p,
+				bool parse_completion,
+				innermost_block_tracker *tracker,
+				struct type *context_type)
+{
+  operation_up &callee_op = std::get<0> (m_storage);
 
-	      /* If the field is not found, check if it exists in the
-		 extension of this object's type. This means that we
-		 need to evaluate completely the expression.  */
+  ada_var_value_operation *avv
+    = dynamic_cast<ada_var_value_operation *> (callee_op.get ());
+  if (avv == nullptr)
+    return false;
 
-	      if (type == NULL)
-		{
-		  arg1
-		    = evaluate_subexp (nullptr, exp, &preeval_pos, EVAL_NORMAL);
-		  arg1 = ada_value_struct_elt (arg1,
-					       &exp->elts[pc + 2].string,
-					       0);
-		  arg1 = unwrap_value (arg1);
-		  type = value_type (ada_to_fixed_value (arg1));
-		}
-	    }
-	  else
-	    type =
-	      ada_lookup_struct_elt_type (type1, &exp->elts[pc + 2].string, 1,
-					  0);
+  symbol *sym = avv->get_symbol ();
+  if (SYMBOL_DOMAIN (sym) != UNDEF_DOMAIN)
+    return false;
 
-	  return value_zero (ada_aligned_type (type), lval_memory);
-	}
-      else
-	{
-	  arg1 = ada_value_struct_elt (arg1, &exp->elts[pc + 2].string, 0);
-	  arg1 = unwrap_value (arg1);
-	  return ada_to_fixed_value (arg1);
-	}
+  const std::vector<operation_up> &args_up = std::get<1> (m_storage);
+  int nargs = args_up.size ();
+  std::vector<value *> argvec (nargs);
 
-    case OP_TYPE:
-      /* The value is not supposed to be used.  This is here to make it
-	 easier to accommodate expressions that contain types.  */
-      (*pos) += 2;
-      if (noside == EVAL_SKIP)
-	goto nosideret;
-      else if (noside == EVAL_AVOID_SIDE_EFFECTS)
-	return allocate_value (exp->elts[pc + 1].type);
-      else
-	error (_("Attempt to use a type name as an expression"));
-
-    case OP_AGGREGATE:
-    case OP_CHOICES:
-    case OP_OTHERS:
-    case OP_DISCRETE_RANGE:
-    case OP_POSITIONAL:
-    case OP_NAME:
-      if (noside == EVAL_NORMAL)
-	switch (op) 
-	  {
-	  case OP_NAME:
-	    error (_("Undefined name, ambiguous name, or renaming used in "
-		     "component association: %s."), &exp->elts[pc+2].string);
-	  case OP_AGGREGATE:
-	    error (_("Aggregates only allowed on the right of an assignment"));
-	  default:
-	    internal_error (__FILE__, __LINE__,
-			    _("aggregate apparently mangled"));
-	  }
+  for (int i = 0; i < args_up.size (); ++i)
+    argvec[i] = args_up[i]->evaluate (nullptr, exp, EVAL_AVOID_SIDE_EFFECTS);
 
-      ada_forward_operator_length (exp, pc, &oplen, &nargs);
-      *pos += oplen - 1;
-      for (tem = 0; tem < nargs; tem += 1) 
-	ada_evaluate_subexp (NULL, exp, pos, noside);
-      goto nosideret;
-    }
+  const block *block = avv->get_block ();
+  block_symbol resolved
+    = ada_resolve_funcall (sym, block,
+			   context_type, parse_completion,
+			   nargs, argvec.data (),
+			   tracker);
+
+  std::get<0> (m_storage)
+    = make_operation<ada_var_value_operation> (resolved.symbol,
+					       resolved.block);
+  return false;
+}
 
-nosideret:
-  return eval_skip_value (exp);
 }
+
 \f
 
 				/* Fixed point */
@@ -14288,336 +12901,6 @@ info_exceptions_command (const char *regexp, int from_tty)
     printf_filtered ("%s: %s\n", info.name, paddress (gdbarch, info.addr));
 }
 
-				/* Operators */
-/* Information about operators given special treatment in functions
-   below.  */
-/* Format: OP_DEFN (<operator>, <operator length>, <# args>, <binop>).  */
-
-#define ADA_OPERATORS \
-    OP_DEFN (OP_VAR_VALUE, 4, 0, 0) \
-    OP_DEFN (BINOP_IN_BOUNDS, 3, 2, 0) \
-    OP_DEFN (TERNOP_IN_RANGE, 1, 3, 0) \
-    OP_DEFN (OP_ATR_FIRST, 1, 2, 0) \
-    OP_DEFN (OP_ATR_LAST, 1, 2, 0) \
-    OP_DEFN (OP_ATR_LENGTH, 1, 2, 0) \
-    OP_DEFN (OP_ATR_IMAGE, 1, 2, 0) \
-    OP_DEFN (OP_ATR_MAX, 1, 3, 0) \
-    OP_DEFN (OP_ATR_MIN, 1, 3, 0) \
-    OP_DEFN (OP_ATR_MODULUS, 1, 1, 0) \
-    OP_DEFN (OP_ATR_POS, 1, 2, 0) \
-    OP_DEFN (OP_ATR_SIZE, 1, 1, 0) \
-    OP_DEFN (OP_ATR_TAG, 1, 1, 0) \
-    OP_DEFN (OP_ATR_VAL, 1, 2, 0) \
-    OP_DEFN (UNOP_QUAL, 3, 1, 0) \
-    OP_DEFN (UNOP_IN_RANGE, 3, 1, 0) \
-    OP_DEFN (OP_OTHERS, 1, 1, 0) \
-    OP_DEFN (OP_POSITIONAL, 3, 1, 0) \
-    OP_DEFN (OP_DISCRETE_RANGE, 1, 2, 0)
-
-static void
-ada_operator_length (const struct expression *exp, int pc, int *oplenp,
-		     int *argsp)
-{
-  switch (exp->elts[pc - 1].opcode)
-    {
-    default:
-      operator_length_standard (exp, pc, oplenp, argsp);
-      break;
-
-#define OP_DEFN(op, len, args, binop) \
-    case op: *oplenp = len; *argsp = args; break;
-      ADA_OPERATORS;
-#undef OP_DEFN
-
-    case OP_AGGREGATE:
-      *oplenp = 3;
-      *argsp = longest_to_int (exp->elts[pc - 2].longconst);
-      break;
-
-    case OP_CHOICES:
-      *oplenp = 3;
-      *argsp = longest_to_int (exp->elts[pc - 2].longconst) + 1;
-      break;
-    }
-}
-
-/* Implementation of the exp_descriptor method operator_check.  */
-
-static int
-ada_operator_check (struct expression *exp, int pos,
-		    int (*objfile_func) (struct objfile *objfile, void *data),
-		    void *data)
-{
-  const union exp_element *const elts = exp->elts;
-  struct type *type = NULL;
-
-  switch (elts[pos].opcode)
-    {
-      case UNOP_IN_RANGE:
-      case UNOP_QUAL:
-	type = elts[pos + 1].type;
-	break;
-
-      default:
-	return operator_check_standard (exp, pos, objfile_func, data);
-    }
-
-  /* Invoke callbacks for TYPE and OBJFILE if they were set as non-NULL.  */
-
-  if (type && TYPE_OBJFILE (type)
-      && (*objfile_func) (TYPE_OBJFILE (type), data))
-    return 1;
-
-  return 0;
-}
-
-/* As for operator_length, but assumes PC is pointing at the first
-   element of the operator, and gives meaningful results only for the 
-   Ada-specific operators, returning 0 for *OPLENP and *ARGSP otherwise.  */
-
-static void
-ada_forward_operator_length (struct expression *exp, int pc,
-			     int *oplenp, int *argsp)
-{
-  switch (exp->elts[pc].opcode)
-    {
-    default:
-      *oplenp = *argsp = 0;
-      break;
-
-#define OP_DEFN(op, len, args, binop) \
-    case op: *oplenp = len; *argsp = args; break;
-      ADA_OPERATORS;
-#undef OP_DEFN
-
-    case OP_AGGREGATE:
-      *oplenp = 3;
-      *argsp = longest_to_int (exp->elts[pc + 1].longconst);
-      break;
-
-    case OP_CHOICES:
-      *oplenp = 3;
-      *argsp = longest_to_int (exp->elts[pc + 1].longconst) + 1;
-      break;
-
-    case OP_STRING:
-    case OP_NAME:
-      {
-	int len = longest_to_int (exp->elts[pc + 1].longconst);
-
-	*oplenp = 4 + BYTES_TO_EXP_ELEM (len + 1);
-	*argsp = 0;
-	break;
-      }
-    }
-}
-
-static int
-ada_dump_subexp_body (struct expression *exp, struct ui_file *stream, int elt)
-{
-  enum exp_opcode op = exp->elts[elt].opcode;
-  int oplen, nargs;
-  int pc = elt;
-  int i;
-
-  ada_forward_operator_length (exp, elt, &oplen, &nargs);
-
-  switch (op)
-    {
-      /* Ada attributes ('Foo).  */
-    case OP_ATR_FIRST:
-    case OP_ATR_LAST:
-    case OP_ATR_LENGTH:
-    case OP_ATR_IMAGE:
-    case OP_ATR_MAX:
-    case OP_ATR_MIN:
-    case OP_ATR_MODULUS:
-    case OP_ATR_POS:
-    case OP_ATR_SIZE:
-    case OP_ATR_TAG:
-    case OP_ATR_VAL:
-      break;
-
-    case UNOP_IN_RANGE:
-    case UNOP_QUAL:
-      /* XXX: gdb_sprint_host_address, type_sprint */
-      fprintf_filtered (stream, _("Type @"));
-      gdb_print_host_address (exp->elts[pc + 1].type, stream);
-      fprintf_filtered (stream, " (");
-      type_print (exp->elts[pc + 1].type, NULL, stream, 0);
-      fprintf_filtered (stream, ")");
-      break;
-    case BINOP_IN_BOUNDS:
-      fprintf_filtered (stream, " (%d)",
-			longest_to_int (exp->elts[pc + 2].longconst));
-      break;
-    case TERNOP_IN_RANGE:
-      break;
-
-    case OP_AGGREGATE:
-    case OP_OTHERS:
-    case OP_DISCRETE_RANGE:
-    case OP_POSITIONAL:
-    case OP_CHOICES:
-      break;
-
-    case OP_NAME:
-    case OP_STRING:
-      {
-	char *name = &exp->elts[elt + 2].string;
-	int len = longest_to_int (exp->elts[elt + 1].longconst);
-
-	fprintf_filtered (stream, "Text: `%.*s'", len, name);
-	break;
-      }
-
-    default:
-      return dump_subexp_body_standard (exp, stream, elt);
-    }
-
-  elt += oplen;
-  for (i = 0; i < nargs; i += 1)
-    elt = dump_subexp (exp, stream, elt);
-
-  return elt;
-}
-
-/* The Ada extension of print_subexp (q.v.).  */
-
-static void
-ada_print_subexp (struct expression *exp, int *pos,
-		  struct ui_file *stream, enum precedence prec)
-{
-  int oplen, nargs, i;
-  int pc = *pos;
-  enum exp_opcode op = exp->elts[pc].opcode;
-
-  ada_forward_operator_length (exp, pc, &oplen, &nargs);
-
-  *pos += oplen;
-  switch (op)
-    {
-    default:
-      *pos -= oplen;
-      print_subexp_standard (exp, pos, stream, prec);
-      return;
-
-    case OP_VAR_VALUE:
-      fputs_filtered (exp->elts[pc + 2].symbol->natural_name (), stream);
-      return;
-
-    case BINOP_IN_BOUNDS:
-      /* XXX: sprint_subexp */
-      print_subexp (exp, pos, stream, PREC_SUFFIX);
-      fputs_filtered (" in ", stream);
-      print_subexp (exp, pos, stream, PREC_SUFFIX);
-      fputs_filtered ("'range", stream);
-      if (exp->elts[pc + 1].longconst > 1)
-	fprintf_filtered (stream, "(%ld)",
-			  (long) exp->elts[pc + 1].longconst);
-      return;
-
-    case TERNOP_IN_RANGE:
-      if (prec >= PREC_EQUAL)
-	fputs_filtered ("(", stream);
-      /* XXX: sprint_subexp */
-      print_subexp (exp, pos, stream, PREC_SUFFIX);
-      fputs_filtered (" in ", stream);
-      print_subexp (exp, pos, stream, PREC_EQUAL);
-      fputs_filtered (" .. ", stream);
-      print_subexp (exp, pos, stream, PREC_EQUAL);
-      if (prec >= PREC_EQUAL)
-	fputs_filtered (")", stream);
-      return;
-
-    case OP_ATR_FIRST:
-    case OP_ATR_LAST:
-    case OP_ATR_LENGTH:
-    case OP_ATR_IMAGE:
-    case OP_ATR_MAX:
-    case OP_ATR_MIN:
-    case OP_ATR_MODULUS:
-    case OP_ATR_POS:
-    case OP_ATR_SIZE:
-    case OP_ATR_TAG:
-    case OP_ATR_VAL:
-      if (exp->elts[*pos].opcode == OP_TYPE)
-	{
-	  if (exp->elts[*pos + 1].type->code () != TYPE_CODE_VOID)
-	    LA_PRINT_TYPE (exp->elts[*pos + 1].type, "", stream, 0, 0,
-			   &type_print_raw_options);
-	  *pos += 3;
-	}
-      else
-	print_subexp (exp, pos, stream, PREC_SUFFIX);
-      fprintf_filtered (stream, "'%s", ada_attribute_name (op));
-      if (nargs > 1)
-	{
-	  int tem;
-
-	  for (tem = 1; tem < nargs; tem += 1)
-	    {
-	      fputs_filtered ((tem == 1) ? " (" : ", ", stream);
-	      print_subexp (exp, pos, stream, PREC_ABOVE_COMMA);
-	    }
-	  fputs_filtered (")", stream);
-	}
-      return;
-
-    case UNOP_QUAL:
-      type_print (exp->elts[pc + 1].type, "", stream, 0);
-      fputs_filtered ("'(", stream);
-      print_subexp (exp, pos, stream, PREC_PREFIX);
-      fputs_filtered (")", stream);
-      return;
-
-    case UNOP_IN_RANGE:
-      /* XXX: sprint_subexp */
-      print_subexp (exp, pos, stream, PREC_SUFFIX);
-      fputs_filtered (" in ", stream);
-      LA_PRINT_TYPE (exp->elts[pc + 1].type, "", stream, 1, 0,
-		     &type_print_raw_options);
-      return;
-
-    case OP_DISCRETE_RANGE:
-      print_subexp (exp, pos, stream, PREC_SUFFIX);
-      fputs_filtered ("..", stream);
-      print_subexp (exp, pos, stream, PREC_SUFFIX);
-      return;
-
-    case OP_OTHERS:
-      fputs_filtered ("others => ", stream);
-      print_subexp (exp, pos, stream, PREC_SUFFIX);
-      return;
-
-    case OP_CHOICES:
-      for (i = 0; i < nargs-1; i += 1)
-	{
-	  if (i > 0)
-	    fputs_filtered ("|", stream);
-	  print_subexp (exp, pos, stream, PREC_SUFFIX);
-	}
-      fputs_filtered (" => ", stream);
-      print_subexp (exp, pos, stream, PREC_SUFFIX);
-      return;
-      
-    case OP_POSITIONAL:
-      print_subexp (exp, pos, stream, PREC_SUFFIX);
-      return;
-
-    case OP_AGGREGATE:
-      fputs_filtered ("(", stream);
-      for (i = 0; i < nargs; i += 1)
-	{
-	  if (i > 0)
-	    fputs_filtered (", ", stream);
-	  print_subexp (exp, pos, stream, PREC_SUFFIX);
-	}
-      fputs_filtered (")", stream);
-      return;
-    }
-}
-
 /* Table mapping opcodes into strings for printing operators
    and precedences of the operators.  */
 
@@ -14658,14 +12941,6 @@ static const struct op_print ada_op_print_tab[] = {
 \f
 				/* Language vector */
 
-static const struct exp_descriptor ada_exp_descriptor = {
-  ada_print_subexp,
-  ada_operator_length,
-  ada_operator_check,
-  ada_dump_subexp_body,
-  ada_evaluate_subexp
-};
-
 /* symbol_name_matcher_ftype adapter for wild_match.  */
 
 static bool
@@ -15258,14 +13533,6 @@ class ada_language : public language_defn
   void post_parser (expression_up *expp, struct parser_state *ps)
     const override
   {
-    struct type *context_type = NULL;
-    int pc = 0;
-
-    if (ps->void_context_p)
-      context_type = builtin_type ((*expp)->gdbarch)->builtin_void;
-
-    resolve_subexp (expp, &pc, 1, context_type, ps->parse_completion,
-		    ps->block_tracker);
   }
 
   /* See language.h.  */
@@ -15332,11 +13599,6 @@ class ada_language : public language_defn
 
   /* See language.h.  */
 
-  const struct exp_descriptor *expression_ops () const override
-  { return &ada_exp_descriptor; }
-
-  /* See language.h.  */
-
   const struct op_print *opcode_print_table () const override
   { return ada_op_print_tab; }
 
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 189/203] Remove now-unused C evaluator code
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (187 preceding siblings ...)
  2021-01-01 21:47 ` [PATCH 188/203] Remove now-unused Ada " Tom Tromey
@ 2021-01-01 21:47 ` Tom Tromey
  2021-01-01 21:47 ` [PATCH 190/203] Remove union exp_element Tom Tromey
                   ` (14 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:47 UTC (permalink / raw)
  To: gdb-patches

Now that the C parser has switched to the new style, there is no need
for the old C evaluation code.  This affects some other languages that
were relying on the C code.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* opencl-lang.c (evaluate_subexp_opencl, exp_descriptor_opencl):
	Remove.
	(class opencl_language) <expression_ops>: Remove.
	* d-lang.c (class d_language) <expression_ops>: Remove.
	* c-lang.h (evaluate_subexp_c, exp_descriptor_c): Don't declare.
	* c-lang.c (evaluate_subexp_c, exp_descriptor_c): Remove.
	(class c_language, class cplus_language, class asm_language)
	(class minimal_language) <expression_ops>: Remove.
---
 gdb/ChangeLog     |  11 ++
 gdb/c-lang.c      | 180 -----------------------------
 gdb/c-lang.h      |   7 +-
 gdb/d-lang.c      |   5 -
 gdb/opencl-lang.c | 280 ----------------------------------------------
 5 files changed, 12 insertions(+), 471 deletions(-)

diff --git a/gdb/c-lang.c b/gdb/c-lang.c
index 07a17b62567..90ad90cab4e 100644
--- a/gdb/c-lang.c
+++ b/gdb/c-lang.c
@@ -580,157 +580,6 @@ parse_one_string (struct obstack *output, const char *data, int len,
     }
 }
 
-/* Expression evaluator for the C language family.  Most operations
-   are delegated to evaluate_subexp_standard; see that function for a
-   description of the arguments.  */
-
-struct value *
-evaluate_subexp_c (struct type *expect_type, struct expression *exp,
-		   int *pos, enum noside noside)
-{
-  enum exp_opcode op = exp->elts[*pos].opcode;
-
-  switch (op)
-    {
-    case OP_STRING:
-      {
-	int oplen, limit;
-	struct type *type;
-	struct value *result;
-	c_string_type dest_type;
-	const char *dest_charset;
-	int satisfy_expected = 0;
-
-	auto_obstack output;
-
-	++*pos;
-	oplen = longest_to_int (exp->elts[*pos].longconst);
-
-	++*pos;
-	limit = *pos + BYTES_TO_EXP_ELEM (oplen + 1);
-	dest_type = ((enum c_string_type_values)
-		     longest_to_int (exp->elts[*pos].longconst));
-	switch (dest_type & ~C_CHAR)
-	  {
-	  case C_STRING:
-	    type = language_string_char_type (exp->language_defn,
-					      exp->gdbarch);
-	    break;
-	  case C_WIDE_STRING:
-	    type = lookup_typename (exp->language_defn, "wchar_t", NULL, 0);
-	    break;
-	  case C_STRING_16:
-	    type = lookup_typename (exp->language_defn, "char16_t", NULL, 0);
-	    break;
-	  case C_STRING_32:
-	    type = lookup_typename (exp->language_defn, "char32_t", NULL, 0);
-	    break;
-	  default:
-	    internal_error (__FILE__, __LINE__, _("unhandled c_string_type"));
-	  }
-
-	/* Ensure TYPE_LENGTH is valid for TYPE.  */
-	check_typedef (type);
-
-	/* If the caller expects an array of some integral type,
-	   satisfy them.  If something odder is expected, rely on the
-	   caller to cast.  */
-	if (expect_type && expect_type->code () == TYPE_CODE_ARRAY)
-	  {
-	    struct type *element_type
-	      = check_typedef (TYPE_TARGET_TYPE (expect_type));
-
-	    if (element_type->code () == TYPE_CODE_INT
-		|| element_type->code () == TYPE_CODE_CHAR)
-	      {
-		type = element_type;
-		satisfy_expected = 1;
-	      }
-	  }
-
-	dest_charset = charset_for_string_type (dest_type, exp->gdbarch);
-
-	++*pos;
-	while (*pos < limit)
-	  {
-	    int len;
-
-	    len = longest_to_int (exp->elts[*pos].longconst);
-
-	    ++*pos;
-	    if (noside != EVAL_SKIP)
-	      parse_one_string (&output, &exp->elts[*pos].string, len,
-				dest_charset, type);
-	    *pos += BYTES_TO_EXP_ELEM (len);
-	  }
-
-	/* Skip the trailing length and opcode.  */
-	*pos += 2;
-
-	if (noside == EVAL_SKIP)
-	  {
-	    /* Return a dummy value of the appropriate type.  */
-	    if (expect_type != NULL)
-	      result = allocate_value (expect_type);
-	    else if ((dest_type & C_CHAR) != 0)
-	      result = allocate_value (type);
-	    else
-	      result = value_cstring ("", 0, type);
-	    return result;
-	  }
-
-	if ((dest_type & C_CHAR) != 0)
-	  {
-	    LONGEST value;
-
-	    if (obstack_object_size (&output) != TYPE_LENGTH (type))
-	      error (_("Could not convert character "
-		       "constant to target character set"));
-	    value = unpack_long (type, (gdb_byte *) obstack_base (&output));
-	    result = value_from_longest (type, value);
-	  }
-	else
-	  {
-	    int i;
-
-	    /* Write the terminating character.  */
-	    for (i = 0; i < TYPE_LENGTH (type); ++i)
-	      obstack_1grow (&output, 0);
-
-	    if (satisfy_expected)
-	      {
-		LONGEST low_bound, high_bound;
-		int element_size = TYPE_LENGTH (type);
-
-		if (!get_discrete_bounds (expect_type->index_type (),
-					  &low_bound, &high_bound))
-		  {
-		    low_bound = 0;
-		    high_bound = (TYPE_LENGTH (expect_type) / element_size) - 1;
-		  }
-		if (obstack_object_size (&output) / element_size
-		    > (high_bound - low_bound + 1))
-		  error (_("Too many array elements"));
-
-		result = allocate_value (expect_type);
-		memcpy (value_contents_raw (result), obstack_base (&output),
-			obstack_object_size (&output));
-	      }
-	    else
-	      result = value_cstring ((const char *) obstack_base (&output),
-				      obstack_object_size (&output),
-				      type);
-	  }
-	return result;
-      }
-      break;
-
-    default:
-      break;
-    }
-  return evaluate_subexp_standard (expect_type, exp, pos, noside);
-}
-
 namespace expr
 {
 
@@ -970,15 +819,6 @@ c_language_arch_info (struct gdbarch *gdbarch,
   lai->set_bool_type (builtin->builtin_int);
 }
 
-const struct exp_descriptor exp_descriptor_c = 
-{
-  print_subexp_standard,
-  operator_length_standard,
-  operator_check_standard,
-  dump_subexp_body_standard,
-  evaluate_subexp_c
-};
-
 /* Class representing the C language.  */
 
 class c_language : public language_defn
@@ -1050,11 +890,6 @@ class c_language : public language_defn
 
   /* See language.h.  */
 
-  const struct exp_descriptor *expression_ops () const override
-  { return &exp_descriptor_c; }
-
-  /* See language.h.  */
-
   const struct op_print *opcode_print_table () const override
   { return c_op_print_tab; }
 };
@@ -1233,11 +1068,6 @@ class cplus_language : public language_defn
 
   /* See language.h.  */
 
-  const struct exp_descriptor *expression_ops () const override
-  { return &exp_descriptor_c; }
-
-  /* See language.h.  */
-
   const struct op_print *opcode_print_table () const override
   { return c_op_print_tab; }
 
@@ -1314,11 +1144,6 @@ class asm_language : public language_defn
 
   /* See language.h.  */
 
-  const struct exp_descriptor *expression_ops () const override
-  { return &exp_descriptor_c; }
-
-  /* See language.h.  */
-
   const struct op_print *opcode_print_table () const override
   { return c_op_print_tab; }
 };
@@ -1376,11 +1201,6 @@ class minimal_language : public language_defn
 
   /* See language.h.  */
 
-  const struct exp_descriptor *expression_ops () const override
-  { return &exp_descriptor_c; }
-
-  /* See language.h.  */
-
   const struct op_print *opcode_print_table () const override
   { return c_op_print_tab; }
 };
diff --git a/gdb/c-lang.h b/gdb/c-lang.h
index 5dfd73123f8..a46957d0d84 100644
--- a/gdb/c-lang.h
+++ b/gdb/c-lang.h
@@ -90,10 +90,7 @@ extern void c_value_print (struct value *, struct ui_file *,
 
 /* These are in c-lang.c: */
 
-extern struct value *evaluate_subexp_c (struct type *expect_type,
-					struct expression *exp,
-					int *pos,
-					enum noside noside);
+extern void c_printchar (int, struct type *, struct ui_file *);
 
 extern void c_printstr (struct ui_file * stream,
 			struct type *elttype,
@@ -106,8 +103,6 @@ extern void c_printstr (struct ui_file * stream,
 extern void c_language_arch_info (struct gdbarch *gdbarch,
 				  struct language_arch_info *lai);
 
-extern const struct exp_descriptor exp_descriptor_c;
-
 extern void c_emit_char (int c, struct type *type,
 			 struct ui_file *stream, int quoter);
 
diff --git a/gdb/d-lang.c b/gdb/d-lang.c
index 65ee7409c80..4488c10e609 100644
--- a/gdb/d-lang.c
+++ b/gdb/d-lang.c
@@ -219,11 +219,6 @@ class d_language : public language_defn
 
   /* See language.h.  */
 
-  const struct exp_descriptor *expression_ops () const override
-  { return &exp_descriptor_c; }
-
-  /* See language.h.  */
-
   const struct op_print *opcode_print_table () const override
   { return d_op_print_tab; }
 };
diff --git a/gdb/opencl-lang.c b/gdb/opencl-lang.c
index c5150953022..b283be173c4 100644
--- a/gdb/opencl-lang.c
+++ b/gdb/opencl-lang.c
@@ -692,272 +692,6 @@ eval_opencl_assign (struct type *expect_type, struct expression *exp,
   return value_assign (arg1, arg2);
 }
 
-/* Expression evaluator for the OpenCL.  Most operations are delegated to
-   evaluate_subexp_standard; see that function for a description of the
-   arguments.  */
-
-static struct value *
-evaluate_subexp_opencl (struct type *expect_type, struct expression *exp,
-		   int *pos, enum noside noside)
-{
-  enum exp_opcode op = exp->elts[*pos].opcode;
-  struct value *arg1 = NULL;
-  struct value *arg2 = NULL;
-  struct type *type1, *type2;
-
-  switch (op)
-    {
-    /* Handle assignment and cast operators to support OpenCL-style
-       scalar-to-vector widening.  */
-    case BINOP_ASSIGN:
-      (*pos)++;
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      type1 = value_type (arg1);
-      arg2 = evaluate_subexp (type1, exp, pos, noside);
-
-      return eval_opencl_assign (expect_type, exp, noside, op, arg1, arg2);
-
-    case UNOP_CAST:
-      type1 = exp->elts[*pos + 1].type;
-      (*pos) += 2;
-      arg1 = evaluate_subexp (type1, exp, pos, noside);
-
-      if (noside == EVAL_SKIP)
-	return value_from_longest (builtin_type (exp->gdbarch)->
-				   builtin_int, 1);
-
-      return opencl_value_cast (type1, arg1);
-
-    case UNOP_CAST_TYPE:
-      (*pos)++;
-      arg1 = evaluate_subexp (NULL, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
-      type1 = value_type (arg1);
-      arg1 = evaluate_subexp (type1, exp, pos, noside);
-
-      if (noside == EVAL_SKIP)
-	return value_from_longest (builtin_type (exp->gdbarch)->
-				   builtin_int, 1);
-
-      return opencl_value_cast (type1, arg1);
-
-    /* Handle binary relational and equality operators that are either not
-       or differently defined for GNU vectors.  */
-    case BINOP_EQUAL:
-    case BINOP_NOTEQUAL:
-    case BINOP_LESS:
-    case BINOP_GTR:
-    case BINOP_GEQ:
-    case BINOP_LEQ:
-      (*pos)++;
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      arg2 = evaluate_subexp (value_type (arg1), exp, pos, noside);
-
-      if (noside == EVAL_SKIP)
-	return value_from_longest (builtin_type (exp->gdbarch)->
-				   builtin_int, 1);
-
-      return opencl_relop (expect_type, exp, noside, op, arg1, arg2);
-
-    /* Handle the logical unary operator not(!).  */
-    case UNOP_LOGICAL_NOT:
-      (*pos)++;
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-
-      if (noside == EVAL_SKIP)
-	return value_from_longest (builtin_type (exp->gdbarch)->
-				   builtin_int, 1);
-
-      return opencl_logical_not (expect_type, exp, noside, op, arg1);
-
-    /* Handle the logical operator and(&&) and or(||).  */
-    case BINOP_LOGICAL_AND:
-    case BINOP_LOGICAL_OR:
-      (*pos)++;
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-
-      if (noside == EVAL_SKIP)
-	{
-	  evaluate_subexp (nullptr, exp, pos, noside);
-
-	  return value_from_longest (builtin_type (exp->gdbarch)->
-				     builtin_int, 1);
-	}
-      else
-	{
-	  /* For scalar operations we need to avoid evaluating operands
-	     unnecessarily.  However, for vector operations we always need to
-	     evaluate both operands.  Unfortunately we only know which of the
-	     two cases apply after we know the type of the second operand.
-	     Therefore we evaluate it once using EVAL_AVOID_SIDE_EFFECTS.  */
-	  int oldpos = *pos;
-
-	  arg2 = evaluate_subexp (nullptr, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
-	  *pos = oldpos;
-	  type1 = check_typedef (value_type (arg1));
-	  type2 = check_typedef (value_type (arg2));
-
-	  if ((type1->code () == TYPE_CODE_ARRAY && type1->is_vector ())
-	      || (type2->code () == TYPE_CODE_ARRAY && type2->is_vector ()))
-	    {
-	      arg2 = evaluate_subexp (nullptr, exp, pos, noside);
-
-	      return opencl_relop (nullptr, exp, noside, op, arg1, arg2);
-	    }
-	  else
-	    {
-	      /* For scalar built-in types, only evaluate the right
-		 hand operand if the left hand operand compares
-		 unequal(&&)/equal(||) to 0.  */
-	      int res;
-	      int tmp = value_logical_not (arg1);
-
-	      if (op == BINOP_LOGICAL_OR)
-		tmp = !tmp;
-
-	      arg2
-		= evaluate_subexp (nullptr, exp, pos, tmp ? EVAL_SKIP : noside);
-	      type1 = language_bool_type (exp->language_defn, exp->gdbarch);
-
-	      if (op == BINOP_LOGICAL_AND)
-		res = !tmp && !value_logical_not (arg2);
-	      else /* BINOP_LOGICAL_OR */
-		res = tmp || !value_logical_not (arg2);
-
-	      return value_from_longest (type1, res);
-	    }
-	}
-
-    /* Handle the ternary selection operator.  */
-    case TERNOP_COND:
-      (*pos)++;
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      type1 = check_typedef (value_type (arg1));
-      if (type1->code () == TYPE_CODE_ARRAY && type1->is_vector ())
-	{
-	  struct value *arg3, *tmp, *ret;
-	  struct type *eltype2, *type3, *eltype3;
-	  int t2_is_vec, t3_is_vec, i;
-	  LONGEST lowb1, lowb2, lowb3, highb1, highb2, highb3;
-
-	  arg2 = evaluate_subexp (nullptr, exp, pos, noside);
-	  arg3 = evaluate_subexp (nullptr, exp, pos, noside);
-	  type2 = check_typedef (value_type (arg2));
-	  type3 = check_typedef (value_type (arg3));
-	  t2_is_vec
-	    = type2->code () == TYPE_CODE_ARRAY && type2->is_vector ();
-	  t3_is_vec
-	    = type3->code () == TYPE_CODE_ARRAY && type3->is_vector ();
-
-	  /* Widen the scalar operand to a vector if necessary.  */
-	  if (t2_is_vec || !t3_is_vec)
-	    {
-	      arg3 = opencl_value_cast (type2, arg3);
-	      type3 = value_type (arg3);
-	    }
-	  else if (!t2_is_vec || t3_is_vec)
-	    {
-	      arg2 = opencl_value_cast (type3, arg2);
-	      type2 = value_type (arg2);
-	    }
-	  else if (!t2_is_vec || !t3_is_vec)
-	    {
-	      /* Throw an error if arg2 or arg3 aren't vectors.  */
-	      error (_("\
-Cannot perform conditional operation on incompatible types"));
-	    }
-
-	  eltype2 = check_typedef (TYPE_TARGET_TYPE (type2));
-	  eltype3 = check_typedef (TYPE_TARGET_TYPE (type3));
-
-	  if (!get_array_bounds (type1, &lowb1, &highb1)
-	      || !get_array_bounds (type2, &lowb2, &highb2)
-	      || !get_array_bounds (type3, &lowb3, &highb3))
-	    error (_("Could not determine the vector bounds"));
-
-	  /* Throw an error if the types of arg2 or arg3 are incompatible.  */
-	  if (eltype2->code () != eltype3->code ()
-	      || TYPE_LENGTH (eltype2) != TYPE_LENGTH (eltype3)
-	      || eltype2->is_unsigned () != eltype3->is_unsigned ()
-	      || lowb2 != lowb3 || highb2 != highb3)
-	    error (_("\
-Cannot perform operation on vectors with different types"));
-
-	  /* Throw an error if the sizes of arg1 and arg2/arg3 differ.  */
-	  if (lowb1 != lowb2 || lowb1 != lowb3
-	      || highb1 != highb2 || highb1 != highb3)
-	    error (_("\
-Cannot perform conditional operation on vectors with different sizes"));
-
-	  ret = allocate_value (type2);
-
-	  for (i = 0; i < highb1 - lowb1 + 1; i++)
-	    {
-	      tmp = value_logical_not (value_subscript (arg1, i)) ?
-		    value_subscript (arg3, i) : value_subscript (arg2, i);
-	      memcpy (value_contents_writeable (ret) +
-		      i * TYPE_LENGTH (eltype2), value_contents_all (tmp),
-		      TYPE_LENGTH (eltype2));
-	    }
-
-	  return ret;
-	}
-      else
-	{
-	  if (value_logical_not (arg1))
-	    {
-	      /* Skip the second operand.  */
-	      evaluate_subexp (nullptr, exp, pos, EVAL_SKIP);
-
-	      return evaluate_subexp (nullptr, exp, pos, noside);
-	    }
-	  else
-	    {
-	      /* Skip the third operand.  */
-	      arg2 = evaluate_subexp (nullptr, exp, pos, noside);
-	      evaluate_subexp (nullptr, exp, pos, EVAL_SKIP);
-
-	      return arg2;
-	    }
-	}
-
-    /* Handle STRUCTOP_STRUCT to allow component access on OpenCL vectors.  */
-    case STRUCTOP_STRUCT:
-      {
-	int pc = (*pos)++;
-	int tem = longest_to_int (exp->elts[pc + 1].longconst);
-
-	(*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1);
-	arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-	type1 = check_typedef (value_type (arg1));
-
-	if (noside == EVAL_SKIP)
-	  {
-	    return value_from_longest (builtin_type (exp->gdbarch)->
-				       builtin_int, 1);
-	  }
-	else if (type1->code () == TYPE_CODE_ARRAY && type1->is_vector ())
-	  {
-	    return opencl_component_ref (exp, arg1, &exp->elts[pc + 2].string,
-					 noside);
-	  }
-	else
-	  {
-	    struct value *v = value_struct_elt (&arg1, NULL,
-						&exp->elts[pc + 2].string, NULL,
-						"structure");
-
-	    if (noside == EVAL_AVOID_SIDE_EFFECTS)
-	      v = value_zero (value_type (v), VALUE_LVAL (v));
-	    return v;
-	  }
-      }
-    default:
-      break;
-    }
-
-  return evaluate_subexp_c (expect_type, exp, pos, noside);
-}
-
 namespace expr
 {
 
@@ -1119,15 +853,6 @@ Cannot perform conditional operation on vectors with different sizes"));
 
 } /* namespace expr */
 
-const struct exp_descriptor exp_descriptor_opencl =
-{
-  print_subexp_standard,
-  operator_length_standard,
-  operator_check_standard,
-  dump_subexp_body_standard,
-  evaluate_subexp_opencl
-};
-
 /* Class representing the OpenCL language.  */
 
 class opencl_language : public language_defn
@@ -1251,11 +976,6 @@ class opencl_language : public language_defn
 
   /* See language.h.  */
 
-  const struct exp_descriptor *expression_ops () const override
-  { return &exp_descriptor_opencl; }
-
-  /* See language.h.  */
-
   const struct op_print *opcode_print_table () const override
   { return c_op_print_tab; }
 };
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 190/203] Remove union exp_element
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (188 preceding siblings ...)
  2021-01-01 21:47 ` [PATCH 189/203] Remove now-unused C " Tom Tromey
@ 2021-01-01 21:47 ` Tom Tromey
  2021-01-01 21:47 ` [PATCH 191/203] Remove two Ada opcodes Tom Tromey
                   ` (13 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:47 UTC (permalink / raw)
  To: gdb-patches

This removes union exp_element functions that either create such
elements or walk them.  struct expression no longer holds
exp_elements.  A couple of language_defn methods are also removed, as
they are obsolete.

Note that this patch also removes the print_expression code.  The only
in-tree caller of this was from dump_prefix_expression, which is only
called when expression debugging is enabled.  Implementing this would
involve a fair amount of code, and it seems to me that prefix dumping
is preferable anyway, as it is unambiguous.  So, I have not
reimplemented this feature.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* value.h (evaluate_subexp_with_coercion): Don't declare.
	* parse.c (exp_descriptor_standard): Remove.
	(expr_builder::expr_builder, expr_builder::release): Update.
	(expression::expression): Remove size_t parameter.
	(expression::~expression): Simplify.
	(expression::resize): Remove.
	(write_exp_elt, write_exp_elt_opcode, write_exp_elt_sym)
	(write_exp_elt_msym, write_exp_elt_block, write_exp_elt_objfile)
	(write_exp_elt_longcst, write_exp_elt_floatcst)
	(write_exp_elt_type, write_exp_elt_intern, write_exp_string)
	(write_exp_string_vector, write_exp_bitstring): Remove.
	* p-lang.h (class pascal_language) <opcode_print_table,
	op_print_tab>: Remove.
	* p-lang.c (pascal_language::op_print_tab): Remove.
	* opencl-lang.c (class opencl_language) <opcode_print_table>:
	Remove.
	* objc-lang.c (objc_op_print_tab): Remove.
	(class objc_language) <opcode_print_table>: Remove.
	* m2-lang.h (class m2_language) <opcode_print_table,
	op_print_tab>: Remove.
	* m2-lang.c (m2_language::op_print_tab): Remove.
	* language.h (struct language_defn) <post_parser, expression_ops,
	opcode_print_table>: Remove.
	* language.c (language_defn::expression_ops)
	(auto_or_unknown_language::opcode_print_table): Remove.
	* go-lang.h (class go_language) <expression_ops,
	opcode_print_table, op_print_tab>: Remove.
	* go-lang.c (go_language::expression_ops): Remove.
	(go_language::op_print_tab): Remove.
	* f-lang.h (class f_language) <opcode_print_table>: Remove
	<op_print_tab>: Remove.
	* f-lang.c (f_language::op_print_tab): Remove.
	* expression.h (union exp_element): Remove.
	(struct expression): Remove size_t parameter from constructor.
	<resize>: Remove.
	<first_opcode>: Update.
	<nelts, elts>: Remove.
	(EXP_ELEM_TO_BYTES, BYTES_TO_EXP_ELEM): Remove.
	(evaluate_subexp_standard, print_expression, op_string)
	(dump_raw_expression): Don't declare.
	* expprint.c (print_expression, print_subexp)
	(print_subexp_funcall, print_subexp_standard, op_string)
	(dump_raw_expression, dump_subexp, dump_subexp_body)
	(dump_subexp_body_funcall, dump_subexp_body_standard): Remove.
	(dump_prefix_expression): Update.
	* eval.c (evaluate_subexp, evaluate_expression, evaluate_type):
	Update.
	(evaluate_subexpression_type): Remove.
	(fetch_subexp_value): Remove "pc" parameter.  Update.
	(extract_field_op, evaluate_struct_tuple, evaluate_funcall)
	(evaluate_subexp_standard, evaluate_subexp_for_address)
	(evaluate_subexp_with_coercion, evaluate_subexp_for_sizeof)
	(evaluate_subexp_for_cast): Remove.
	(parse_and_eval_type): Update.
	* dtrace-probe.c (dtrace_probe::compile_to_ax): Update.
	* d-lang.c (d_op_print_tab): Remove.
	(class d_language) <opcode_print_table>: Remove.
	* c-lang.h (c_op_print_tab): Don't declare.
	* c-lang.c (c_op_print_tab): Remove.
	(class c_language, class cplus_language, class asm_language, class
	minimal_language) <opcode_print_table>: Remove.
	* breakpoint.c (update_watchpoint, watchpoint_check)
	(watchpoint_exp_is_const, watch_command_1): Update.
	* ax-gdb.h (union exp_element): Don't declare.
	* ax-gdb.c (const_var_ref, const_expr, maybe_const_expr)
	(gen_repeat, gen_sizeof, gen_expr_for_cast, gen_expr)
	(gen_expr_binop_rest): Remove.
	(gen_trace_for_expr, gen_eval_for_expr, gen_printf): Update.
	* ada-lang.c (ada_op_print_tab): Remove.
	(class ada_language) <post_parser, opcode_print_table>: Remove.
---
 gdb/ChangeLog       |   73 ++
 gdb/ada-lang.c      |   58 --
 gdb/ax-gdb.c        |  735 +------------------
 gdb/ax-gdb.h        |    1 -
 gdb/breakpoint.c    |  118 +---
 gdb/c-lang.c        |   59 --
 gdb/c-lang.h        |    2 -
 gdb/d-lang.c        |   43 --
 gdb/dtrace-probe.c  |   10 +-
 gdb/eval.c          | 1629 +------------------------------------------
 gdb/expprint.c      | 1110 +----------------------------
 gdb/expression.h    |   58 +-
 gdb/f-lang.c        |   28 -
 gdb/f-lang.h        |    9 -
 gdb/go-lang.c       |   46 --
 gdb/go-lang.h       |   16 -
 gdb/language.c      |   20 -
 gdb/language.h      |   20 -
 gdb/m2-lang.c       |   37 -
 gdb/m2-lang.h       |    9 -
 gdb/objc-lang.c     |   43 --
 gdb/opencl-lang.c   |    5 -
 gdb/p-lang.c        |   34 -
 gdb/p-lang.h        |    9 -
 gdb/parse.c         |  971 +-------------------------
 gdb/parser-defs.h   |  179 -----
 gdb/ppc-linux-nat.c |   25 +-
 gdb/printcmd.c      |    8 +-
 gdb/rust-lang.h     |    5 -
 gdb/stap-probe.c    |    7 +-
 gdb/tracepoint.c    |   56 +-
 gdb/value.c         |   30 +-
 gdb/value.h         |   14 +-
 33 files changed, 151 insertions(+), 5316 deletions(-)

diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index c7d9540798d..e7bfe9967e9 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -12901,43 +12901,6 @@ info_exceptions_command (const char *regexp, int from_tty)
     printf_filtered ("%s: %s\n", info.name, paddress (gdbarch, info.addr));
 }
 
-/* Table mapping opcodes into strings for printing operators
-   and precedences of the operators.  */
-
-static const struct op_print ada_op_print_tab[] = {
-  {":=", BINOP_ASSIGN, PREC_ASSIGN, 1},
-  {"or else", BINOP_LOGICAL_OR, PREC_LOGICAL_OR, 0},
-  {"and then", BINOP_LOGICAL_AND, PREC_LOGICAL_AND, 0},
-  {"or", BINOP_BITWISE_IOR, PREC_BITWISE_IOR, 0},
-  {"xor", BINOP_BITWISE_XOR, PREC_BITWISE_XOR, 0},
-  {"and", BINOP_BITWISE_AND, PREC_BITWISE_AND, 0},
-  {"=", BINOP_EQUAL, PREC_EQUAL, 0},
-  {"/=", BINOP_NOTEQUAL, PREC_EQUAL, 0},
-  {"<=", BINOP_LEQ, PREC_ORDER, 0},
-  {">=", BINOP_GEQ, PREC_ORDER, 0},
-  {">", BINOP_GTR, PREC_ORDER, 0},
-  {"<", BINOP_LESS, PREC_ORDER, 0},
-  {">>", BINOP_RSH, PREC_SHIFT, 0},
-  {"<<", BINOP_LSH, PREC_SHIFT, 0},
-  {"+", BINOP_ADD, PREC_ADD, 0},
-  {"-", BINOP_SUB, PREC_ADD, 0},
-  {"&", BINOP_CONCAT, PREC_ADD, 0},
-  {"*", BINOP_MUL, PREC_MUL, 0},
-  {"/", BINOP_DIV, PREC_MUL, 0},
-  {"rem", BINOP_REM, PREC_MUL, 0},
-  {"mod", BINOP_MOD, PREC_MUL, 0},
-  {"**", BINOP_EXP, PREC_REPEAT, 0},
-  {"@", BINOP_REPEAT, PREC_REPEAT, 0},
-  {"-", UNOP_NEG, PREC_PREFIX, 0},
-  {"+", UNOP_PLUS, PREC_PREFIX, 0},
-  {"not ", UNOP_LOGICAL_NOT, PREC_PREFIX, 0},
-  {"not ", UNOP_COMPLEMENT, PREC_PREFIX, 0},
-  {"abs ", UNOP_ABS, PREC_PREFIX, 0},
-  {".all", UNOP_IND, PREC_SUFFIX, 1},
-  {"'access", UNOP_ADDR, PREC_SUFFIX, 1},
-  {"'size", OP_ATR_SIZE, PREC_SUFFIX, 1},
-  {NULL, OP_NULL, PREC_SUFFIX, 0}
-};
 \f
 				/* Language vector */
 
@@ -13519,22 +13482,6 @@ class ada_language : public language_defn
     return ada_parse (ps);
   }
 
-  /* See language.h.
-
-     Same as evaluate_type (*EXP), but resolves ambiguous symbol references
-     (marked by OP_VAR_VALUE nodes in which the symbol has an undefined
-     namespace) and converts operators that are user-defined into
-     appropriate function calls.  If CONTEXT_TYPE is non-null, it provides
-     a preferred result type [at the moment, only type void has any
-     effect---causing procedures to be preferred over functions in calls].
-     A null CONTEXT_TYPE indicates that a non-void return type is
-     preferred.  May change (expand) *EXP.  */
-
-  void post_parser (expression_up *expp, struct parser_state *ps)
-    const override
-  {
-  }
-
   /* See language.h.  */
 
   void emitchar (int ch, struct type *chtype,
@@ -13597,11 +13544,6 @@ class ada_language : public language_defn
   const struct lang_varobj_ops *varobj_ops () const override
   { return &ada_varobj_ops; }
 
-  /* See language.h.  */
-
-  const struct op_print *opcode_print_table () const override
-  { return ada_op_print_tab; }
-
 protected:
   /* See language.h.  */
 
diff --git a/gdb/ax-gdb.c b/gdb/ax-gdb.c
index d2f50bbec7b..788be528d1b 100644
--- a/gdb/ax-gdb.c
+++ b/gdb/ax-gdb.c
@@ -70,14 +70,9 @@
 /* Prototypes for local functions.  */
 
 /* There's a standard order to the arguments of these functions:
-   union exp_element ** --- pointer into expression
    struct agent_expr * --- agent expression buffer to generate code into
    struct axs_value * --- describes value left on top of stack  */
 
-static struct value *const_var_ref (struct symbol *var);
-static struct value *const_expr (union exp_element **pc);
-static struct value *maybe_const_expr (union exp_element **pc);
-
 static void gen_traced_pop (struct agent_expr *, struct axs_value *);
 
 static void gen_sign_extend (struct agent_expr *, struct type *);
@@ -148,123 +143,13 @@ static void gen_struct_ref (struct agent_expr *ax,
 			    const char *operand_name);
 static void gen_static_field (struct agent_expr *ax, struct axs_value *value,
 			      struct type *type, int fieldno);
-static void gen_repeat (struct expression *exp, union exp_element **pc,
-			struct agent_expr *ax, struct axs_value *value);
-static void gen_sizeof (struct expression *exp, union exp_element **pc,
-			struct agent_expr *ax, struct axs_value *value,
-			struct type *size_type);
-static void gen_expr_binop_rest (struct expression *exp,
-				 enum exp_opcode op, union exp_element **pc,
-				 struct agent_expr *ax,
-				 struct axs_value *value,
-				 struct axs_value *value1,
-				 struct axs_value *value2);
 static void gen_expr_binop_rest (struct expression *exp,
 				 enum exp_opcode op,
 				 struct agent_expr *ax,
 				 struct axs_value *value,
 				 struct axs_value *value1,
 				 struct axs_value *value2);
-\f
-
-/* Detecting constant expressions.  */
-
-/* If the variable reference at *PC is a constant, return its value.
-   Otherwise, return zero.
-
-   Hey, Wally!  How can a variable reference be a constant?
-
-   Well, Beav, this function really handles the OP_VAR_VALUE operator,
-   not specifically variable references.  GDB uses OP_VAR_VALUE to
-   refer to any kind of symbolic reference: function names, enum
-   elements, and goto labels are all handled through the OP_VAR_VALUE
-   operator, even though they're constants.  It makes sense given the
-   situation.
-
-   Gee, Wally, don'cha wonder sometimes if data representations that
-   subvert commonly accepted definitions of terms in favor of heavily
-   context-specific interpretations are really just a tool of the
-   programming hegemony to preserve their power and exclude the
-   proletariat?  */
-
-static struct value *
-const_var_ref (struct symbol *var)
-{
-  struct type *type = SYMBOL_TYPE (var);
-
-  switch (SYMBOL_CLASS (var))
-    {
-    case LOC_CONST:
-      return value_from_longest (type, (LONGEST) SYMBOL_VALUE (var));
-
-    case LOC_LABEL:
-      return value_from_pointer (type, (CORE_ADDR) SYMBOL_VALUE_ADDRESS (var));
-
-    default:
-      return 0;
-    }
-}
-
-
-/* If the expression starting at *PC has a constant value, return it.
-   Otherwise, return zero.  If we return a value, then *PC will be
-   advanced to the end of it.  If we return zero, *PC could be
-   anywhere.  */
-static struct value *
-const_expr (union exp_element **pc)
-{
-  enum exp_opcode op = (*pc)->opcode;
-  struct value *v1;
-
-  switch (op)
-    {
-    case OP_LONG:
-      {
-	struct type *type = (*pc)[1].type;
-	LONGEST k = (*pc)[2].longconst;
-
-	(*pc) += 4;
-	return value_from_longest (type, k);
-      }
-
-    case OP_VAR_VALUE:
-      {
-	struct value *v = const_var_ref ((*pc)[2].symbol);
-
-	(*pc) += 4;
-	return v;
-      }
-
-      /* We could add more operators in here.  */
-
-    case UNOP_NEG:
-      (*pc)++;
-      v1 = const_expr (pc);
-      if (v1)
-	return value_neg (v1);
-      else
-	return 0;
-
-    default:
-      return 0;
-    }
-}
 
-
-/* Like const_expr, but guarantee also that *PC is undisturbed if the
-   expression is not constant.  */
-static struct value *
-maybe_const_expr (union exp_element **pc)
-{
-  union exp_element *tentative_pc = *pc;
-  struct value *v = const_expr (&tentative_pc);
-
-  /* If we got a value, then update the real PC.  */
-  if (v)
-    *pc = tentative_pc;
-
-  return v;
-}
 \f
 
 /* Generating bytecode from GDB expressions: general assumptions */
@@ -1691,592 +1576,8 @@ gen_aggregate_elt_ref (struct agent_expr *ax, struct axs_value *value,
   return 0;
 }
 
-/* Generate code for GDB's magical `repeat' operator.
-   LVALUE @ INT creates an array INT elements long, and whose elements
-   have the same type as LVALUE, located in memory so that LVALUE is
-   its first element.  For example, argv[0]@argc gives you the array
-   of command-line arguments.
-
-   Unfortunately, because we have to know the types before we actually
-   have a value for the expression, we can't implement this perfectly
-   without changing the type system, having values that occupy two
-   stack slots, doing weird things with sizeof, etc.  So we require
-   the right operand to be a constant expression.  */
-static void
-gen_repeat (struct expression *exp, union exp_element **pc,
-	    struct agent_expr *ax, struct axs_value *value)
-{
-  struct axs_value value1;
-
-  /* We don't want to turn this into an rvalue, so no conversions
-     here.  */
-  gen_expr (exp, pc, ax, &value1);
-  if (value1.kind != axs_lvalue_memory)
-    error (_("Left operand of `@' must be an object in memory."));
-
-  /* Evaluate the length; it had better be a constant.  */
-  {
-    struct value *v = const_expr (pc);
-    int length;
-
-    if (!v)
-      error (_("Right operand of `@' must be a "
-	       "constant, in agent expressions."));
-    if (value_type (v)->code () != TYPE_CODE_INT)
-      error (_("Right operand of `@' must be an integer."));
-    length = value_as_long (v);
-    if (length <= 0)
-      error (_("Right operand of `@' must be positive."));
-
-    /* The top of the stack is already the address of the object, so
-       all we need to do is frob the type of the lvalue.  */
-    {
-      /* FIXME-type-allocation: need a way to free this type when we are
-	 done with it.  */
-      struct type *array
-	= lookup_array_range_type (value1.type, 0, length - 1);
-
-      value->kind = axs_lvalue_memory;
-      value->type = array;
-    }
-  }
-}
-
-
-/* Emit code for the `sizeof' operator.
-   *PC should point at the start of the operand expression; we advance it
-   to the first instruction after the operand.  */
-static void
-gen_sizeof (struct expression *exp, union exp_element **pc,
-	    struct agent_expr *ax, struct axs_value *value,
-	    struct type *size_type)
-{
-  /* We don't care about the value of the operand expression; we only
-     care about its type.  However, in the current arrangement, the
-     only way to find an expression's type is to generate code for it.
-     So we generate code for the operand, and then throw it away,
-     replacing it with code that simply pushes its size.  */
-  int start = ax->len;
-
-  gen_expr (exp, pc, ax, value);
-
-  /* Throw away the code we just generated.  */
-  ax->len = start;
-
-  ax_const_l (ax, TYPE_LENGTH (value->type));
-  value->kind = axs_rvalue;
-  value->type = size_type;
-}
 \f
 
-/* Generate bytecode for a cast to TO_TYPE.  Advance *PC over the
-   subexpression.  */
-
-static void
-gen_expr_for_cast (struct expression *exp, union exp_element **pc,
-		   struct agent_expr *ax, struct axs_value *value,
-		   struct type *to_type)
-{
-  enum exp_opcode op = (*pc)[0].opcode;
-
-  /* Don't let symbols be handled with gen_expr because that throws an
-     "unknown type" error for no-debug data symbols.  Instead, we want
-     the cast to reinterpret such symbols.  */
-  if (op == OP_VAR_MSYM_VALUE || op == OP_VAR_VALUE)
-    {
-      if (op == OP_VAR_VALUE)
-	{
-	  gen_var_ref (ax, value, (*pc)[2].symbol);
-
-	  if (value->optimized_out)
-	    error (_("`%s' has been optimized out, cannot use"),
-		   (*pc)[2].symbol->print_name ());
-	}
-      else
-	gen_msym_var_ref (ax, value, (*pc)[2].msymbol, (*pc)[1].objfile);
-      if (value->type->code () == TYPE_CODE_ERROR)
-	value->type = to_type;
-      (*pc) += 4;
-    }
-  else
-    gen_expr (exp, pc, ax, value);
-  gen_cast (ax, value, to_type);
-}
-
-/* Generating bytecode from GDB expressions: general recursive thingy  */
-
-/* XXX: i18n */
-/* A gen_expr function written by a Gen-X'er guy.
-   Append code for the subexpression of EXPR starting at *POS_P to AX.  */
-void
-gen_expr (struct expression *exp, union exp_element **pc,
-	  struct agent_expr *ax, struct axs_value *value)
-{
-  /* Used to hold the descriptions of operand expressions.  */
-  struct axs_value value1, value2, value3;
-  enum exp_opcode op = (*pc)[0].opcode, op2;
-  int if1, go1, if2, go2, end;
-  struct type *int_type = builtin_type (ax->gdbarch)->builtin_int;
-
-  /* If we're looking at a constant expression, just push its value.  */
-  {
-    struct value *v = maybe_const_expr (pc);
-
-    if (v)
-      {
-	ax_const_l (ax, value_as_long (v));
-	value->kind = axs_rvalue;
-	value->type = check_typedef (value_type (v));
-	return;
-      }
-  }
-
-  /* Otherwise, go ahead and generate code for it.  */
-  switch (op)
-    {
-      /* Binary arithmetic operators.  */
-    case BINOP_ADD:
-    case BINOP_SUB:
-    case BINOP_MUL:
-    case BINOP_DIV:
-    case BINOP_REM:
-    case BINOP_LSH:
-    case BINOP_RSH:
-    case BINOP_SUBSCRIPT:
-    case BINOP_BITWISE_AND:
-    case BINOP_BITWISE_IOR:
-    case BINOP_BITWISE_XOR:
-    case BINOP_EQUAL:
-    case BINOP_NOTEQUAL:
-    case BINOP_LESS:
-    case BINOP_GTR:
-    case BINOP_LEQ:
-    case BINOP_GEQ:
-      (*pc)++;
-      gen_expr (exp, pc, ax, &value1);
-      gen_usual_unary (ax, &value1);
-      gen_expr_binop_rest (exp, op, pc, ax, value, &value1, &value2);
-      break;
-
-    case BINOP_LOGICAL_AND:
-      (*pc)++;
-      /* Generate the obvious sequence of tests and jumps.  */
-      gen_expr (exp, pc, ax, &value1);
-      gen_usual_unary (ax, &value1);
-      if1 = ax_goto (ax, aop_if_goto);
-      go1 = ax_goto (ax, aop_goto);
-      ax_label (ax, if1, ax->len);
-      gen_expr (exp, pc, ax, &value2);
-      gen_usual_unary (ax, &value2);
-      if2 = ax_goto (ax, aop_if_goto);
-      go2 = ax_goto (ax, aop_goto);
-      ax_label (ax, if2, ax->len);
-      ax_const_l (ax, 1);
-      end = ax_goto (ax, aop_goto);
-      ax_label (ax, go1, ax->len);
-      ax_label (ax, go2, ax->len);
-      ax_const_l (ax, 0);
-      ax_label (ax, end, ax->len);
-      value->kind = axs_rvalue;
-      value->type = int_type;
-      break;
-
-    case BINOP_LOGICAL_OR:
-      (*pc)++;
-      /* Generate the obvious sequence of tests and jumps.  */
-      gen_expr (exp, pc, ax, &value1);
-      gen_usual_unary (ax, &value1);
-      if1 = ax_goto (ax, aop_if_goto);
-      gen_expr (exp, pc, ax, &value2);
-      gen_usual_unary (ax, &value2);
-      if2 = ax_goto (ax, aop_if_goto);
-      ax_const_l (ax, 0);
-      end = ax_goto (ax, aop_goto);
-      ax_label (ax, if1, ax->len);
-      ax_label (ax, if2, ax->len);
-      ax_const_l (ax, 1);
-      ax_label (ax, end, ax->len);
-      value->kind = axs_rvalue;
-      value->type = int_type;
-      break;
-
-    case TERNOP_COND:
-      (*pc)++;
-      gen_expr (exp, pc, ax, &value1);
-      gen_usual_unary (ax, &value1);
-      /* For (A ? B : C), it's easiest to generate subexpression
-	 bytecodes in order, but if_goto jumps on true, so we invert
-	 the sense of A.  Then we can do B by dropping through, and
-	 jump to do C.  */
-      gen_logical_not (ax, &value1, int_type);
-      if1 = ax_goto (ax, aop_if_goto);
-      gen_expr (exp, pc, ax, &value2);
-      gen_usual_unary (ax, &value2);
-      end = ax_goto (ax, aop_goto);
-      ax_label (ax, if1, ax->len);
-      gen_expr (exp, pc, ax, &value3);
-      gen_usual_unary (ax, &value3);
-      ax_label (ax, end, ax->len);
-      /* This is arbitrary - what if B and C are incompatible types? */
-      value->type = value2.type;
-      value->kind = value2.kind;
-      break;
-
-    case BINOP_ASSIGN:
-      (*pc)++;
-      if ((*pc)[0].opcode == OP_INTERNALVAR)
-	{
-	  const char *name = internalvar_name ((*pc)[1].internalvar);
-	  struct trace_state_variable *tsv;
-
-	  (*pc) += 3;
-	  gen_expr (exp, pc, ax, value);
-	  tsv = find_trace_state_variable (name);
-	  if (tsv)
-	    {
-	      ax_tsv (ax, aop_setv, tsv->number);
-	      if (ax->tracing)
-		ax_tsv (ax, aop_tracev, tsv->number);
-	    }
-	  else
-	    error (_("$%s is not a trace state variable, "
-		     "may not assign to it"), name);
-	}
-      else
-	error (_("May only assign to trace state variables"));
-      break;
-
-    case BINOP_ASSIGN_MODIFY:
-      (*pc)++;
-      op2 = (*pc)[0].opcode;
-      (*pc)++;
-      (*pc)++;
-      if ((*pc)[0].opcode == OP_INTERNALVAR)
-	{
-	  const char *name = internalvar_name ((*pc)[1].internalvar);
-	  struct trace_state_variable *tsv;
-
-	  (*pc) += 3;
-	  tsv = find_trace_state_variable (name);
-	  if (tsv)
-	    {
-	      /* The tsv will be the left half of the binary operation.  */
-	      ax_tsv (ax, aop_getv, tsv->number);
-	      if (ax->tracing)
-		ax_tsv (ax, aop_tracev, tsv->number);
-	      /* Trace state variables are always 64-bit integers.  */
-	      value1.kind = axs_rvalue;
-	      value1.type = builtin_type (ax->gdbarch)->builtin_long_long;
-	      /* Now do right half of expression.  */
-	      gen_expr_binop_rest (exp, op2, pc, ax, value, &value1, &value2);
-	      /* We have a result of the binary op, set the tsv.  */
-	      ax_tsv (ax, aop_setv, tsv->number);
-	      if (ax->tracing)
-		ax_tsv (ax, aop_tracev, tsv->number);
-	    }
-	  else
-	    error (_("$%s is not a trace state variable, "
-		     "may not assign to it"), name);
-	}
-      else
-	error (_("May only assign to trace state variables"));
-      break;
-
-      /* Note that we need to be a little subtle about generating code
-	 for comma.  In C, we can do some optimizations here because
-	 we know the left operand is only being evaluated for effect.
-	 However, if the tracing kludge is in effect, then we always
-	 need to evaluate the left hand side fully, so that all the
-	 variables it mentions get traced.  */
-    case BINOP_COMMA:
-      (*pc)++;
-      gen_expr (exp, pc, ax, &value1);
-      /* Don't just dispose of the left operand.  We might be tracing,
-	 in which case we want to emit code to trace it if it's an
-	 lvalue.  */
-      gen_traced_pop (ax, &value1);
-      gen_expr (exp, pc, ax, value);
-      /* It's the consumer's responsibility to trace the right operand.  */
-      break;
-
-    case OP_LONG:		/* some integer constant */
-      {
-	struct type *type = (*pc)[1].type;
-	LONGEST k = (*pc)[2].longconst;
-
-	(*pc) += 4;
-	gen_int_literal (ax, value, k, type);
-      }
-      break;
-
-    case OP_VAR_VALUE:
-      gen_var_ref (ax, value, (*pc)[2].symbol);
-
-      if (value->optimized_out)
-	error (_("`%s' has been optimized out, cannot use"),
-	       (*pc)[2].symbol->print_name ());
-
-      if (value->type->code () == TYPE_CODE_ERROR)
-	error_unknown_type ((*pc)[2].symbol->print_name ());
-
-      (*pc) += 4;
-      break;
-
-    case OP_VAR_MSYM_VALUE:
-      gen_msym_var_ref (ax, value, (*pc)[2].msymbol, (*pc)[1].objfile);
-
-      if (value->type->code () == TYPE_CODE_ERROR)
-	error_unknown_type ((*pc)[2].msymbol->linkage_name ());
-
-      (*pc) += 4;
-      break;
-
-    case OP_REGISTER:
-      {
-	const char *name = &(*pc)[2].string;
-	int reg;
-
-	(*pc) += 4 + BYTES_TO_EXP_ELEM ((*pc)[1].longconst + 1);
-	reg = user_reg_map_name_to_regnum (ax->gdbarch, name, strlen (name));
-	if (reg == -1)
-	  internal_error (__FILE__, __LINE__,
-			  _("Register $%s not available"), name);
-	/* No support for tracing user registers yet.  */
-	if (reg >= gdbarch_num_cooked_regs (ax->gdbarch))
-	  error (_("'%s' is a user-register; "
-		   "GDB cannot yet trace user-register contents."),
-		 name);
-	value->kind = axs_lvalue_register;
-	value->u.reg = reg;
-	value->type = register_type (ax->gdbarch, reg);
-      }
-      break;
-
-    case OP_INTERNALVAR:
-      {
-	struct internalvar *var = (*pc)[1].internalvar;
-	const char *name = internalvar_name (var);
-	struct trace_state_variable *tsv;
-
-	(*pc) += 3;
-	tsv = find_trace_state_variable (name);
-	if (tsv)
-	  {
-	    ax_tsv (ax, aop_getv, tsv->number);
-	    if (ax->tracing)
-	      ax_tsv (ax, aop_tracev, tsv->number);
-	    /* Trace state variables are always 64-bit integers.  */
-	    value->kind = axs_rvalue;
-	    value->type = builtin_type (ax->gdbarch)->builtin_long_long;
-	  }
-	else if (! compile_internalvar_to_ax (var, ax, value))
-	  error (_("$%s is not a trace state variable; GDB agent "
-		   "expressions cannot use convenience variables."), name);
-      }
-      break;
-
-      /* Weirdo operator: see comments for gen_repeat for details.  */
-    case BINOP_REPEAT:
-      /* Note that gen_repeat handles its own argument evaluation.  */
-      (*pc)++;
-      gen_repeat (exp, pc, ax, value);
-      break;
-
-    case UNOP_CAST:
-      {
-	struct type *type = (*pc)[1].type;
-
-	(*pc) += 3;
-	gen_expr_for_cast (exp, pc, ax, value, type);
-      }
-      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_for_cast (exp, pc, ax, value, type);
-      }
-      break;
-
-    case UNOP_MEMVAL:
-      {
-	struct type *type = check_typedef ((*pc)[1].type);
-
-	(*pc) += 3;
-	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_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.  */
-      gen_expr (exp, pc, ax, value);
-      gen_usual_unary (ax, value);
-      break;
-      
-    case UNOP_NEG:
-      (*pc)++;
-      /* -FOO is equivalent to 0 - FOO.  */
-      gen_int_literal (ax, &value1, 0,
-		       builtin_type (ax->gdbarch)->builtin_int);
-      gen_usual_unary (ax, &value1);	/* shouldn't do much */
-      gen_expr (exp, pc, ax, &value2);
-      gen_usual_unary (ax, &value2);
-      gen_usual_arithmetic (ax, &value1, &value2);
-      gen_binop (ax, value, &value1, &value2, aop_sub, aop_sub, 1, "negation");
-      break;
-
-    case UNOP_LOGICAL_NOT:
-      (*pc)++;
-      gen_expr (exp, pc, ax, value);
-      gen_usual_unary (ax, value);
-      gen_logical_not (ax, value, int_type);
-      break;
-
-    case UNOP_COMPLEMENT:
-      (*pc)++;
-      gen_expr (exp, pc, ax, value);
-      gen_usual_unary (ax, value);
-      gen_integral_promotions (ax, value);
-      gen_complement (ax, value);
-      break;
-
-    case UNOP_IND:
-      (*pc)++;
-      gen_expr (exp, pc, ax, value);
-      gen_usual_unary (ax, value);
-      if (!pointer_type (value->type))
-	error (_("Argument of unary `*' is not a pointer."));
-      gen_deref (value);
-      break;
-
-    case UNOP_ADDR:
-      (*pc)++;
-      gen_expr (exp, pc, ax, value);
-      gen_address_of (value);
-      break;
-
-    case UNOP_SIZEOF:
-      (*pc)++;
-      /* Notice that gen_sizeof handles its own operand, unlike most
-	 of the other unary operator functions.  This is because we
-	 have to throw away the code we generate.  */
-      gen_sizeof (exp, pc, ax, value,
-		  builtin_type (ax->gdbarch)->builtin_int);
-      break;
-
-    case STRUCTOP_STRUCT:
-    case STRUCTOP_PTR:
-      {
-	int length = (*pc)[1].longconst;
-	const char *name = &(*pc)[2].string;
-
-	(*pc) += 4 + BYTES_TO_EXP_ELEM (length + 1);
-	gen_expr (exp, pc, ax, value);
-	if (op == STRUCTOP_STRUCT)
-	  gen_struct_ref (ax, value, name, ".", "structure or union");
-	else if (op == STRUCTOP_PTR)
-	  gen_struct_ref (ax, value, name, "->",
-			  "pointer to a structure or union");
-	else
-	  /* If this `if' chain doesn't handle it, then the case list
-	     shouldn't mention it, and we shouldn't be here.  */
-	  internal_error (__FILE__, __LINE__,
-			  _("gen_expr: unhandled struct case"));
-      }
-      break;
-
-    case OP_THIS:
-      {
-	struct symbol *sym, *func;
-	const struct block *b;
-	const struct language_defn *lang;
-
-	b = block_for_pc (ax->scope);
-	func = block_linkage_function (b);
-	lang = language_def (func->language ());
-
-	sym = lookup_language_this (lang, b).symbol;
-	if (!sym)
-	  error (_("no `%s' found"), lang->name_of_this ());
-
-	gen_var_ref (ax, value, sym);
-
-	if (value->optimized_out)
-	  error (_("`%s' has been optimized out, cannot use"),
-		 sym->print_name ());
-
-	(*pc) += 2;
-      }
-      break;
-
-    case OP_SCOPE:
-      {
-	struct type *type = (*pc)[1].type;
-	int length = longest_to_int ((*pc)[2].longconst);
-	const char *name = &(*pc)[3].string;
-	int found;
-
-	found = gen_aggregate_elt_ref (ax, value, type, name);
-	if (!found)
-	  error (_("There is no field named %s"), name);
-	(*pc) += 5 + BYTES_TO_EXP_ELEM (length + 1);
-      }
-      break;
-
-    case OP_TYPE:
-    case OP_TYPEOF:
-    case OP_DECLTYPE:
-      error (_("Attempt to use a type name as an expression."));
-
-    default:
-      error (_("Unsupported operator %s (%d) in expression."),
-	     op_name (op), op);
-    }
-}
-
 namespace expr
 {
 
@@ -2901,19 +2202,6 @@ gen_expr_binop_rest (struct expression *exp,
     }
 }
 
-/* Variant of gen_expr_binop_rest that first generates the
-   right-hand-side.  */
-
-static void
-gen_expr_binop_rest (struct expression *exp,
-		     enum exp_opcode op, union exp_element **pc,
-		     struct agent_expr *ax, struct axs_value *value,
-		     struct axs_value *value1, struct axs_value *value2)
-{
-  gen_expr (exp, pc, ax, value2);
-  gen_expr_binop_rest (exp, op, ax, value, value1, value2);
-}
-
 /* A helper function that emits a binop based on two operations.  */
 
 void
@@ -3057,17 +2345,12 @@ gen_trace_for_expr (CORE_ADDR scope, struct expression *expr,
 		    int trace_string)
 {
   agent_expr_up ax (new agent_expr (expr->gdbarch, scope));
-  union exp_element *pc;
   struct axs_value value;
 
-  pc = expr->elts;
   ax->tracing = 1;
   ax->trace_string = trace_string;
   value.optimized_out = 0;
-  if (expr->op != nullptr)
-    expr->op->generate_ax (expr, ax.get (), &value);
-  else
-    gen_expr (expr, &pc, ax.get (), &value);
+  expr->op->generate_ax (expr, ax.get (), &value);
 
   /* Make sure we record the final object, and get rid of it.  */
   gen_traced_pop (ax.get (), &value);
@@ -3089,16 +2372,11 @@ agent_expr_up
 gen_eval_for_expr (CORE_ADDR scope, struct expression *expr)
 {
   agent_expr_up ax (new agent_expr (expr->gdbarch, scope));
-  union exp_element *pc;
   struct axs_value value;
 
-  pc = expr->elts;
   ax->tracing = 0;
   value.optimized_out = 0;
-  if (expr->op != nullptr)
-    expr->op->generate_ax (expr, ax.get (), &value);
-  else
-    gen_expr (expr, &pc, ax.get (), &value);
+  expr->op->generate_ax (expr, ax.get (), &value);
 
   require_rvalue (ax.get (), &value);
 
@@ -3140,7 +2418,6 @@ gen_printf (CORE_ADDR scope, struct gdbarch *gdbarch,
 	    int nargs, struct expression **exprs)
 {
   agent_expr_up ax (new agent_expr (gdbarch, scope));
-  union exp_element *pc;
   struct axs_value value;
   int tem;
 
@@ -3152,13 +2429,7 @@ gen_printf (CORE_ADDR scope, struct gdbarch *gdbarch,
   for (tem = nargs - 1; tem >= 0; --tem)
     {
       value.optimized_out = 0;
-      if (exprs[tem]->op != nullptr)
-	exprs[tem]->op->generate_ax (exprs[tem], ax.get (), &value);
-      else
-	{
-	  pc = exprs[tem]->elts;
-	  gen_expr (exprs[tem], &pc, ax.get (), &value);
-	}
+      exprs[tem]->op->generate_ax (exprs[tem], ax.get (), &value);
       require_rvalue (ax.get (), &value);
     }
 
diff --git a/gdb/ax-gdb.h b/gdb/ax-gdb.h
index 5b7a513ac8e..b143847889b 100644
--- a/gdb/ax-gdb.h
+++ b/gdb/ax-gdb.h
@@ -22,7 +22,6 @@
 #include "ax.h"  /* For agent_expr_up.  */
 
 struct expression;
-union exp_element;
 
 /* Types and enums */
 
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 1f7716c29f4..67685344eb3 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -1898,12 +1898,11 @@ update_watchpoint (struct watchpoint *b, int reparse)
     }
   else if (within_current_scope && b->exp)
     {
-      int pc = 0;
       std::vector<value_ref_ptr> val_chain;
       struct value *v, *result;
       struct program_space *frame_pspace;
 
-      fetch_subexp_value (b->exp.get (), &pc, b->exp->op.get (), &v, &result,
+      fetch_subexp_value (b->exp.get (), b->exp->op.get (), &v, &result,
 			  &val_chain, false);
 
       /* Avoid setting b->val if it's already set.  The meaning of
@@ -4945,7 +4944,6 @@ watchpoint_check (bpstat bs)
 	 free_all_values.  We can't call free_all_values because we
 	 might be in the middle of evaluating a function call.  */
 
-      int pc = 0;
       struct value *mark;
       struct value *new_val;
 
@@ -4956,7 +4954,7 @@ watchpoint_check (bpstat bs)
 	return WP_VALUE_CHANGED;
 
       mark = value_mark ();
-      fetch_subexp_value (b->exp.get (), &pc, b->exp->op.get (), &new_val,
+      fetch_subexp_value (b->exp.get (), b->exp->op.get (), &new_val,
 			  NULL, NULL, false);
 
       if (b->val_bitsize != 0)
@@ -10058,112 +10056,7 @@ break_range_command (const char *arg, int from_tty)
 static bool
 watchpoint_exp_is_const (const struct expression *exp)
 {
-  if (exp->op != nullptr)
-    return exp->op->constant_p ();
-
-  int i = exp->nelts;
-
-  while (i > 0)
-    {
-      int oplenp, argsp;
-
-      /* We are only interested in the descriptor of each element.  */
-      operator_length (exp, i, &oplenp, &argsp);
-      i -= oplenp;
-
-      switch (exp->elts[i].opcode)
-	{
-	case BINOP_ADD:
-	case BINOP_SUB:
-	case BINOP_MUL:
-	case BINOP_DIV:
-	case BINOP_REM:
-	case BINOP_MOD:
-	case BINOP_LSH:
-	case BINOP_RSH:
-	case BINOP_LOGICAL_AND:
-	case BINOP_LOGICAL_OR:
-	case BINOP_BITWISE_AND:
-	case BINOP_BITWISE_IOR:
-	case BINOP_BITWISE_XOR:
-	case BINOP_EQUAL:
-	case BINOP_NOTEQUAL:
-	case BINOP_LESS:
-	case BINOP_GTR:
-	case BINOP_LEQ:
-	case BINOP_GEQ:
-	case BINOP_REPEAT:
-	case BINOP_COMMA:
-	case BINOP_EXP:
-	case BINOP_MIN:
-	case BINOP_MAX:
-	case BINOP_INTDIV:
-	case BINOP_CONCAT:
-	case TERNOP_COND:
-	case TERNOP_SLICE:
-
-	case OP_LONG:
-	case OP_FLOAT:
-	case OP_LAST:
-	case OP_COMPLEX:
-	case OP_STRING:
-	case OP_ARRAY:
-	case OP_TYPE:
-	case OP_TYPEOF:
-	case OP_DECLTYPE:
-	case OP_TYPEID:
-	case OP_NAME:
-	case OP_OBJC_NSSTRING:
-
-	case UNOP_NEG:
-	case UNOP_LOGICAL_NOT:
-	case UNOP_COMPLEMENT:
-	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
-	     determined to be constants, then so is "A + B".
-
-	     UNOP_IND is one exception to the rule above, because the
-	     value of *ADDR is not necessarily a constant, even when
-	     ADDR is.  */
-	  break;
-
-	case OP_VAR_VALUE:
-	  /* Check whether the associated symbol is a constant.
-
-	     We use SYMBOL_CLASS rather than TYPE_CONST because it's
-	     possible that a buggy compiler could mark a variable as
-	     constant even when it is not, and TYPE_CONST would return
-	     true in this case, while SYMBOL_CLASS wouldn't.
-
-	     We also have to check for function symbols because they
-	     are always constant.  */
-	  {
-	    struct symbol *s = exp->elts[i + 2].symbol;
-
-	    if (SYMBOL_CLASS (s) != LOC_BLOCK
-		&& SYMBOL_CLASS (s) != LOC_CONST
-		&& SYMBOL_CLASS (s) != LOC_CONST_BYTES)
-	      return false;
-	    break;
-	  }
-
-	/* The default action is to return 0 because we are using
-	   the optimistic approach here: If we don't know something,
-	   then it is not a constant.  */
-	default:
-	  return false;
-	}
-    }
-
-  return true;
+  return exp->op->constant_p ();
 }
 
 /* Watchpoint destructor.  */
@@ -10664,7 +10557,6 @@ watch_command_1 (const char *arg, int accessflag, int from_tty,
   const char *cond_end = NULL;
   enum bptype bp_type;
   int thread = -1;
-  int pc = 0;
   /* Flag to indicate whether we are going to use masks for
      the hardware watchpoint.  */
   bool use_mask = false;
@@ -10781,8 +10673,8 @@ watch_command_1 (const char *arg, int accessflag, int from_tty,
   exp_valid_block = tracker.block ();
   struct value *mark = value_mark ();
   struct value *val_as_value = nullptr;
-  fetch_subexp_value (exp.get (), &pc, exp->op.get (), &val_as_value, &result,
-		      NULL, just_location);
+  fetch_subexp_value (exp.get (), exp->op.get (), &val_as_value, &result, NULL,
+		      just_location);
 
   if (val_as_value != NULL && just_location)
     {
diff --git a/gdb/c-lang.c b/gdb/c-lang.c
index 90ad90cab4e..5dd27329726 100644
--- a/gdb/c-lang.c
+++ b/gdb/c-lang.c
@@ -741,45 +741,6 @@ c_is_string_type_p (struct type *type)
   return false;
 }
 
-\f
-/* Table mapping opcodes into strings for printing operators
-   and precedences of the operators.  */
-
-const struct op_print c_op_print_tab[] =
-{
-  {",", BINOP_COMMA, PREC_COMMA, 0},
-  {"=", BINOP_ASSIGN, PREC_ASSIGN, 1},
-  {"||", BINOP_LOGICAL_OR, PREC_LOGICAL_OR, 0},
-  {"&&", BINOP_LOGICAL_AND, PREC_LOGICAL_AND, 0},
-  {"|", BINOP_BITWISE_IOR, PREC_BITWISE_IOR, 0},
-  {"^", BINOP_BITWISE_XOR, PREC_BITWISE_XOR, 0},
-  {"&", BINOP_BITWISE_AND, PREC_BITWISE_AND, 0},
-  {"==", BINOP_EQUAL, PREC_EQUAL, 0},
-  {"!=", BINOP_NOTEQUAL, PREC_EQUAL, 0},
-  {"<=", BINOP_LEQ, PREC_ORDER, 0},
-  {">=", BINOP_GEQ, PREC_ORDER, 0},
-  {">", BINOP_GTR, PREC_ORDER, 0},
-  {"<", BINOP_LESS, PREC_ORDER, 0},
-  {">>", BINOP_RSH, PREC_SHIFT, 0},
-  {"<<", BINOP_LSH, PREC_SHIFT, 0},
-  {"+", BINOP_ADD, PREC_ADD, 0},
-  {"-", BINOP_SUB, PREC_ADD, 0},
-  {"*", BINOP_MUL, PREC_MUL, 0},
-  {"/", BINOP_DIV, PREC_MUL, 0},
-  {"%", BINOP_REM, PREC_MUL, 0},
-  {"@", BINOP_REPEAT, PREC_REPEAT, 0},
-  {"+", UNOP_PLUS, PREC_PREFIX, 0},
-  {"-", UNOP_NEG, PREC_PREFIX, 0},
-  {"!", UNOP_LOGICAL_NOT, PREC_PREFIX, 0},
-  {"~", UNOP_COMPLEMENT, PREC_PREFIX, 0},
-  {"*", UNOP_IND, PREC_PREFIX, 0},
-  {"&", UNOP_ADDR, PREC_PREFIX, 0},
-  {"sizeof ", UNOP_SIZEOF, PREC_PREFIX, 0},
-  {"alignof ", UNOP_ALIGNOF, PREC_PREFIX, 0},
-  {"++", UNOP_PREINCREMENT, PREC_PREFIX, 0},
-  {"--", UNOP_PREDECREMENT, PREC_PREFIX, 0},
-  {NULL, OP_NULL, PREC_PREFIX, 0}
-};
 \f
 
 void
@@ -887,11 +848,6 @@ class c_language : public language_defn
 
   enum macro_expansion macro_expansion () const override
   { return macro_expansion_c; }
-
-  /* See language.h.  */
-
-  const struct op_print *opcode_print_table () const override
-  { return c_op_print_tab; }
 };
 
 /* Single instance of the C language class.  */
@@ -1066,11 +1022,6 @@ class cplus_language : public language_defn
   const struct lang_varobj_ops *varobj_ops () const override
   { return &cplus_varobj_ops; }
 
-  /* See language.h.  */
-
-  const struct op_print *opcode_print_table () const override
-  { return c_op_print_tab; }
-
 protected:
 
   /* See language.h.  */
@@ -1141,11 +1092,6 @@ class asm_language : public language_defn
 
   enum macro_expansion macro_expansion () const override
   { return macro_expansion_c; }
-
-  /* See language.h.  */
-
-  const struct op_print *opcode_print_table () const override
-  { return c_op_print_tab; }
 };
 
 /* The single instance of the ASM language class.  */
@@ -1198,11 +1144,6 @@ class minimal_language : public language_defn
 
   enum macro_expansion macro_expansion () const override
   { return macro_expansion_c; }
-
-  /* See language.h.  */
-
-  const struct op_print *opcode_print_table () const override
-  { return c_op_print_tab; }
 };
 
 /* The single instance of the minimal language class.  */
diff --git a/gdb/c-lang.h b/gdb/c-lang.h
index a46957d0d84..e09c647fecd 100644
--- a/gdb/c-lang.h
+++ b/gdb/c-lang.h
@@ -106,8 +106,6 @@ extern void c_language_arch_info (struct gdbarch *gdbarch,
 extern void c_emit_char (int c, struct type *type,
 			 struct ui_file *stream, int quoter);
 
-extern const struct op_print c_op_print_tab[];
-
 /* These are in c-typeprint.c: */
 
 extern void c_type_print_base (struct type *, struct ui_file *,
diff --git a/gdb/d-lang.c b/gdb/d-lang.c
index 4488c10e609..6c9b730cf41 100644
--- a/gdb/d-lang.c
+++ b/gdb/d-lang.c
@@ -57,44 +57,6 @@ d_demangle (const char *symbol, int options)
   return gdb_demangle (symbol, options | DMGL_DLANG);
 }
 
-/* Table mapping opcodes into strings for printing operators
-   and precedences of the operators.  */
-static const struct op_print d_op_print_tab[] =
-{
-  {",", BINOP_COMMA, PREC_COMMA, 0},
-  {"=", BINOP_ASSIGN, PREC_ASSIGN, 1},
-  {"||", BINOP_LOGICAL_OR, PREC_LOGICAL_OR, 0},
-  {"&&", BINOP_LOGICAL_AND, PREC_LOGICAL_AND, 0},
-  {"|", BINOP_BITWISE_IOR, PREC_BITWISE_IOR, 0},
-  {"^", BINOP_BITWISE_XOR, PREC_BITWISE_XOR, 0},
-  {"&", BINOP_BITWISE_AND, PREC_BITWISE_AND, 0},
-  {"==", BINOP_EQUAL, PREC_ORDER, 0},
-  {"!=", BINOP_NOTEQUAL, PREC_ORDER, 0},
-  {"<=", BINOP_LEQ, PREC_ORDER, 0},
-  {">=", BINOP_GEQ, PREC_ORDER, 0},
-  {">", BINOP_GTR, PREC_ORDER, 0},
-  {"<", BINOP_LESS, PREC_ORDER, 0},
-  {">>", BINOP_RSH, PREC_SHIFT, 0},
-  {"<<", BINOP_LSH, PREC_SHIFT, 0},
-  {"+", BINOP_ADD, PREC_ADD, 0},
-  {"-", BINOP_SUB, PREC_ADD, 0},
-  {"~", BINOP_CONCAT, PREC_ADD, 0},
-  {"*", BINOP_MUL, PREC_MUL, 0},
-  {"/", BINOP_DIV, PREC_MUL, 0},
-  {"%", BINOP_REM, PREC_MUL, 0},
-  {"^^", BINOP_EXP, PREC_REPEAT, 0},
-  {"@", BINOP_REPEAT, PREC_REPEAT, 0},
-  {"-", UNOP_NEG, PREC_PREFIX, 0},
-  {"!", UNOP_LOGICAL_NOT, PREC_PREFIX, 0},
-  {"~", UNOP_COMPLEMENT, PREC_PREFIX, 0},
-  {"*", UNOP_IND, PREC_PREFIX, 0},
-  {"&", UNOP_ADDR, PREC_PREFIX, 0},
-  {"sizeof ", UNOP_SIZEOF, PREC_PREFIX, 0},
-  {"++", UNOP_PREINCREMENT, PREC_PREFIX, 0},
-  {"--", UNOP_PREDECREMENT, PREC_PREFIX, 0},
-  {NULL, OP_NULL, PREC_PREFIX, 0}
-};
-
 /* Class representing the D language.  */
 
 class d_language : public language_defn
@@ -216,11 +178,6 @@ class d_language : public language_defn
 
   const char *name_of_this () const override
   { return "this"; }
-
-  /* See language.h.  */
-
-  const struct op_print *opcode_print_table () const override
-  { return d_op_print_tab; }
 };
 
 /* Single instance of the D language class.  */
diff --git a/gdb/dtrace-probe.c b/gdb/dtrace-probe.c
index 3fa02ddaebe..cccd3a8bbba 100644
--- a/gdb/dtrace-probe.c
+++ b/gdb/dtrace-probe.c
@@ -725,17 +725,9 @@ dtrace_probe::compile_to_ax (struct agent_expr *expr, struct axs_value *value,
 			     unsigned n)
 {
   struct dtrace_probe_arg *arg;
-  union exp_element *pc;
 
   arg = this->get_arg_by_number (n, expr->gdbarch);
-
-  if (arg->expr->op != nullptr)
-    arg->expr->op->generate_ax (arg->expr.get (), expr, value);
-  else
-    {
-      pc = arg->expr->elts;
-      gen_expr (arg->expr.get (), &pc, expr, value);
-    }
+  arg->expr->op->generate_ax (arg->expr.get (), expr, value);
 
   require_rvalue (expr, value);
   value->type = arg->type;
diff --git a/gdb/eval.c b/gdb/eval.c
index bb4e59fe17f..1f87748e80b 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -45,34 +45,19 @@
 
 /* Prototypes for local functions.  */
 
-static struct value *evaluate_subexp_for_sizeof (struct expression *, int *,
-						 enum noside);
-
-static struct value *evaluate_subexp_for_address (struct expression *,
-						  int *, enum noside);
-
-static value *evaluate_subexp_for_cast (expression *exp, int *pos,
-					enum noside noside,
-					struct type *type);
-
-static struct value *evaluate_struct_tuple (struct value *,
-					    struct expression *, int *,
-					    enum noside, int);
-
-struct value *
+static struct value *
 evaluate_subexp (struct type *expect_type, struct expression *exp,
-		 int *pos, enum noside noside)
+		 enum noside noside)
 {
   struct value *retval;
 
   gdb::optional<enable_thread_stack_temporaries> stack_temporaries;
-  if (*pos == 0 && target_has_execution ()
+  if (target_has_execution ()
       && exp->language_defn->la_language == language_cplus
       && !thread_stack_temporaries_enabled_p (inferior_thread ()))
     stack_temporaries.emplace (inferior_thread ());
 
-  retval = (*exp->language_defn->expression_ops ()->evaluate_exp)
-    (expect_type, exp, pos, noside);
+  return exp->op->evaluate (expect_type, exp, noside);
 
   if (stack_temporaries.has_value ()
       && value_in_thread_stack_temporaries (retval, inferior_thread ()))
@@ -128,12 +113,7 @@ parse_to_comma_and_eval (const char **expp)
 struct value *
 evaluate_expression (struct expression *exp, struct type *expect_type)
 {
-  int pc = 0;
-
-  if (exp->op != nullptr)
-    return exp->op->evaluate (expect_type, exp, EVAL_NORMAL);
-
-  return evaluate_subexp (expect_type, exp, &pc, EVAL_NORMAL);
+  return evaluate_subexp (expect_type, exp, EVAL_NORMAL);
 }
 
 /* Evaluate an expression, avoiding all memory references
@@ -142,23 +122,7 @@ evaluate_expression (struct expression *exp, struct type *expect_type)
 struct value *
 evaluate_type (struct expression *exp)
 {
-  int pc = 0;
-
-  if (exp->op != nullptr)
-    return exp->op->evaluate (nullptr, exp, EVAL_AVOID_SIDE_EFFECTS);
-
-  return evaluate_subexp (nullptr, exp, &pc, EVAL_AVOID_SIDE_EFFECTS);
-}
-
-/* Evaluate a subexpression, avoiding all memory references and
-   getting a value whose type alone is correct.  */
-
-struct value *
-evaluate_subexpression_type (struct expression *exp, int subexp)
-{
-  if (exp->op != nullptr)
-    return exp->op->evaluate (nullptr, exp, EVAL_AVOID_SIDE_EFFECTS);
-  return evaluate_subexp (nullptr, exp, &subexp, EVAL_AVOID_SIDE_EFFECTS);
+  return evaluate_subexp (nullptr, exp, EVAL_AVOID_SIDE_EFFECTS);
 }
 
 /* Find the current value of a watchpoint on EXP.  Return the value in
@@ -184,7 +148,7 @@ evaluate_subexpression_type (struct expression *exp, int subexp)
    values will be left on the value chain.  */
 
 void
-fetch_subexp_value (struct expression *exp, int *pc,
+fetch_subexp_value (struct expression *exp,
 		    expr::operation *op,
 		    struct value **valp, struct value **resultp,
 		    std::vector<value_ref_ptr> *val_chain,
@@ -204,10 +168,7 @@ fetch_subexp_value (struct expression *exp, int *pc,
 
   try
     {
-      if (op == nullptr)
-	result = evaluate_subexp (nullptr, exp, pc, EVAL_NORMAL);
-      else
-	result = op->evaluate (nullptr, exp, EVAL_NORMAL);
+      result = op->evaluate (nullptr, exp, EVAL_NORMAL);
     }
   catch (const gdb_exception &ex)
     {
@@ -260,91 +221,6 @@ fetch_subexp_value (struct expression *exp, int *pc,
     }
 }
 
-/* Extract a field operation from an expression.  If the subexpression
-   of EXP starting at *SUBEXP is not a structure dereference
-   operation, return NULL.  Otherwise, return the name of the
-   dereferenced field, and advance *SUBEXP to point to the
-   subexpression of the left-hand-side of the dereference.  This is
-   used when completing field names.  */
-
-const char *
-extract_field_op (struct expression *exp, int *subexp)
-{
-  int tem;
-  char *result;
-
-  if (exp->elts[*subexp].opcode != STRUCTOP_STRUCT
-      && exp->elts[*subexp].opcode != STRUCTOP_PTR)
-    return NULL;
-  tem = longest_to_int (exp->elts[*subexp + 1].longconst);
-  result = &exp->elts[*subexp + 2].string;
-  (*subexp) += 1 + 3 + BYTES_TO_EXP_ELEM (tem + 1);
-  return result;
-}
-
-/* This function evaluates brace-initializers (in C/C++) for
-   structure types.  */
-
-static struct value *
-evaluate_struct_tuple (struct value *struct_val,
-		       struct expression *exp,
-		       int *pos, enum noside noside, int nargs)
-{
-  struct type *struct_type = check_typedef (value_type (struct_val));
-  struct type *field_type;
-  int fieldno = -1;
-
-  while (--nargs >= 0)
-    {
-      struct value *val = NULL;
-      int bitpos, bitsize;
-      bfd_byte *addr;
-
-      fieldno++;
-      /* Skip static fields.  */
-      while (fieldno < struct_type->num_fields ()
-	     && field_is_static (&struct_type->field (fieldno)))
-	fieldno++;
-      if (fieldno >= struct_type->num_fields ())
-	error (_("too many initializers"));
-      field_type = struct_type->field (fieldno).type ();
-      if (field_type->code () == TYPE_CODE_UNION
-	  && TYPE_FIELD_NAME (struct_type, fieldno)[0] == '0')
-	error (_("don't know which variant you want to set"));
-
-      /* Here, struct_type is the type of the inner struct,
-	 while substruct_type is the type of the inner struct.
-	 These are the same for normal structures, but a variant struct
-	 contains anonymous union fields that contain substruct fields.
-	 The value fieldno is the index of the top-level (normal or
-	 anonymous union) field in struct_field, while the value
-	 subfieldno is the index of the actual real (named inner) field
-	 in substruct_type.  */
-
-      field_type = struct_type->field (fieldno).type ();
-      if (val == 0)
-	val = evaluate_subexp (field_type, exp, pos, noside);
-
-      /* Now actually set the field in struct_val.  */
-
-      /* Assign val to field fieldno.  */
-      if (value_type (val) != field_type)
-	val = value_cast (field_type, val);
-
-      bitsize = TYPE_FIELD_BITSIZE (struct_type, fieldno);
-      bitpos = TYPE_FIELD_BITPOS (struct_type, fieldno);
-      addr = value_contents_writeable (struct_val) + bitpos / 8;
-      if (bitsize)
-	modify_field (struct_type, addr,
-		      value_as_long (val), bitpos % 8, bitsize);
-      else
-	memcpy (addr, value_contents (val),
-		TYPE_LENGTH (value_type (val)));
-
-    }
-  return struct_val;
-}
-
 /* Promote value ARG1 as appropriate before performing a unary operation
    on this argument.
    If the result is not appropriate for any particular language then it
@@ -808,412 +684,6 @@ evaluate_subexp_do_call (expression *exp, enum noside noside,
     }
 }
 
-/* Helper for evaluating an OP_FUNCALL.  */
-
-static value *
-evaluate_funcall (type *expect_type, expression *exp, int *pos,
-		  enum noside noside)
-{
-  int tem;
-  int pc2 = 0;
-  value *arg1 = NULL;
-  value *arg2 = NULL;
-  int save_pos1;
-  symbol *function = NULL;
-  char *function_name = NULL;
-  const char *var_func_name = NULL;
-
-  int pc = (*pos);
-  (*pos) += 2;
-
-  exp_opcode op = exp->elts[*pos].opcode;
-  int nargs = longest_to_int (exp->elts[pc].longconst);
-  /* Allocate arg vector, including space for the function to be
-     called in argvec[0], a potential `this', and a terminating
-     NULL.  */
-  value **argvec = (value **) alloca (sizeof (value *) * (nargs + 3));
-  if (op == STRUCTOP_MEMBER || op == STRUCTOP_MPTR)
-    {
-      /* First, evaluate the structure into arg2.  */
-      pc2 = (*pos)++;
-
-      if (op == STRUCTOP_MEMBER)
-	{
-	  arg2 = evaluate_subexp_for_address (exp, pos, noside);
-	}
-      else
-	{
-	  arg2 = evaluate_subexp (nullptr, exp, pos, noside);
-	}
-
-      /* If the function is a virtual function, then the aggregate
-	 value (providing the structure) plays its part by providing
-	 the vtable.  Otherwise, it is just along for the ride: call
-	 the function directly.  */
-
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-
-      type *a1_type = check_typedef (value_type (arg1));
-      if (noside == EVAL_SKIP)
-	tem = 1;  /* Set it to the right arg index so that all
-		     arguments can also be skipped.  */
-      else if (a1_type->code () == TYPE_CODE_METHODPTR)
-	{
-	  if (noside == EVAL_AVOID_SIDE_EFFECTS)
-	    arg1 = value_zero (TYPE_TARGET_TYPE (a1_type), not_lval);
-	  else
-	    arg1 = cplus_method_ptr_to_value (&arg2, arg1);
-
-	  /* Now, say which argument to start evaluating from.  */
-	  nargs++;
-	  tem = 2;
-	  argvec[1] = arg2;
-	}
-      else if (a1_type->code () == TYPE_CODE_MEMBERPTR)
-	{
-	  struct type *type_ptr
-	    = lookup_pointer_type (TYPE_SELF_TYPE (a1_type));
-	  struct type *target_type_ptr
-	    = lookup_pointer_type (TYPE_TARGET_TYPE (a1_type));
-
-	  /* Now, convert these values to an address.  */
-	  arg2 = value_cast (type_ptr, arg2);
-
-	  long mem_offset = value_as_long (arg1);
-
-	  arg1 = value_from_pointer (target_type_ptr,
-				     value_as_long (arg2) + mem_offset);
-	  arg1 = value_ind (arg1);
-	  tem = 1;
-	}
-      else
-	error (_("Non-pointer-to-member value used in pointer-to-member "
-		 "construct"));
-    }
-  else if (op == STRUCTOP_STRUCT || op == STRUCTOP_PTR)
-    {
-      /* Hair for method invocations.  */
-      int tem2;
-
-      nargs++;
-      /* First, evaluate the structure into arg2.  */
-      pc2 = (*pos)++;
-      tem2 = longest_to_int (exp->elts[pc2 + 1].longconst);
-      *pos += 3 + BYTES_TO_EXP_ELEM (tem2 + 1);
-
-      if (op == STRUCTOP_STRUCT)
-	{
-	  /* If v is a variable in a register, and the user types
-	     v.method (), this will produce an error, because v has no
-	     address.
-
-	     A possible way around this would be to allocate a copy of
-	     the variable on the stack, copy in the contents, call the
-	     function, and copy out the contents.  I.e. convert this
-	     from call by reference to call by copy-return (or
-	     whatever it's called).  However, this does not work
-	     because it is not the same: the method being called could
-	     stash a copy of the address, and then future uses through
-	     that address (after the method returns) would be expected
-	     to use the variable itself, not some copy of it.  */
-	  arg2 = evaluate_subexp_for_address (exp, pos, noside);
-	}
-      else
-	{
-	  arg2 = evaluate_subexp (nullptr, exp, pos, noside);
-
-	  /* Check to see if the operator '->' has been overloaded.
-	     If the operator has been overloaded replace arg2 with the
-	     value returned by the custom operator and continue
-	     evaluation.  */
-	  while (unop_user_defined_p (op, arg2))
-	    {
-	      struct value *value = NULL;
-	      try
-		{
-		  value = value_x_unop (arg2, op, noside);
-		}
-
-	      catch (const gdb_exception_error &except)
-		{
-		  if (except.error == NOT_FOUND_ERROR)
-		    break;
-		  else
-		    throw;
-		}
-
-		arg2 = value;
-	    }
-	}
-      /* Now, say which argument to start evaluating from.  */
-      tem = 2;
-    }
-  else if (op == OP_SCOPE
-	   && overload_resolution
-	   && (exp->language_defn->la_language == language_cplus))
-    {
-      /* Unpack it locally so we can properly handle overload
-	 resolution.  */
-      char *name;
-      int local_tem;
-
-      pc2 = (*pos)++;
-      local_tem = longest_to_int (exp->elts[pc2 + 2].longconst);
-      (*pos) += 4 + BYTES_TO_EXP_ELEM (local_tem + 1);
-      struct type *type = exp->elts[pc2 + 1].type;
-      name = &exp->elts[pc2 + 3].string;
-
-      function = NULL;
-      function_name = NULL;
-      if (type->code () == TYPE_CODE_NAMESPACE)
-	{
-	  function = cp_lookup_symbol_namespace (type->name (),
-						 name,
-						 get_selected_block (0),
-						 VAR_DOMAIN).symbol;
-	  if (function == NULL)
-	    error (_("No symbol \"%s\" in namespace \"%s\"."),
-		   name, type->name ());
-
-	  tem = 1;
-	  /* arg2 is left as NULL on purpose.  */
-	}
-      else
-	{
-	  gdb_assert (type->code () == TYPE_CODE_STRUCT
-		      || type->code () == TYPE_CODE_UNION);
-	  function_name = name;
-
-	  /* We need a properly typed value for method lookup.  For
-	     static methods arg2 is otherwise unused.  */
-	  arg2 = value_zero (type, lval_memory);
-	  ++nargs;
-	  tem = 2;
-	}
-    }
-  else if (op == OP_ADL_FUNC)
-    {
-      /* Save the function position and move pos so that the arguments
-	 can be evaluated.  */
-      int func_name_len;
-
-      save_pos1 = *pos;
-      tem = 1;
-
-      func_name_len = longest_to_int (exp->elts[save_pos1 + 3].longconst);
-      (*pos) += 6 + BYTES_TO_EXP_ELEM (func_name_len + 1);
-    }
-  else
-    {
-      /* Non-method function call.  */
-      save_pos1 = *pos;
-      tem = 1;
-
-      /* If this is a C++ function wait until overload resolution.  */
-      if (op == OP_VAR_VALUE
-	  && overload_resolution
-	  && (exp->language_defn->la_language == language_cplus))
-	{
-	  (*pos) += 4; /* Skip the evaluation of the symbol.  */
-	  argvec[0] = NULL;
-	}
-      else
-	{
-	  if (op == OP_VAR_MSYM_VALUE)
-	    {
-	      minimal_symbol *msym = exp->elts[*pos + 2].msymbol;
-	      var_func_name = msym->print_name ();
-	    }
-	  else if (op == OP_VAR_VALUE)
-	    {
-	      symbol *sym = exp->elts[*pos + 2].symbol;
-	      var_func_name = sym->print_name ();
-	    }
-
-	  argvec[0] = evaluate_subexp_with_coercion (exp, pos, noside);
-	  type *type = value_type (argvec[0]);
-	  if (type && type->code () == TYPE_CODE_PTR)
-	    type = TYPE_TARGET_TYPE (type);
-	  if (type && type->code () == TYPE_CODE_FUNC)
-	    {
-	      for (; tem <= nargs && tem <= type->num_fields (); tem++)
-		{
-		  argvec[tem] = evaluate_subexp (type->field (tem - 1).type (),
-						 exp, pos, noside);
-		}
-	    }
-	}
-    }
-
-  /* Evaluate arguments (if not already done, e.g., namespace::func()
-     and overload-resolution is off).  */
-  for (; tem <= nargs; tem++)
-    {
-      /* Ensure that array expressions are coerced into pointer
-	 objects.  */
-      argvec[tem] = evaluate_subexp_with_coercion (exp, pos, noside);
-    }
-
-  /* Signal end of arglist.  */
-  argvec[tem] = 0;
-
-  if (noside == EVAL_SKIP)
-    return eval_skip_value (exp);
-
-  if (op == OP_ADL_FUNC)
-    {
-      struct symbol *symp;
-      char *func_name;
-      int  name_len;
-      int string_pc = save_pos1 + 3;
-
-      /* Extract the function name.  */
-      name_len = longest_to_int (exp->elts[string_pc].longconst);
-      func_name = (char *) alloca (name_len + 1);
-      strcpy (func_name, &exp->elts[string_pc + 1].string);
-
-      find_overload_match (gdb::make_array_view (&argvec[1], nargs),
-			   func_name,
-			   NON_METHOD, /* not method */
-			   NULL, NULL, /* pass NULL symbol since
-					  symbol is unknown */
-			   NULL, &symp, NULL, 0, noside);
-
-      /* Now fix the expression being evaluated.  */
-      exp->elts[save_pos1 + 2].symbol = symp;
-      argvec[0] = evaluate_subexp_with_coercion (exp, &save_pos1, noside);
-    }
-
-  if (op == STRUCTOP_STRUCT || op == STRUCTOP_PTR
-      || (op == OP_SCOPE && function_name != NULL))
-    {
-      int static_memfuncp;
-      char *tstr;
-
-      /* Method invocation: stuff "this" as first parameter.  If the
-	 method turns out to be static we undo this below.  */
-      argvec[1] = arg2;
-
-      if (op != OP_SCOPE)
-	{
-	  /* Name of method from expression.  */
-	  tstr = &exp->elts[pc2 + 2].string;
-	}
-      else
-	tstr = function_name;
-
-      if (overload_resolution && (exp->language_defn->la_language
-				  == language_cplus))
-	{
-	  /* Language is C++, do some overload resolution before
-	     evaluation.  */
-	  struct value *valp = NULL;
-
-	  (void) find_overload_match (gdb::make_array_view (&argvec[1], nargs),
-				      tstr,
-				      METHOD, /* method */
-				      &arg2,  /* the object */
-				      NULL, &valp, NULL,
-				      &static_memfuncp, 0, noside);
-
-	  if (op == OP_SCOPE && !static_memfuncp)
-	    {
-	      /* For the time being, we don't handle this.  */
-	      error (_("Call to overloaded function %s requires "
-		       "`this' pointer"),
-		     function_name);
-	    }
-	  argvec[1] = arg2;	/* the ``this'' pointer */
-	  argvec[0] = valp;	/* Use the method found after overload
-				   resolution.  */
-	}
-      else
-	/* Non-C++ case -- or no overload resolution.  */
-	{
-	  struct value *temp = arg2;
-
-	  argvec[0] = value_struct_elt (&temp, argvec + 1, tstr,
-					&static_memfuncp,
-					op == STRUCTOP_STRUCT
-					? "structure" : "structure pointer");
-	  /* value_struct_elt updates temp with the correct value of
-	     the ``this'' pointer if necessary, so modify argvec[1] to
-	     reflect any ``this'' changes.  */
-	  arg2
-	    = value_from_longest (lookup_pointer_type(value_type (temp)),
-				  value_address (temp)
-				  + value_embedded_offset (temp));
-	  argvec[1] = arg2;	/* the ``this'' pointer */
-	}
-
-      /* Take out `this' if needed.  */
-      if (static_memfuncp)
-	{
-	  argvec[1] = argvec[0];
-	  nargs--;
-	  argvec++;
-	}
-    }
-  else if (op == STRUCTOP_MEMBER || op == STRUCTOP_MPTR)
-    {
-      /* Pointer to member.  argvec[1] is already set up.  */
-      argvec[0] = arg1;
-    }
-  else if (op == OP_VAR_VALUE || (op == OP_SCOPE && function != NULL))
-    {
-      /* Non-member function being called.  */
-      /* fn: This can only be done for C++ functions.  A C-style
-	 function in a C++ program, for instance, does not have the
-	 fields that are expected here.  */
-
-      if (overload_resolution && (exp->language_defn->la_language
-				  == language_cplus))
-	{
-	  /* Language is C++, do some overload resolution before
-	     evaluation.  */
-	  struct symbol *symp;
-	  int no_adl = 0;
-
-	  /* If a scope has been specified disable ADL.  */
-	  if (op == OP_SCOPE)
-	    no_adl = 1;
-
-	  if (op == OP_VAR_VALUE)
-	    function = exp->elts[save_pos1+2].symbol;
-
-	  (void) find_overload_match (gdb::make_array_view (&argvec[1], nargs),
-				      NULL,        /* no need for name */
-				      NON_METHOD,  /* not method */
-				      NULL, function, /* the function */
-				      NULL, &symp, NULL, no_adl, noside);
-
-	  if (op == OP_VAR_VALUE)
-	    {
-	      /* Now fix the expression being evaluated.  */
-	      exp->elts[save_pos1+2].symbol = symp;
-	      argvec[0] = evaluate_subexp_with_coercion (exp, &save_pos1,
-							 noside);
-	    }
-	  else
-	    argvec[0] = value_of_variable (symp, get_selected_block (0));
-	}
-      else
-	{
-	  /* Not C++, or no overload resolution allowed.  */
-	  /* Nothing to be done; argvec already correctly set up.  */
-	}
-    }
-  else
-    {
-      /* It is probably a C-style function.  */
-      /* Nothing to be done; argvec already correctly set up.  */
-    }
-
-  return evaluate_subexp_do_call (exp, noside, argvec[0],
-				  gdb::make_array_view (argvec + 1, nargs),
-				  var_func_name, expect_type);
-}
-
 namespace expr
 {
 
@@ -3040,738 +2510,6 @@ array_operation::evaluate (struct type *expect_type,
 
 }
 
-struct value *
-evaluate_subexp_standard (struct type *expect_type,
-			  struct expression *exp, int *pos,
-			  enum noside noside)
-{
-  enum exp_opcode op;
-  int tem, tem2, tem3;
-  int pc, oldpos;
-  struct value *arg1 = NULL;
-  struct value *arg2 = NULL;
-  struct type *type;
-  int nargs;
-  struct value **argvec;
-  int ix;
-  struct type **arg_types;
-
-  pc = (*pos)++;
-  op = exp->elts[pc].opcode;
-
-  switch (op)
-    {
-    case OP_SCOPE:
-      tem = longest_to_int (exp->elts[pc + 2].longconst);
-      (*pos) += 4 + BYTES_TO_EXP_ELEM (tem + 1);
-      return eval_op_scope (expect_type, exp, noside,
-			    exp->elts[pc + 1].type,
-			    &exp->elts[pc + 3].string);
-
-    case OP_LONG:
-      (*pos) += 3;
-      return value_from_longest (exp->elts[pc + 1].type,
-				 exp->elts[pc + 2].longconst);
-
-    case OP_FLOAT:
-      (*pos) += 3;
-      return value_from_contents (exp->elts[pc + 1].type,
-				  exp->elts[pc + 2].floatconst);
-
-    case OP_ADL_FUNC:
-    case OP_VAR_VALUE:
-      {
-	(*pos) += 3;
-	symbol *var = exp->elts[pc + 2].symbol;
-	if (SYMBOL_TYPE (var)->code () == TYPE_CODE_ERROR)
-	  error_unknown_type (var->print_name ());
-	if (noside != EVAL_SKIP)
-	    return evaluate_var_value (noside, exp->elts[pc + 1].block, var);
-	else
-	  {
-	    /* Return a dummy value of the correct type when skipping, so
-	       that parent functions know what is to be skipped.  */
-	    return allocate_value (SYMBOL_TYPE (var));
-	  }
-      }
-
-    case OP_VAR_MSYM_VALUE:
-      {
-	(*pos) += 3;
-
-	minimal_symbol *msymbol = exp->elts[pc + 2].msymbol;
-	return eval_op_var_msym_value (expect_type, exp, noside,
-				       msymbol,
-				       exp->elts[pc + 1].objfile);
-      }
-
-    case OP_VAR_ENTRY_VALUE:
-      (*pos) += 2;
-
-      {
-	struct symbol *sym = exp->elts[pc + 1].symbol;
-
-	return eval_op_var_entry_value (expect_type, exp, noside, sym);
-      }
-
-    case OP_FUNC_STATIC_VAR:
-      tem = longest_to_int (exp->elts[pc + 1].longconst);
-      (*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1);
-      if (noside == EVAL_SKIP)
-	return eval_skip_value (exp);
-
-      {
-	value *func = evaluate_subexp_standard (NULL, exp, pos, noside);
-
-	return eval_op_func_static_var (expect_type, exp, noside, func,
-					&exp->elts[pc + 2].string);
-      }
-
-    case OP_LAST:
-      (*pos) += 2;
-      return
-	access_value_history (longest_to_int (exp->elts[pc + 1].longconst));
-
-    case OP_REGISTER:
-      {
-	const char *name = &exp->elts[pc + 2].string;
-
-	(*pos) += 3 + BYTES_TO_EXP_ELEM (exp->elts[pc + 1].longconst + 1);
-	return eval_op_register (expect_type, exp, noside, name);
-      }
-    case OP_BOOL:
-      (*pos) += 2;
-      type = language_bool_type (exp->language_defn, exp->gdbarch);
-      return value_from_longest (type, exp->elts[pc + 1].longconst);
-
-    case OP_INTERNALVAR:
-      (*pos) += 2;
-      return value_of_internalvar (exp->gdbarch,
-				   exp->elts[pc + 1].internalvar);
-
-    case OP_STRING:
-      tem = longest_to_int (exp->elts[pc + 1].longconst);
-      (*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1);
-      return eval_op_string (expect_type, exp, noside, tem,
-			     &exp->elts[pc + 2].string);
-
-    case OP_OBJC_NSSTRING:		/* Objective C Foundation Class
-					   NSString constant.  */
-      tem = longest_to_int (exp->elts[pc + 1].longconst);
-      (*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1);
-      if (noside == EVAL_SKIP)
-	return eval_skip_value (exp);
-      return value_nsstring (exp->gdbarch, &exp->elts[pc + 2].string, tem + 1);
-
-    case OP_ARRAY:
-      (*pos) += 3;
-      tem2 = longest_to_int (exp->elts[pc + 1].longconst);
-      tem3 = longest_to_int (exp->elts[pc + 2].longconst);
-      nargs = tem3 - tem2 + 1;
-      type = expect_type ? check_typedef (expect_type) : nullptr;
-
-      if (expect_type != nullptr && noside != EVAL_SKIP
-	  && type->code () == TYPE_CODE_STRUCT)
-	{
-	  struct value *rec = allocate_value (expect_type);
-
-	  memset (value_contents_raw (rec), '\0', TYPE_LENGTH (type));
-	  return evaluate_struct_tuple (rec, exp, pos, noside, nargs);
-	}
-
-      if (expect_type != nullptr && noside != EVAL_SKIP
-	  && type->code () == TYPE_CODE_ARRAY)
-	{
-	  struct type *range_type = type->index_type ();
-	  struct type *element_type = TYPE_TARGET_TYPE (type);
-	  struct value *array = allocate_value (expect_type);
-	  int element_size = TYPE_LENGTH (check_typedef (element_type));
-	  LONGEST low_bound, high_bound, index;
-
-	  if (!get_discrete_bounds (range_type, &low_bound, &high_bound))
-	    {
-	      low_bound = 0;
-	      high_bound = (TYPE_LENGTH (type) / element_size) - 1;
-	    }
-	  index = low_bound;
-	  memset (value_contents_raw (array), 0, TYPE_LENGTH (expect_type));
-	  for (tem = nargs; --nargs >= 0;)
-	    {
-	      struct value *element;
-
-	      element = evaluate_subexp (element_type, exp, pos, noside);
-	      if (value_type (element) != element_type)
-		element = value_cast (element_type, element);
-	      if (index > high_bound)
-		/* To avoid memory corruption.  */
-		error (_("Too many array elements"));
-	      memcpy (value_contents_raw (array)
-		      + (index - low_bound) * element_size,
-		      value_contents (element),
-		      element_size);
-	      index++;
-	    }
-	  return array;
-	}
-
-      if (expect_type != nullptr && noside != EVAL_SKIP
-	  && type->code () == TYPE_CODE_SET)
-	{
-	  struct value *set = allocate_value (expect_type);
-	  gdb_byte *valaddr = value_contents_raw (set);
-	  struct type *element_type = type->index_type ();
-	  struct type *check_type = element_type;
-	  LONGEST low_bound, high_bound;
-
-	  /* Get targettype of elementtype.  */
-	  while (check_type->code () == TYPE_CODE_RANGE
-		 || check_type->code () == TYPE_CODE_TYPEDEF)
-	    check_type = TYPE_TARGET_TYPE (check_type);
-
-	  if (!get_discrete_bounds (element_type, &low_bound, &high_bound))
-	    error (_("(power)set type with unknown size"));
-	  memset (valaddr, '\0', TYPE_LENGTH (type));
-	  for (tem = 0; tem < nargs; tem++)
-	    {
-	      LONGEST range_low, range_high;
-	      struct type *range_low_type, *range_high_type;
-	      struct value *elem_val;
-
-	      elem_val = evaluate_subexp (element_type, exp, pos, noside);
-	      range_low_type = range_high_type = value_type (elem_val);
-	      range_low = range_high = value_as_long (elem_val);
-
-	      /* Check types of elements to avoid mixture of elements from
-		 different types. Also check if type of element is "compatible"
-		 with element type of powerset.  */
-	      if (range_low_type->code () == TYPE_CODE_RANGE)
-		range_low_type = TYPE_TARGET_TYPE (range_low_type);
-	      if (range_high_type->code () == TYPE_CODE_RANGE)
-		range_high_type = TYPE_TARGET_TYPE (range_high_type);
-	      if ((range_low_type->code () != range_high_type->code ())
-		  || (range_low_type->code () == TYPE_CODE_ENUM
-		      && (range_low_type != range_high_type)))
-		/* different element modes.  */
-		error (_("POWERSET tuple elements of different mode"));
-	      if ((check_type->code () != range_low_type->code ())
-		  || (check_type->code () == TYPE_CODE_ENUM
-		      && range_low_type != check_type))
-		error (_("incompatible POWERSET tuple elements"));
-	      if (range_low > range_high)
-		{
-		  warning (_("empty POWERSET tuple range"));
-		  continue;
-		}
-	      if (range_low < low_bound || range_high > high_bound)
-		error (_("POWERSET tuple element out of range"));
-	      range_low -= low_bound;
-	      range_high -= low_bound;
-	      for (; range_low <= range_high; range_low++)
-		{
-		  int bit_index = (unsigned) range_low % TARGET_CHAR_BIT;
-
-		  if (gdbarch_byte_order (exp->gdbarch) == BFD_ENDIAN_BIG)
-		    bit_index = TARGET_CHAR_BIT - 1 - bit_index;
-		  valaddr[(unsigned) range_low / TARGET_CHAR_BIT]
-		    |= 1 << bit_index;
-		}
-	    }
-	  return set;
-	}
-
-      argvec = XALLOCAVEC (struct value *, nargs);
-      for (tem = 0; tem < nargs; tem++)
-	{
-	  /* Ensure that array expressions are coerced into pointer
-	     objects.  */
-	  argvec[tem] = evaluate_subexp_with_coercion (exp, pos, noside);
-	}
-      if (noside == EVAL_SKIP)
-	return eval_skip_value (exp);
-      return value_array (tem2, tem3, argvec);
-
-    case TERNOP_SLICE:
-      {
-	struct value *array = evaluate_subexp (nullptr, exp, pos, noside);
-	struct value *low = evaluate_subexp (nullptr, exp, pos, noside);
-	struct value *upper = evaluate_subexp (nullptr, exp, pos, noside);
-	return eval_op_ternop (expect_type, exp, noside, array, low, upper);
-      }
-
-    case TERNOP_COND:
-      /* Skip third and second args to evaluate the first one.  */
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      if (value_logical_not (arg1))
-	{
-	  evaluate_subexp (nullptr, exp, pos, EVAL_SKIP);
-	  return evaluate_subexp (nullptr, exp, pos, noside);
-	}
-      else
-	{
-	  arg2 = evaluate_subexp (nullptr, exp, pos, noside);
-	  evaluate_subexp (nullptr, exp, pos, EVAL_SKIP);
-	  return arg2;
-	}
-
-    case OP_OBJC_SELECTOR:
-      {				/* Objective C @selector operator.  */
-	char *sel = &exp->elts[pc + 2].string;
-	int len = longest_to_int (exp->elts[pc + 1].longconst);
-
-	(*pos) += 3 + BYTES_TO_EXP_ELEM (len + 1);
-	if (sel[len] != 0)
-	  sel[len] = 0;		/* Make sure it's terminated.  */
-
-	return eval_op_objc_selector (expect_type, exp, noside, sel);
-      }
-
-    case OP_OBJC_MSGCALL:
-      {				/* Objective C message (method) call.  */
-	CORE_ADDR selector = 0;
-
-	enum noside sub_no_side = EVAL_NORMAL;
-
-	struct value *target = NULL;
-
-	struct type *selector_type = NULL;
-
-	selector = exp->elts[pc + 1].longconst;
-	nargs = exp->elts[pc + 2].longconst;
-	argvec = XALLOCAVEC (struct value *, nargs + 3);
-
-	(*pos) += 3;
-
-	selector_type = builtin_type (exp->gdbarch)->builtin_data_ptr;
-
-	if (noside == EVAL_AVOID_SIDE_EFFECTS)
-	  sub_no_side = EVAL_NORMAL;
-	else
-	  sub_no_side = noside;
-
-	target = evaluate_subexp (selector_type, exp, pos, sub_no_side);
-
-	if (value_as_long (target) == 0)
-	  sub_no_side = EVAL_SKIP;
-	else
-	  sub_no_side = noside;
-
-	/* Now depending on whether we found a symbol for the method,
-	   we will either call the runtime dispatcher or the method
-	   directly.  */
-
-	argvec[0] = nullptr;
-	argvec[1] = nullptr;
-	/* User-supplied arguments.  */
-	for (tem = 0; tem < nargs; tem++)
-	  argvec[tem + 2] = evaluate_subexp_with_coercion (exp, pos,
-							   sub_no_side);
-	argvec[tem + 3] = 0;
-
-	auto call_args = gdb::make_array_view (argvec, nargs + 3);
-
-	return eval_op_objc_msgcall (expect_type, exp, noside, selector,
-				     target, call_args);
-      }
-      break;
-
-    case OP_FUNCALL:
-      return evaluate_funcall (expect_type, exp, pos, noside);
-
-    case OP_COMPLEX:
-      /* We have a complex number, There should be 2 floating 
-	 point numbers that compose it.  */
-      (*pos) += 2;
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      arg2 = evaluate_subexp (nullptr, exp, pos, noside);
-
-      return value_literal_complex (arg1, arg2, exp->elts[pc + 1].type);
-
-    case STRUCTOP_STRUCT:
-      tem = longest_to_int (exp->elts[pc + 1].longconst);
-      (*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1);
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      return eval_op_structop_struct (expect_type, exp, noside, arg1,
-				      &exp->elts[pc + 2].string);
-
-    case STRUCTOP_PTR:
-      tem = longest_to_int (exp->elts[pc + 1].longconst);
-      (*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1);
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      return eval_op_structop_ptr (expect_type, exp, noside, arg1,
-				   &exp->elts[pc + 2].string);
-
-    case STRUCTOP_MEMBER:
-    case STRUCTOP_MPTR:
-      if (op == STRUCTOP_MEMBER)
-	arg1 = evaluate_subexp_for_address (exp, pos, noside);
-      else
-	arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-
-      arg2 = evaluate_subexp (nullptr, exp, pos, noside);
-
-      return eval_op_member (expect_type, exp, noside, arg1, arg2);
-
-    case TYPE_INSTANCE:
-      {
-	type_instance_flags flags
-	  = (type_instance_flag_value) longest_to_int (exp->elts[pc + 1].longconst);
-	nargs = longest_to_int (exp->elts[pc + 2].longconst);
-	arg_types = (struct type **) alloca (nargs * sizeof (struct type *));
-	for (ix = 0; ix < nargs; ++ix)
-	  arg_types[ix] = exp->elts[pc + 2 + ix + 1].type;
-
-	fake_method fake_expect_type (flags, nargs, arg_types);
-	*(pos) += 4 + nargs;
-	return evaluate_subexp_standard (fake_expect_type.type (), exp, pos,
-					 noside);
-      }
-
-    case BINOP_CONCAT:
-      arg1 = evaluate_subexp_with_coercion (exp, pos, noside);
-      arg2 = evaluate_subexp_with_coercion (exp, pos, noside);
-      return eval_op_concat (expect_type, exp, noside, arg1, arg2);
-
-    case BINOP_ASSIGN:
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      /* Special-case assignments where the left-hand-side is a
-	 convenience variable -- in these, don't bother setting an
-	 expected type.  This avoids a weird case where re-assigning a
-	 string or array to an internal variable could error with "Too
-	 many array elements".  */
-      arg2 = evaluate_subexp (VALUE_LVAL (arg1) == lval_internalvar
-				? nullptr
-				: value_type (arg1),
-			      exp, pos, noside);
-
-      if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS)
-	return arg1;
-      if (binop_user_defined_p (op, arg1, arg2))
-	return value_x_binop (arg1, arg2, op, OP_NULL, noside);
-      else
-	return value_assign (arg1, arg2);
-
-    case BINOP_ASSIGN_MODIFY:
-      (*pos) += 2;
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      arg2 = evaluate_subexp (value_type (arg1), exp, pos, noside);
-      op = exp->elts[pc + 1].opcode;
-      return eval_binop_assign_modify (expect_type, exp, noside, op,
-				       arg1, arg2);
-
-    case BINOP_ADD:
-      arg1 = evaluate_subexp_with_coercion (exp, pos, noside);
-      arg2 = evaluate_subexp_with_coercion (exp, pos, noside);
-      return eval_op_add (expect_type, exp, noside, arg1, arg2);
-
-    case BINOP_SUB:
-      arg1 = evaluate_subexp_with_coercion (exp, pos, noside);
-      arg2 = evaluate_subexp_with_coercion (exp, pos, noside);
-      return eval_op_sub (expect_type, exp, noside, arg1, arg2);
-
-    case BINOP_EXP:
-    case BINOP_MUL:
-    case BINOP_DIV:
-    case BINOP_INTDIV:
-    case BINOP_REM:
-    case BINOP_MOD:
-    case BINOP_LSH:
-    case BINOP_RSH:
-    case BINOP_BITWISE_AND:
-    case BINOP_BITWISE_IOR:
-    case BINOP_BITWISE_XOR:
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      arg2 = evaluate_subexp (nullptr, exp, pos, noside);
-      return eval_op_binary (expect_type, exp, noside, op, arg1, arg2);
-
-    case BINOP_SUBSCRIPT:
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      arg2 = evaluate_subexp (nullptr, exp, pos, noside);
-      return eval_op_subscript (expect_type, exp, noside, op, arg1, arg2);
-
-    case MULTI_SUBSCRIPT:
-      (*pos) += 2;
-      nargs = longest_to_int (exp->elts[pc + 1].longconst);
-      arg1 = evaluate_subexp_with_coercion (exp, pos, noside);
-      argvec = XALLOCAVEC (struct value *, nargs);
-      for (ix = 0; ix < nargs; ++ix)
-	argvec[ix] = evaluate_subexp_with_coercion (exp, pos, noside);
-      return eval_multi_subscript (expect_type, exp, noside, arg1,
-				   gdb::make_array_view (argvec, nargs));
-
-    case BINOP_LOGICAL_AND:
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      if (noside == EVAL_SKIP)
-	{
-	  evaluate_subexp (nullptr, exp, pos, noside);
-	  return eval_skip_value (exp);
-	}
-
-      oldpos = *pos;
-      arg2 = evaluate_subexp (nullptr, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
-      *pos = oldpos;
-
-      if (binop_user_defined_p (op, arg1, arg2))
-	{
-	  arg2 = evaluate_subexp (nullptr, exp, pos, noside);
-	  return value_x_binop (arg1, arg2, op, OP_NULL, noside);
-	}
-      else
-	{
-	  tem = value_logical_not (arg1);
-	  arg2
-	    = evaluate_subexp (nullptr, exp, pos, (tem ? EVAL_SKIP : noside));
-	  type = language_bool_type (exp->language_defn, exp->gdbarch);
-	  return value_from_longest (type,
-			     (LONGEST) (!tem && !value_logical_not (arg2)));
-	}
-
-    case BINOP_LOGICAL_OR:
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      if (noside == EVAL_SKIP)
-	{
-	  evaluate_subexp (nullptr, exp, pos, noside);
-	  return eval_skip_value (exp);
-	}
-
-      oldpos = *pos;
-      arg2 = evaluate_subexp (nullptr, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
-      *pos = oldpos;
-
-      if (binop_user_defined_p (op, arg1, arg2))
-	{
-	  arg2 = evaluate_subexp (nullptr, exp, pos, noside);
-	  return value_x_binop (arg1, arg2, op, OP_NULL, noside);
-	}
-      else
-	{
-	  tem = value_logical_not (arg1);
-	  arg2
-	    = evaluate_subexp (nullptr, exp, pos, (!tem ? EVAL_SKIP : noside));
-	  type = language_bool_type (exp->language_defn, exp->gdbarch);
-	  return value_from_longest (type,
-			     (LONGEST) (!tem || !value_logical_not (arg2)));
-	}
-
-    case BINOP_EQUAL:
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      arg2 = evaluate_subexp (value_type (arg1), exp, pos, noside);
-      return eval_op_equal (expect_type, exp, noside, op, arg1, arg2);
-
-    case BINOP_NOTEQUAL:
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      arg2 = evaluate_subexp (value_type (arg1), exp, pos, noside);
-      return eval_op_notequal (expect_type, exp, noside, op, arg1, arg2);
-
-    case BINOP_LESS:
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      arg2 = evaluate_subexp (value_type (arg1), exp, pos, noside);
-      return eval_op_less (expect_type, exp, noside, op, arg1, arg2);
-
-    case BINOP_GTR:
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      arg2 = evaluate_subexp (value_type (arg1), exp, pos, noside);
-      return eval_op_gtr (expect_type, exp, noside, op, arg1, arg2);
-
-    case BINOP_GEQ:
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      arg2 = evaluate_subexp (value_type (arg1), exp, pos, noside);
-      return eval_op_geq (expect_type, exp, noside, op, arg1, arg2);
-
-    case BINOP_LEQ:
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      arg2 = evaluate_subexp (value_type (arg1), exp, pos, noside);
-      return eval_op_leq (expect_type, exp, noside, op, arg1, arg2);
-
-    case BINOP_REPEAT:
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      arg2 = evaluate_subexp (nullptr, exp, pos, noside);
-      return eval_op_repeat (expect_type, exp, noside, op, arg1, arg2);
-
-    case BINOP_COMMA:
-      evaluate_subexp (nullptr, exp, pos, noside);
-      return evaluate_subexp (nullptr, exp, pos, noside);
-
-    case UNOP_PLUS:
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      return eval_op_plus (expect_type, exp, noside, op, arg1);
-      
-    case UNOP_NEG:
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      return eval_op_neg (expect_type, exp, noside, op, arg1);
-
-    case UNOP_COMPLEMENT:
-      /* C++: check for and handle destructor names.  */
-
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      return eval_op_complement (expect_type, exp, noside, op, arg1);
-
-    case UNOP_LOGICAL_NOT:
-      arg1 = evaluate_subexp (nullptr, exp, pos, noside);
-      return eval_op_lognot (expect_type, exp, noside, op, arg1);
-
-    case UNOP_IND:
-      if (expect_type && expect_type->code () == TYPE_CODE_PTR)
-	expect_type = TYPE_TARGET_TYPE (check_typedef (expect_type));
-      arg1 = evaluate_subexp (expect_type, exp, pos, noside);
-      return eval_op_ind (expect_type, exp, noside, arg1);
-
-    case UNOP_ADDR:
-      /* C++: check for and handle pointer to members.  */
-
-      if (noside == EVAL_SKIP)
-	{
-	  evaluate_subexp (nullptr, exp, pos, EVAL_SKIP);
-	  return eval_skip_value (exp);
-	}
-      else
-	return evaluate_subexp_for_address (exp, pos, noside);
-
-    case UNOP_SIZEOF:
-      if (noside == EVAL_SKIP)
-	{
-	  evaluate_subexp (nullptr, exp, pos, EVAL_SKIP);
-	  return eval_skip_value (exp);
-	}
-      return evaluate_subexp_for_sizeof (exp, pos, noside);
-
-    case UNOP_ALIGNOF:
-      arg1 = evaluate_subexp (nullptr, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
-      return eval_op_alignof (expect_type, exp, noside, arg1);
-
-    case UNOP_CAST:
-      (*pos) += 2;
-      type = exp->elts[pc + 1].type;
-      return evaluate_subexp_for_cast (exp, pos, noside, type);
-
-    case UNOP_CAST_TYPE:
-      arg1 = evaluate_subexp (NULL, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
-      type = value_type (arg1);
-      return evaluate_subexp_for_cast (exp, pos, noside, type);
-
-    case UNOP_DYNAMIC_CAST:
-      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)
-	return eval_skip_value (exp);
-      return value_dynamic_cast (type, arg1);
-
-    case UNOP_REINTERPRET_CAST:
-      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)
-	return eval_skip_value (exp);
-      return value_reinterpret_cast (type, arg1);
-
-    case UNOP_MEMVAL:
-      (*pos) += 2;
-      arg1 = evaluate_subexp (expect_type, exp, pos, noside);
-      return eval_op_memval (expect_type, exp, noside, arg1,
-			     exp->elts[pc + 1].type);
-
-    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);
-      return eval_op_memval (expect_type, exp, noside, arg1, type);
-
-    case UNOP_PREINCREMENT:
-      arg1 = evaluate_subexp (expect_type, exp, pos, noside);
-      return eval_op_preinc (expect_type, exp, noside, op, arg1);
-
-    case UNOP_PREDECREMENT:
-      arg1 = evaluate_subexp (expect_type, exp, pos, noside);
-      return eval_op_predec (expect_type, exp, noside, op, arg1);
-
-    case UNOP_POSTINCREMENT:
-      arg1 = evaluate_subexp (expect_type, exp, pos, noside);
-      return eval_op_postinc (expect_type, exp, noside, op, arg1);
-
-    case UNOP_POSTDECREMENT:
-      arg1 = evaluate_subexp (expect_type, exp, pos, noside);
-      return eval_op_postdec (expect_type, exp, noside, op, arg1);
-
-    case OP_THIS:
-      (*pos) += 1;
-      return value_of_this (exp->language_defn);
-
-    case OP_TYPE:
-      /* The value is not supposed to be used.  This is here to make it
-	 easier to accommodate expressions that contain types.  */
-      (*pos) += 2;
-      return eval_op_type (expect_type, exp, noside, exp->elts[pc + 1].type);
-
-    case OP_TYPEOF:
-    case OP_DECLTYPE:
-      if (noside == EVAL_SKIP)
-	{
-	  evaluate_subexp (nullptr, exp, pos, EVAL_SKIP);
-	  return eval_skip_value (exp);
-	}
-      else if (noside == EVAL_AVOID_SIDE_EFFECTS)
-	{
-	  enum exp_opcode sub_op = exp->elts[*pos].opcode;
-	  struct value *result;
-
-	  result = evaluate_subexp (nullptr, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
-
-	  /* 'decltype' has special semantics for lvalues.  */
-	  if (op == OP_DECLTYPE
-	      && (sub_op == BINOP_SUBSCRIPT
-		  || sub_op == STRUCTOP_MEMBER
-		  || sub_op == STRUCTOP_MPTR
-		  || sub_op == UNOP_IND
-		  || sub_op == STRUCTOP_STRUCT
-		  || sub_op == STRUCTOP_PTR
-		  || sub_op == OP_SCOPE))
-	    {
-	      type = value_type (result);
-
-	      if (!TYPE_IS_REFERENCE (type))
-		{
-		  type = lookup_lvalue_reference_type (type);
-		  result = allocate_value (type);
-		}
-	    }
-
-	  return result;
-	}
-      else
-	error (_("Attempt to use a type as an expression"));
-
-    case OP_TYPEID:
-      {
-	struct value *result;
-	enum exp_opcode sub_op = exp->elts[*pos].opcode;
-
-	if (sub_op == OP_TYPE || sub_op == OP_DECLTYPE || sub_op == OP_TYPEOF)
-	  result = evaluate_subexp (nullptr, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
-	else
-	  result = evaluate_subexp (nullptr, exp, pos, noside);
-
-	if (noside != EVAL_NORMAL)
-	  return allocate_value (cplus_typeid_type (exp->gdbarch));
-
-	return cplus_typeid (result);
-      }
-
-    default:
-      /* Removing this case and compiling with gcc -Wall reveals that
-	 a lot of cases are hitting this case.  Some of these should
-	 probably be removed from expression.h; others are legitimate
-	 expressions which are (apparently) not fully implemented.
-
-	 If there are any cases landing here which mean a user error,
-	 then they should be separate cases, with more descriptive
-	 error messages.  */
-
-      error (_("GDB does not (yet) know how to "
-	       "evaluate that kind of expression"));
-    }
-
-  gdb_assert_not_reached ("missed return?");
-}
 \f
 /* Helper for evaluate_subexp_for_address.  */
 
@@ -3796,117 +2534,6 @@ evaluate_subexp_for_address_base (struct expression *exp, enum noside noside,
   return value_addr (x);
 }
 
-/* Evaluate a subexpression of EXP, at index *POS,
-   and return the address of that subexpression.
-   Advance *POS over the subexpression.
-   If the subexpression isn't an lvalue, get an error.
-   NOSIDE may be EVAL_AVOID_SIDE_EFFECTS;
-   then only the type of the result need be correct.  */
-
-static struct value *
-evaluate_subexp_for_address (struct expression *exp, int *pos,
-			     enum noside noside)
-{
-  enum exp_opcode op;
-  int pc;
-  struct symbol *var;
-  struct value *x;
-  int tem;
-
-  pc = (*pos);
-  op = exp->elts[pc].opcode;
-
-  switch (op)
-    {
-    case UNOP_IND:
-      (*pos)++;
-      x = evaluate_subexp (nullptr, exp, pos, noside);
-
-      /* We can't optimize out "&*" if there's a user-defined operator*.  */
-      if (unop_user_defined_p (op, x))
-	{
-	  x = value_x_unop (x, op, noside);
-	  goto default_case_after_eval;
-	}
-
-      return coerce_array (x);
-
-    case UNOP_MEMVAL:
-      (*pos) += 3;
-      return value_cast (lookup_pointer_type (exp->elts[pc + 1].type),
-			 evaluate_subexp (nullptr, exp, pos, noside));
-
-    case UNOP_MEMVAL_TYPE:
-      {
-	struct type *type;
-
-	(*pos) += 1;
-	x = evaluate_subexp (nullptr, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
-	type = value_type (x);
-	return value_cast (lookup_pointer_type (type),
-			   evaluate_subexp (nullptr, exp, pos, noside));
-      }
-
-    case OP_VAR_VALUE:
-      var = exp->elts[pc + 2].symbol;
-
-      /* C++: The "address" of a reference should yield the address
-       * of the object pointed to.  Let value_addr() deal with it.  */
-      if (TYPE_IS_REFERENCE (SYMBOL_TYPE (var)))
-	goto default_case;
-
-      (*pos) += 4;
-      if (noside == EVAL_AVOID_SIDE_EFFECTS)
-	{
-	  struct type *type =
-	    lookup_pointer_type (SYMBOL_TYPE (var));
-	  enum address_class sym_class = SYMBOL_CLASS (var);
-
-	  if (sym_class == LOC_CONST
-	      || sym_class == LOC_CONST_BYTES
-	      || sym_class == LOC_REGISTER)
-	    error (_("Attempt to take address of register or constant."));
-
-	  return
-	    value_zero (type, not_lval);
-	}
-      else
-	return address_of_variable (var, exp->elts[pc + 1].block);
-
-    case OP_VAR_MSYM_VALUE:
-      {
-	(*pos) += 4;
-
-	value *val = evaluate_var_msym_value (noside,
-					      exp->elts[pc + 1].objfile,
-					      exp->elts[pc + 2].msymbol);
-	if (noside == EVAL_AVOID_SIDE_EFFECTS)
-	  {
-	    struct type *type = lookup_pointer_type (value_type (val));
-	    return value_zero (type, not_lval);
-	  }
-	else
-	  return value_addr (val);
-      }
-
-    case OP_SCOPE:
-      tem = longest_to_int (exp->elts[pc + 2].longconst);
-      (*pos) += 5 + BYTES_TO_EXP_ELEM (tem + 1);
-      x = value_aggregate_elt (exp->elts[pc + 1].type,
-			       &exp->elts[pc + 3].string,
-			       NULL, 1, noside);
-      if (x == NULL)
-	error (_("There is no field named %s"), &exp->elts[pc + 3].string);
-      return x;
-
-    default:
-    default_case:
-      x = evaluate_subexp (nullptr, exp, pos, noside);
-    default_case_after_eval:
-      return evaluate_subexp_for_address_base (exp, noside, x);
-    }
-}
-
 namespace expr
 {
 
@@ -3993,51 +2620,6 @@ unop_memval_type_operation::evaluate_for_address (struct expression *exp,
 
 }
 
-/* Evaluate like `evaluate_subexp' except coercing arrays to pointers.
-   When used in contexts where arrays will be coerced anyway, this is
-   equivalent to `evaluate_subexp' but much faster because it avoids
-   actually fetching array contents (perhaps obsolete now that we have
-   value_lazy()).
-
-   Note that we currently only do the coercion for C expressions, where
-   arrays are zero based and the coercion is correct.  For other languages,
-   with nonzero based arrays, coercion loses.  Use CAST_IS_CONVERSION
-   to decide if coercion is appropriate.  */
-
-struct value *
-evaluate_subexp_with_coercion (struct expression *exp,
-			       int *pos, enum noside noside)
-{
-  enum exp_opcode op;
-  int pc;
-  struct value *val;
-  struct symbol *var;
-  struct type *type;
-
-  pc = (*pos);
-  op = exp->elts[pc].opcode;
-
-  switch (op)
-    {
-    case OP_VAR_VALUE:
-      var = exp->elts[pc + 2].symbol;
-      type = check_typedef (SYMBOL_TYPE (var));
-      if (type->code () == TYPE_CODE_ARRAY
-	  && !type->is_vector ()
-	  && CAST_IS_CONVERSION (exp->language_defn))
-	{
-	  (*pos) += 4;
-	  val = address_of_variable (var, exp->elts[pc + 1].block);
-	  return value_cast (lookup_pointer_type (TYPE_TARGET_TYPE (type)),
-			     val);
-	}
-      /* FALLTHROUGH */
-
-    default:
-      return evaluate_subexp (nullptr, exp, pos, noside);
-    }
-}
-
 namespace expr
 {
 
@@ -4103,132 +2685,6 @@ evaluate_subexp_for_sizeof_base (struct expression *exp, struct type *type)
   return value_from_longest (size_type, (LONGEST) TYPE_LENGTH (type));
 }
 
-/* Evaluate a subexpression of EXP, at index *POS,
-   and return a value for the size of that subexpression.
-   Advance *POS over the subexpression.  If NOSIDE is EVAL_NORMAL
-   we allow side-effects on the operand if its type is a variable
-   length array.   */
-
-static struct value *
-evaluate_subexp_for_sizeof (struct expression *exp, int *pos,
-			    enum noside noside)
-{
-  /* FIXME: This should be size_t.  */
-  struct type *size_type = builtin_type (exp->gdbarch)->builtin_int;
-  enum exp_opcode op;
-  int pc;
-  struct type *type;
-  struct value *val;
-
-  pc = (*pos);
-  op = exp->elts[pc].opcode;
-
-  switch (op)
-    {
-      /* This case is handled specially
-	 so that we avoid creating a value for the result type.
-	 If the result type is very big, it's desirable not to
-	 create a value unnecessarily.  */
-    case UNOP_IND:
-      (*pos)++;
-      val = evaluate_subexp (nullptr, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
-      type = check_typedef (value_type (val));
-      if (type->code () != TYPE_CODE_PTR
-	  && !TYPE_IS_REFERENCE (type)
-	  && type->code () != TYPE_CODE_ARRAY)
-	error (_("Attempt to take contents of a non-pointer value."));
-      type = TYPE_TARGET_TYPE (type);
-      if (is_dynamic_type (type))
-	type = value_type (value_ind (val));
-      return value_from_longest (size_type, (LONGEST) TYPE_LENGTH (type));
-
-    case UNOP_MEMVAL:
-      (*pos) += 3;
-      type = exp->elts[pc + 1].type;
-      break;
-
-    case UNOP_MEMVAL_TYPE:
-      (*pos) += 1;
-      val = evaluate_subexp (NULL, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
-      type = value_type (val);
-      break;
-
-    case OP_VAR_VALUE:
-      type = SYMBOL_TYPE (exp->elts[pc + 2].symbol);
-      if (is_dynamic_type (type))
-	{
-	  val = evaluate_subexp (nullptr, exp, pos, EVAL_NORMAL);
-	  type = value_type (val);
-	  if (type->code () == TYPE_CODE_ARRAY)
-	    {
-	      if (type_not_allocated (type) || type_not_associated (type))
-		return value_zero (size_type, not_lval);
-	      else if (is_dynamic_type (type->index_type ())
-		       && type->bounds ()->high.kind () == PROP_UNDEFINED)
-		return allocate_optimized_out_value (size_type);
-	    }
-	}
-      else
-	(*pos) += 4;
-      break;
-
-    case OP_VAR_MSYM_VALUE:
-      {
-	(*pos) += 4;
-
-	minimal_symbol *msymbol = exp->elts[pc + 2].msymbol;
-	value *mval = evaluate_var_msym_value (noside,
-					       exp->elts[pc + 1].objfile,
-					       msymbol);
-
-	type = value_type (mval);
-	if (type->code () == TYPE_CODE_ERROR)
-	  error_unknown_type (msymbol->print_name ());
-
-	return value_from_longest (size_type, TYPE_LENGTH (type));
-      }
-      break;
-
-      /* Deal with the special case if NOSIDE is EVAL_NORMAL and the resulting
-	 type of the subscript is a variable length array type. In this case we
-	 must re-evaluate the right hand side of the subscription to allow
-	 side-effects. */
-    case BINOP_SUBSCRIPT:
-      if (noside == EVAL_NORMAL)
-	{
-	  int npc = (*pos) + 1;
-
-	  val = evaluate_subexp (nullptr, exp, &npc, EVAL_AVOID_SIDE_EFFECTS);
-	  type = check_typedef (value_type (val));
-	  if (type->code () == TYPE_CODE_ARRAY)
-	    {
-	      type = check_typedef (TYPE_TARGET_TYPE (type));
-	      if (type->code () == TYPE_CODE_ARRAY)
-		{
-		  type = type->index_type ();
-		  /* Only re-evaluate the right hand side if the resulting type
-		     is a variable length type.  */
-		  if (type->bounds ()->flag_bound_evaluated)
-		    {
-		      val = evaluate_subexp (nullptr, exp, pos, EVAL_NORMAL);
-		      return value_from_longest
-			(size_type, (LONGEST) TYPE_LENGTH (value_type (val)));
-		    }
-		}
-	    }
-	}
-
-      /* Fall through.  */
-
-    default:
-      val = evaluate_subexp (nullptr, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
-      type = value_type (val);
-      break;
-    }
-
-  return evaluate_subexp_for_sizeof_base (exp, type);
-}
-
 namespace expr
 {
 
@@ -4349,61 +2805,6 @@ var_value_operation::evaluate_for_sizeof (struct expression *exp,
 
 }
 
-/* Evaluate a subexpression of EXP, at index *POS, and return a value
-   for that subexpression cast to TO_TYPE.  Advance *POS over the
-   subexpression.  */
-
-static value *
-evaluate_subexp_for_cast (expression *exp, int *pos,
-			  enum noside noside,
-			  struct type *to_type)
-{
-  int pc = *pos;
-
-  /* Don't let symbols be evaluated with evaluate_subexp because that
-     throws an "unknown type" error for no-debug data symbols.
-     Instead, we want the cast to reinterpret the symbol.  */
-  if (exp->elts[pc].opcode == OP_VAR_MSYM_VALUE
-      || exp->elts[pc].opcode == OP_VAR_VALUE)
-    {
-      (*pos) += 4;
-
-      value *val;
-      if (exp->elts[pc].opcode == OP_VAR_MSYM_VALUE)
-	{
-	  if (noside == EVAL_AVOID_SIDE_EFFECTS)
-	    return value_zero (to_type, not_lval);
-
-	  val = evaluate_var_msym_value (noside,
-					 exp->elts[pc + 1].objfile,
-					 exp->elts[pc + 2].msymbol);
-	}
-      else
-	val = evaluate_var_value (noside,
-				  exp->elts[pc + 1].block,
-				  exp->elts[pc + 2].symbol);
-
-      if (noside == EVAL_SKIP)
-	return eval_skip_value (exp);
-
-      val = value_cast (to_type, val);
-
-      /* Don't allow e.g. '&(int)var_with_no_debug_info'.  */
-      if (VALUE_LVAL (val) == lval_memory)
-	{
-	  if (value_lazy (val))
-	    value_fetch_lazy (val);
-	  VALUE_LVAL (val) = not_lval;
-	}
-      return val;
-    }
-
-  value *val = evaluate_subexp (to_type, exp, pos, noside);
-  if (noside == EVAL_SKIP)
-    return eval_skip_value (exp);
-  return value_cast (to_type, val);
-}
-
 namespace expr
 {
 
@@ -4473,15 +2874,9 @@ parse_and_eval_type (const char *p, int length)
   tmp[length + 2] = '0';
   tmp[length + 3] = '\0';
   expression_up expr = parse_expression (tmp);
-  if (expr->first_opcode () != UNOP_CAST)
+  expr::unop_cast_operation *op
+    = dynamic_cast<expr::unop_cast_operation *> (expr->op.get ());
+  if (op == nullptr)
     error (_("Internal error in eval_type."));
-
-  if (expr->op != nullptr)
-    {
-      expr::unop_cast_operation *op
-	= dynamic_cast<expr::unop_cast_operation *> (expr->op.get ());
-      return op->get_type ();
-    }
-
-  return expr->elts[1].type;
+  return op->get_type ();
 }
diff --git a/gdb/expprint.c b/gdb/expprint.c
index 1a6634a7b7f..5e55e77b5a2 100644
--- a/gdb/expprint.c
+++ b/gdb/expprint.c
@@ -36,661 +36,6 @@
 
 #include <ctype.h>
 
-void
-print_expression (struct expression *exp, struct ui_file *stream)
-{
-  int pc = 0;
-
-  print_subexp (exp, &pc, stream, PREC_NULL);
-}
-
-/* Print the subexpression of EXP that starts in position POS, on STREAM.
-   PREC is the precedence of the surrounding operator;
-   if the precedence of the main operator of this subexpression is less,
-   parentheses are needed here.  */
-
-void
-print_subexp (struct expression *exp, int *pos,
-	      struct ui_file *stream, enum precedence prec)
-{
-  exp->language_defn->expression_ops ()->print_subexp (exp, pos, stream,
-						       prec);
-}
-
-/* See parser-defs.h.  */
-
-void
-print_subexp_funcall (struct expression *exp, int *pos,
-		      struct ui_file *stream)
-{
-  unsigned nargs = longest_to_int (exp->elts[*pos].longconst);
-  (*pos) += 2;
-  print_subexp (exp, pos, stream, PREC_SUFFIX);
-  fputs_filtered (" (", stream);
-  for (unsigned tem = 0; tem < nargs; tem++)
-    {
-      if (tem != 0)
-	fputs_filtered (", ", stream);
-      print_subexp (exp, pos, stream, PREC_ABOVE_COMMA);
-    }
-  fputs_filtered (")", stream);
-}
-
-/* Standard implementation of print_subexp for use in language_defn
-   vectors.  */
-void
-print_subexp_standard (struct expression *exp, int *pos,
-		       struct ui_file *stream, enum precedence prec)
-{
-  unsigned tem;
-  const struct op_print *op_print_tab;
-  int pc;
-  unsigned nargs;
-  const char *op_str;
-  int assign_modify = 0;
-  enum exp_opcode opcode;
-  enum precedence myprec = PREC_NULL;
-  /* Set to 1 for a right-associative operator.  */
-  int assoc = 0;
-  struct value *val;
-  char *tempstr = NULL;
-
-  op_print_tab = exp->language_defn->opcode_print_table ();
-  pc = (*pos)++;
-  opcode = exp->elts[pc].opcode;
-  switch (opcode)
-    {
-      /* Common ops */
-
-    case OP_TYPE:
-      (*pos) += 2;
-      type_print (exp->elts[pc + 1].type, "", stream, 0);
-      return;
-
-    case OP_SCOPE:
-      myprec = PREC_PREFIX;
-      assoc = 0;
-      fputs_filtered (exp->elts[pc + 1].type->name (), stream);
-      fputs_filtered ("::", stream);
-      nargs = longest_to_int (exp->elts[pc + 2].longconst);
-      (*pos) += 4 + BYTES_TO_EXP_ELEM (nargs + 1);
-      fputs_filtered (&exp->elts[pc + 3].string, stream);
-      return;
-
-    case OP_LONG:
-      {
-	struct value_print_options opts;
-
-	get_no_prettyformat_print_options (&opts);
-	(*pos) += 3;
-	value_print (value_from_longest (exp->elts[pc + 1].type,
-					 exp->elts[pc + 2].longconst),
-		     stream, &opts);
-      }
-      return;
-
-    case OP_FLOAT:
-      {
-	struct value_print_options opts;
-
-	get_no_prettyformat_print_options (&opts);
-	(*pos) += 3;
-	value_print (value_from_contents (exp->elts[pc + 1].type,
-					  exp->elts[pc + 2].floatconst),
-		     stream, &opts);
-      }
-      return;
-
-    case OP_VAR_VALUE:
-      {
-	const struct block *b;
-
-	(*pos) += 3;
-	b = exp->elts[pc + 1].block;
-	if (b != NULL
-	    && BLOCK_FUNCTION (b) != NULL
-	    && BLOCK_FUNCTION (b)->print_name () != NULL)
-	  {
-	    fputs_filtered (BLOCK_FUNCTION (b)->print_name (), stream);
-	    fputs_filtered ("::", stream);
-	  }
-	fputs_filtered (exp->elts[pc + 2].symbol->print_name (), stream);
-      }
-      return;
-
-    case OP_VAR_MSYM_VALUE:
-      {
-	(*pos) += 3;
-	fputs_filtered (exp->elts[pc + 2].msymbol->print_name (), stream);
-      }
-      return;
-
-    case OP_FUNC_STATIC_VAR:
-      {
-	tem = longest_to_int (exp->elts[pc + 1].longconst);
-	(*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1);
-	fputs_filtered (&exp->elts[pc + 1].string, stream);
-      }
-      return;
-
-    case OP_VAR_ENTRY_VALUE:
-      {
-	(*pos) += 2;
-	fprintf_filtered (stream, "%s@entry",
-			  exp->elts[pc + 1].symbol->print_name ());
-      }
-      return;
-
-    case OP_LAST:
-      (*pos) += 2;
-      fprintf_filtered (stream, "$%d",
-			longest_to_int (exp->elts[pc + 1].longconst));
-      return;
-
-    case OP_REGISTER:
-      {
-	const char *name = &exp->elts[pc + 2].string;
-
-	(*pos) += 3 + BYTES_TO_EXP_ELEM (exp->elts[pc + 1].longconst + 1);
-	fprintf_filtered (stream, "$%s", name);
-	return;
-      }
-
-    case OP_BOOL:
-      (*pos) += 2;
-      fprintf_filtered (stream, "%s",
-			longest_to_int (exp->elts[pc + 1].longconst)
-			? "TRUE" : "FALSE");
-      return;
-
-    case OP_INTERNALVAR:
-      (*pos) += 2;
-      fprintf_filtered (stream, "$%s",
-			internalvar_name (exp->elts[pc + 1].internalvar));
-      return;
-
-    case OP_FUNCALL:
-      print_subexp_funcall (exp, pos, stream);
-      return;
-
-    case OP_NAME:
-      nargs = longest_to_int (exp->elts[pc + 1].longconst);
-      (*pos) += 3 + BYTES_TO_EXP_ELEM (nargs + 1);
-      fputs_filtered (&exp->elts[pc + 2].string, stream);
-      return;
-
-    case OP_STRING:
-      {
-	struct value_print_options opts;
-
-	nargs = longest_to_int (exp->elts[pc + 1].longconst);
-	(*pos) += 3 + BYTES_TO_EXP_ELEM (nargs + 1);
-	/* LA_PRINT_STRING will print using the current repeat count threshold.
-	   If necessary, we can temporarily set it to zero, or pass it as an
-	   additional parameter to LA_PRINT_STRING.  -fnf */
-	get_user_print_options (&opts);
-	exp->language_defn
-	  ->printstr (stream, builtin_type (exp->gdbarch)->builtin_char,
-		      (gdb_byte *) &exp->elts[pc + 2].string, nargs,
-		      NULL, 0, &opts);
-      }
-      return;
-
-    case OP_OBJC_NSSTRING:	/* Objective-C Foundation Class
-				   NSString constant.  */
-      {
-	struct value_print_options opts;
-
-	nargs = longest_to_int (exp->elts[pc + 1].longconst);
-	(*pos) += 3 + BYTES_TO_EXP_ELEM (nargs + 1);
-	fputs_filtered ("@\"", stream);
-	get_user_print_options (&opts);
-	exp->language_defn
-	  ->printstr (stream, builtin_type (exp->gdbarch)->builtin_char,
-		      (gdb_byte *) &exp->elts[pc + 2].string, nargs,
-		      NULL, 0, &opts);
-	fputs_filtered ("\"", stream);
-      }
-      return;
-
-    case OP_OBJC_MSGCALL:
-      {			/* Objective C message (method) call.  */
-	(*pos) += 3;
-	nargs = longest_to_int (exp->elts[pc + 2].longconst);
-	fprintf_unfiltered (stream, "[");
-	print_subexp (exp, pos, stream, PREC_SUFFIX);
-	gdb::unique_xmalloc_ptr<char> selector
-	  = target_read_string (exp->elts[pc + 1].longconst, 1024);
-	if (selector == nullptr)
-	  error (_("bad selector"));
-	if (nargs)
-	  {
-	    char *s, *nextS;
-
-	    s = selector.get ();
-	    for (tem = 0; tem < nargs; tem++)
-	      {
-		nextS = strchr (s, ':');
-		gdb_assert (nextS);	/* Make sure we found ':'.  */
-		*nextS = '\0';
-		fprintf_unfiltered (stream, " %s: ", s);
-		s = nextS + 1;
-		print_subexp (exp, pos, stream, PREC_ABOVE_COMMA);
-	      }
-	  }
-	else
-	  {
-	    fprintf_unfiltered (stream, " %s", selector.get ());
-	  }
-	fprintf_unfiltered (stream, "]");
-	return;
-      }
-
-    case OP_ARRAY:
-      (*pos) += 3;
-      nargs = longest_to_int (exp->elts[pc + 2].longconst);
-      nargs -= longest_to_int (exp->elts[pc + 1].longconst);
-      nargs++;
-      tem = 0;
-      if (exp->elts[pc + 4].opcode == OP_LONG
-	  && exp->elts[pc + 5].type
-	     == builtin_type (exp->gdbarch)->builtin_char
-	  && exp->language_defn->la_language == language_c)
-	{
-	  /* Attempt to print C character arrays using string syntax.
-	     Walk through the args, picking up one character from each
-	     of the OP_LONG expression elements.  If any array element
-	     does not match our expection of what we should find for
-	     a simple string, revert back to array printing.  Note that
-	     the last expression element is an explicit null terminator
-	     byte, which doesn't get printed.  */
-	  tempstr = (char *) alloca (nargs);
-	  pc += 4;
-	  while (tem < nargs)
-	    {
-	      if (exp->elts[pc].opcode != OP_LONG
-		  || exp->elts[pc + 1].type
-		     != builtin_type (exp->gdbarch)->builtin_char)
-		{
-		  /* Not a simple array of char, use regular array
-		     printing.  */
-		  tem = 0;
-		  break;
-		}
-	      else
-		{
-		  tempstr[tem++] =
-		    longest_to_int (exp->elts[pc + 2].longconst);
-		  pc += 4;
-		}
-	    }
-	}
-      if (tem > 0)
-	{
-	  struct value_print_options opts;
-
-	  get_user_print_options (&opts);
-	  exp->language_defn
-	    ->printstr (stream, builtin_type (exp->gdbarch)->builtin_char,
-			(gdb_byte *) tempstr, nargs - 1, NULL, 0, &opts);
-	  (*pos) = pc;
-	}
-      else
-	{
-	  fputs_filtered (" {", stream);
-	  for (tem = 0; tem < nargs; tem++)
-	    {
-	      if (tem != 0)
-		{
-		  fputs_filtered (", ", stream);
-		}
-	      print_subexp (exp, pos, stream, PREC_ABOVE_COMMA);
-	    }
-	  fputs_filtered ("}", stream);
-	}
-      return;
-
-    case TERNOP_COND:
-      if ((int) prec > (int) PREC_COMMA)
-	fputs_filtered ("(", stream);
-      /* Print the subexpressions, forcing parentheses
-	 around any binary operations within them.
-	 This is more parentheses than are strictly necessary,
-	 but it looks clearer.  */
-      print_subexp (exp, pos, stream, PREC_HYPER);
-      fputs_filtered (" ? ", stream);
-      print_subexp (exp, pos, stream, PREC_HYPER);
-      fputs_filtered (" : ", stream);
-      print_subexp (exp, pos, stream, PREC_HYPER);
-      if ((int) prec > (int) PREC_COMMA)
-	fputs_filtered (")", stream);
-      return;
-
-    case TERNOP_SLICE:
-      print_subexp (exp, pos, stream, PREC_SUFFIX);
-      fputs_filtered ("(", stream);
-      print_subexp (exp, pos, stream, PREC_ABOVE_COMMA);
-      fputs_filtered (opcode == TERNOP_SLICE ? " : " : " UP ", stream);
-      print_subexp (exp, pos, stream, PREC_ABOVE_COMMA);
-      fputs_filtered (")", stream);
-      return;
-
-    case STRUCTOP_STRUCT:
-      tem = longest_to_int (exp->elts[pc + 1].longconst);
-      (*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1);
-      print_subexp (exp, pos, stream, PREC_SUFFIX);
-      fputs_filtered (".", stream);
-      fputs_filtered (&exp->elts[pc + 2].string, stream);
-      return;
-
-      /* Will not occur for Modula-2.  */
-    case STRUCTOP_PTR:
-      tem = longest_to_int (exp->elts[pc + 1].longconst);
-      (*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1);
-      print_subexp (exp, pos, stream, PREC_SUFFIX);
-      fputs_filtered ("->", stream);
-      fputs_filtered (&exp->elts[pc + 2].string, stream);
-      return;
-
-    case STRUCTOP_MEMBER:
-      print_subexp (exp, pos, stream, PREC_SUFFIX);
-      fputs_filtered (".*", stream);
-      print_subexp (exp, pos, stream, PREC_SUFFIX);
-      return;
-
-    case STRUCTOP_MPTR:
-      print_subexp (exp, pos, stream, PREC_SUFFIX);
-      fputs_filtered ("->*", stream);
-      print_subexp (exp, pos, stream, PREC_SUFFIX);
-      return;
-
-    case BINOP_SUBSCRIPT:
-      print_subexp (exp, pos, stream, PREC_SUFFIX);
-      fputs_filtered ("[", stream);
-      print_subexp (exp, pos, stream, PREC_ABOVE_COMMA);
-      fputs_filtered ("]", stream);
-      return;
-
-    case UNOP_POSTINCREMENT:
-      print_subexp (exp, pos, stream, PREC_SUFFIX);
-      fputs_filtered ("++", stream);
-      return;
-
-    case UNOP_POSTDECREMENT:
-      print_subexp (exp, pos, stream, PREC_SUFFIX);
-      fputs_filtered ("--", stream);
-      return;
-
-    case UNOP_CAST:
-      (*pos) += 2;
-      if ((int) prec > (int) PREC_PREFIX)
-	fputs_filtered ("(", stream);
-      fputs_filtered ("(", stream);
-      type_print (exp->elts[pc + 1].type, "", stream, 0);
-      fputs_filtered (") ", stream);
-      print_subexp (exp, pos, stream, PREC_PREFIX);
-      if ((int) prec > (int) PREC_PREFIX)
-	fputs_filtered (")", stream);
-      return;
-
-    case UNOP_CAST_TYPE:
-      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);
-      print_subexp (exp, pos, stream, PREC_PREFIX);
-      fputs_filtered ("> (", stream);
-      print_subexp (exp, pos, stream, PREC_PREFIX);
-      fputs_filtered (")", stream);
-      return;
-
-    case UNOP_MEMVAL:
-      (*pos) += 2;
-      if ((int) prec > (int) PREC_PREFIX)
-	fputs_filtered ("(", stream);
-      if (exp->elts[pc + 1].type->code () == TYPE_CODE_FUNC
-	  && exp->elts[pc + 3].opcode == OP_LONG)
-	{
-	  struct value_print_options opts;
-
-	  /* We have a minimal symbol fn, probably.  It's encoded
-	     as a UNOP_MEMVAL (function-type) of an OP_LONG (int, address).
-	     Swallow the OP_LONG (including both its opcodes); ignore
-	     its type; print the value in the type of the MEMVAL.  */
-	  (*pos) += 4;
-	  val = value_at_lazy (exp->elts[pc + 1].type,
-			       (CORE_ADDR) exp->elts[pc + 5].longconst);
-	  get_no_prettyformat_print_options (&opts);
-	  value_print (val, stream, &opts);
-	}
-      else
-	{
-	  fputs_filtered ("{", stream);
-	  type_print (exp->elts[pc + 1].type, "", stream, 0);
-	  fputs_filtered ("} ", stream);
-	  print_subexp (exp, pos, stream, PREC_PREFIX);
-	}
-      if ((int) prec > (int) PREC_PREFIX)
-	fputs_filtered (")", stream);
-      return;
-
-    case UNOP_MEMVAL_TYPE:
-      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 BINOP_ASSIGN_MODIFY:
-      opcode = exp->elts[pc + 1].opcode;
-      (*pos) += 2;
-      myprec = PREC_ASSIGN;
-      assoc = 1;
-      assign_modify = 1;
-      op_str = "???";
-      for (tem = 0; op_print_tab[tem].opcode != OP_NULL; tem++)
-	if (op_print_tab[tem].opcode == opcode)
-	  {
-	    op_str = op_print_tab[tem].string;
-	    break;
-	  }
-      if (op_print_tab[tem].opcode != opcode)
-	/* Not found; don't try to keep going because we don't know how
-	   to interpret further elements.  */
-	error (_("Invalid expression"));
-      break;
-
-      /* C++ ops */
-
-    case OP_THIS:
-      ++(*pos);
-      if (exp->language_defn->name_of_this () != NULL)
-	fputs_filtered (exp->language_defn->name_of_this (), stream);
-      else
-	fprintf_styled (stream, metadata_style.style (),
-			_("<language %s has no 'this'>"),
-			exp->language_defn->name ());
-      return;
-
-      /* Modula-2 ops */
-
-    case MULTI_SUBSCRIPT:
-      (*pos) += 2;
-      nargs = longest_to_int (exp->elts[pc + 1].longconst);
-      print_subexp (exp, pos, stream, PREC_SUFFIX);
-      fprintf_unfiltered (stream, " [");
-      for (tem = 0; tem < nargs; tem++)
-	{
-	  if (tem != 0)
-	    fprintf_unfiltered (stream, ", ");
-	  print_subexp (exp, pos, stream, PREC_ABOVE_COMMA);
-	}
-      fprintf_unfiltered (stream, "]");
-      return;
-
-    case BINOP_VAL:
-      (*pos) += 2;
-      fprintf_unfiltered (stream, "VAL(");
-      type_print (exp->elts[pc + 1].type, "", stream, 0);
-      fprintf_unfiltered (stream, ",");
-      print_subexp (exp, pos, stream, PREC_PREFIX);
-      fprintf_unfiltered (stream, ")");
-      return;
-
-    case TYPE_INSTANCE:
-      {
-	type_instance_flags flags
-	  = (type_instance_flag_value) longest_to_int (exp->elts[pc + 1].longconst);
-	LONGEST count = exp->elts[pc + 2].longconst;
-
-	/* The FLAGS.  */
-	(*pos)++;
-	/* The COUNT.  */
-	(*pos)++;
-	fputs_unfiltered ("TypeInstance(", stream);
-	while (count-- > 0)
-	  {
-	    type_print (exp->elts[(*pos)++].type, "", stream, 0);
-	    if (count > 0)
-	      fputs_unfiltered (",", stream);
-	  }
-	fputs_unfiltered (",", stream);
-	/* Ending COUNT and ending TYPE_INSTANCE.  */
-	(*pos) += 2;
-	print_subexp (exp, pos, stream, PREC_PREFIX);
-
-	if (flags & TYPE_INSTANCE_FLAG_CONST)
-	  fputs_unfiltered (",const", stream);
-	if (flags & TYPE_INSTANCE_FLAG_VOLATILE)
-	  fputs_unfiltered (",volatile", stream);
-
-	fputs_unfiltered (")", stream);
-	return;
-      }
-
-    case OP_RANGE:
-      {
-	enum range_flag range_flag;
-
-	range_flag = (enum range_flag)
-	  longest_to_int (exp->elts[pc + 1].longconst);
-	*pos += 2;
-
-	if (range_flag & RANGE_HIGH_BOUND_EXCLUSIVE)
-	  fputs_filtered ("EXCLUSIVE_", stream);
-	fputs_filtered ("RANGE(", stream);
-	if (!(range_flag & RANGE_LOW_BOUND_DEFAULT))
-	  print_subexp (exp, pos, stream, PREC_ABOVE_COMMA);
-	fputs_filtered ("..", stream);
-	if (!(range_flag & RANGE_HIGH_BOUND_DEFAULT))
-	  print_subexp (exp, pos, stream, PREC_ABOVE_COMMA);
-	fputs_filtered (")", stream);
-	return;
-      }
-
-      /* Default ops */
-
-    default:
-      op_str = "???";
-      for (tem = 0; op_print_tab[tem].opcode != OP_NULL; tem++)
-	if (op_print_tab[tem].opcode == opcode)
-	  {
-	    op_str = op_print_tab[tem].string;
-	    myprec = op_print_tab[tem].precedence;
-	    assoc = op_print_tab[tem].right_assoc;
-	    break;
-	  }
-      if (op_print_tab[tem].opcode != opcode)
-	/* Not found; don't try to keep going because we don't know how
-	   to interpret further elements.  For example, this happens
-	   if opcode is OP_TYPE.  */
-	error (_("Invalid expression"));
-    }
-
-  /* Note that PREC_BUILTIN will always emit parentheses.  */
-  if ((int) myprec < (int) prec)
-    fputs_filtered ("(", stream);
-  if ((int) opcode > (int) BINOP_END)
-    {
-      if (assoc)
-	{
-	  /* Unary postfix operator.  */
-	  print_subexp (exp, pos, stream, PREC_SUFFIX);
-	  fputs_filtered (op_str, stream);
-	}
-      else
-	{
-	  /* Unary prefix operator.  */
-	  fputs_filtered (op_str, stream);
-	  if (myprec == PREC_BUILTIN_FUNCTION)
-	    fputs_filtered ("(", stream);
-	  print_subexp (exp, pos, stream, PREC_PREFIX);
-	  if (myprec == PREC_BUILTIN_FUNCTION)
-	    fputs_filtered (")", stream);
-	}
-    }
-  else
-    {
-      /* Binary operator.  */
-      /* Print left operand.
-	 If operator is right-associative,
-	 increment precedence for this operand.  */
-      print_subexp (exp, pos, stream,
-		    (enum precedence) ((int) myprec + assoc));
-      /* Print the operator itself.  */
-      if (assign_modify)
-	fprintf_filtered (stream, " %s= ", op_str);
-      else if (op_str[0] == ',')
-	fprintf_filtered (stream, "%s ", op_str);
-      else
-	fprintf_filtered (stream, " %s ", op_str);
-      /* Print right operand.
-	 If operator is left-associative,
-	 increment precedence for this operand.  */
-      print_subexp (exp, pos, stream,
-		    (enum precedence) ((int) myprec + !assoc));
-    }
-
-  if ((int) myprec < (int) prec)
-    fputs_filtered (")", stream);
-}
-
-/* Return the operator corresponding to opcode OP as
-   a string.   NULL indicates that the opcode was not found in the
-   current language table.  */
-const char *
-op_string (enum exp_opcode op)
-{
-  int tem;
-  const struct op_print *op_print_tab;
-
-  op_print_tab = current_language->opcode_print_table ();
-  for (tem = 0; op_print_tab[tem].opcode != OP_NULL; tem++)
-    if (op_print_tab[tem].opcode == op)
-      return op_print_tab[tem].string;
-  return NULL;
-}
-
-/* Support for dumping the raw data from expressions in a human readable
-   form.  */
-
-static int dump_subexp_body (struct expression *exp, struct ui_file *, int);
-
 /* Default name for the standard operator OPCODE (i.e., one defined in
    the definition of enum exp_opcode).  */
 
@@ -714,463 +59,10 @@ op_name (enum exp_opcode opcode)
     }
 }
 
-/* Print a raw dump of expression EXP to STREAM.
-   NOTE, if non-NULL, is printed as extra explanatory text.  */
-
-void
-dump_raw_expression (struct expression *exp, struct ui_file *stream,
-		     const char *note)
-{
-  int elt;
-  char *eltscan;
-  int eltsize;
-
-  if (exp->op != nullptr)
-    return;
-
-  fprintf_filtered (stream, "Dump of expression @ ");
-  gdb_print_host_address (exp, stream);
-  if (note)
-    fprintf_filtered (stream, ", %s:", note);
-  fprintf_filtered (stream, "\n\tLanguage %s, %d elements, %ld bytes each.\n",
-		    exp->language_defn->name (), exp->nelts,
-		    (long) sizeof (union exp_element));
-  fprintf_filtered (stream, "\t%5s  %20s  %16s  %s\n", "Index", "Opcode",
-		    "Hex Value", "String Value");
-  for (elt = 0; elt < exp->nelts; elt++)
-    {
-      fprintf_filtered (stream, "\t%5d  ", elt);
-
-      const char *opcode_name = op_name (exp->elts[elt].opcode);
-      fprintf_filtered (stream, "%20s  ", opcode_name);
-
-      print_longest (stream, 'd', 0, exp->elts[elt].longconst);
-      fprintf_filtered (stream, "  ");
-
-      for (eltscan = (char *) &exp->elts[elt],
-	   eltsize = sizeof (union exp_element);
-	   eltsize-- > 0;
-	   eltscan++)
-	{
-	  fprintf_filtered (stream, "%c",
-			    isprint (*eltscan) ? (*eltscan & 0xFF) : '.');
-	}
-      fprintf_filtered (stream, "\n");
-    }
-}
-
-/* Dump the subexpression of prefix expression EXP whose operator is at
-   position ELT onto STREAM.  Returns the position of the next 
-   subexpression in EXP.  */
-
-int
-dump_subexp (struct expression *exp, struct ui_file *stream, int elt)
-{
-  static int indent = 0;
-  int i;
-
-  fprintf_filtered (stream, "\n");
-  fprintf_filtered (stream, "\t%5d  ", elt);
-
-  for (i = 1; i <= indent; i++)
-    fprintf_filtered (stream, " ");
-  indent += 2;
-
-  fprintf_filtered (stream, "%-20s  ", op_name (exp->elts[elt].opcode));
-
-  elt = dump_subexp_body (exp, stream, elt);
-
-  indent -= 2;
-
-  return elt;
-}
-
-/* Dump the operands of prefix expression EXP whose opcode is at
-   position ELT onto STREAM.  Returns the position of the next 
-   subexpression in EXP.  */
-
-static int
-dump_subexp_body (struct expression *exp, struct ui_file *stream, int elt)
-{
-  return exp->language_defn->expression_ops ()->dump_subexp_body (exp, stream,
-								  elt);
-}
-
-/* See parser-defs.h.  */
-
-int
-dump_subexp_body_funcall (struct expression *exp,
-			  struct ui_file *stream, int elt)
-{
-  int nargs = longest_to_int (exp->elts[elt].longconst);
-  fprintf_filtered (stream, "Number of args: %d", nargs);
-  elt += 2;
-
-  for (int i = 1; i <= nargs + 1; i++)
-    elt = dump_subexp (exp, stream, elt);
-
-  return elt;
-}
-
-/* Default value for subexp_body in exp_descriptor vector.  */
-
-int
-dump_subexp_body_standard (struct expression *exp, 
-			   struct ui_file *stream, int elt)
-{
-  int opcode = exp->elts[elt++].opcode;
-
-  switch (opcode)
-    {
-    case TERNOP_COND:
-    case TERNOP_SLICE:
-      elt = dump_subexp (exp, stream, elt);
-      /* FALL THROUGH */
-    case BINOP_ADD:
-    case BINOP_SUB:
-    case BINOP_MUL:
-    case BINOP_DIV:
-    case BINOP_REM:
-    case BINOP_MOD:
-    case BINOP_LSH:
-    case BINOP_RSH:
-    case BINOP_LOGICAL_AND:
-    case BINOP_LOGICAL_OR:
-    case BINOP_BITWISE_AND:
-    case BINOP_BITWISE_IOR:
-    case BINOP_BITWISE_XOR:
-    case BINOP_EQUAL:
-    case BINOP_NOTEQUAL:
-    case BINOP_LESS:
-    case BINOP_GTR:
-    case BINOP_LEQ:
-    case BINOP_GEQ:
-    case BINOP_REPEAT:
-    case BINOP_ASSIGN:
-    case BINOP_COMMA:
-    case BINOP_SUBSCRIPT:
-    case BINOP_EXP:
-    case BINOP_MIN:
-    case BINOP_MAX:
-    case BINOP_INTDIV:
-    case BINOP_ASSIGN_MODIFY:
-    case BINOP_VAL:
-    case BINOP_CONCAT:
-    case BINOP_END:
-    case STRUCTOP_MEMBER:
-    case STRUCTOP_MPTR:
-      elt = dump_subexp (exp, stream, elt);
-      /* FALL THROUGH */
-    case UNOP_NEG:
-    case UNOP_LOGICAL_NOT:
-    case UNOP_COMPLEMENT:
-    case UNOP_IND:
-    case UNOP_ADDR:
-    case UNOP_PREINCREMENT:
-    case UNOP_POSTINCREMENT:
-    case UNOP_PREDECREMENT:
-    case UNOP_POSTDECREMENT:
-    case UNOP_SIZEOF:
-    case UNOP_ALIGNOF:
-    case UNOP_PLUS:
-    case UNOP_CAP:
-    case UNOP_CHR:
-    case UNOP_ORD:
-    case UNOP_ABS:
-    case UNOP_FLOAT:
-    case UNOP_HIGH:
-    case UNOP_MAX:
-    case UNOP_MIN:
-    case UNOP_ODD:
-    case UNOP_TRUNC:
-      elt = dump_subexp (exp, stream, elt);
-      break;
-    case OP_LONG:
-      fprintf_filtered (stream, "Type @");
-      gdb_print_host_address (exp->elts[elt].type, stream);
-      fprintf_filtered (stream, " (");
-      type_print (exp->elts[elt].type, NULL, stream, 0);
-      fprintf_filtered (stream, "), value %ld (0x%lx)",
-			(long) exp->elts[elt + 1].longconst,
-			(long) exp->elts[elt + 1].longconst);
-      elt += 3;
-      break;
-    case OP_FLOAT:
-      fprintf_filtered (stream, "Type @");
-      gdb_print_host_address (exp->elts[elt].type, stream);
-      fprintf_filtered (stream, " (");
-      type_print (exp->elts[elt].type, NULL, stream, 0);
-      fprintf_filtered (stream, "), value ");
-      print_floating (exp->elts[elt + 1].floatconst,
-		      exp->elts[elt].type, stream);
-      elt += 3;
-      break;
-    case OP_VAR_VALUE:
-      fprintf_filtered (stream, "Block @");
-      gdb_print_host_address (exp->elts[elt].block, stream);
-      fprintf_filtered (stream, ", symbol @");
-      gdb_print_host_address (exp->elts[elt + 1].symbol, stream);
-      fprintf_filtered (stream, " (%s)",
-			exp->elts[elt + 1].symbol->print_name ());
-      elt += 3;
-      break;
-    case OP_VAR_MSYM_VALUE:
-      fprintf_filtered (stream, "Objfile @");
-      gdb_print_host_address (exp->elts[elt].objfile, stream);
-      fprintf_filtered (stream, ", msymbol @");
-      gdb_print_host_address (exp->elts[elt + 1].msymbol, stream);
-      fprintf_filtered (stream, " (%s)",
-			exp->elts[elt + 1].msymbol->print_name ());
-      elt += 3;
-      break;
-    case OP_VAR_ENTRY_VALUE:
-      fprintf_filtered (stream, "Entry value of symbol @");
-      gdb_print_host_address (exp->elts[elt].symbol, stream);
-      fprintf_filtered (stream, " (%s)",
-			exp->elts[elt].symbol->print_name ());
-      elt += 2;
-      break;
-    case OP_LAST:
-      fprintf_filtered (stream, "History element %ld",
-			(long) exp->elts[elt].longconst);
-      elt += 2;
-      break;
-    case OP_REGISTER:
-      fprintf_filtered (stream, "Register $%s", &exp->elts[elt + 1].string);
-      elt += 3 + BYTES_TO_EXP_ELEM (exp->elts[elt].longconst + 1);
-      break;
-    case OP_INTERNALVAR:
-      fprintf_filtered (stream, "Internal var @");
-      gdb_print_host_address (exp->elts[elt].internalvar, stream);
-      fprintf_filtered (stream, " (%s)",
-			internalvar_name (exp->elts[elt].internalvar));
-      elt += 2;
-      break;
-    case OP_FUNCALL:
-      elt = dump_subexp_body_funcall (exp, stream, elt);
-      break;
-    case OP_ARRAY:
-      {
-	int lower, upper;
-	int i;
-
-	lower = longest_to_int (exp->elts[elt].longconst);
-	upper = longest_to_int (exp->elts[elt + 1].longconst);
-
-	fprintf_filtered (stream, "Bounds [%d:%d]", lower, upper);
-	elt += 3;
-
-	for (i = 1; i <= upper - lower + 1; i++)
-	  elt = dump_subexp (exp, stream, elt);
-      }
-      break;
-    case UNOP_DYNAMIC_CAST:
-    case UNOP_REINTERPRET_CAST:
-    case UNOP_CAST_TYPE:
-    case UNOP_MEMVAL_TYPE:
-      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, " (");
-      type_print (exp->elts[elt].type, NULL, stream, 0);
-      fprintf_filtered (stream, ")");
-      elt = dump_subexp (exp, stream, elt + 2);
-      break;
-    case OP_TYPE:
-      fprintf_filtered (stream, "Type @");
-      gdb_print_host_address (exp->elts[elt].type, stream);
-      fprintf_filtered (stream, " (");
-      type_print (exp->elts[elt].type, NULL, stream, 0);
-      fprintf_filtered (stream, ")");
-      elt += 2;
-      break;
-    case OP_TYPEOF:
-    case OP_DECLTYPE:
-      fprintf_filtered (stream, "Typeof (");
-      elt = dump_subexp (exp, stream, elt);
-      fprintf_filtered (stream, ")");
-      break;
-    case OP_TYPEID:
-      fprintf_filtered (stream, "typeid (");
-      elt = dump_subexp (exp, stream, elt);
-      fprintf_filtered (stream, ")");
-      break;
-    case STRUCTOP_STRUCT:
-    case STRUCTOP_PTR:
-      {
-	char *elem_name;
-	int len;
-
-	len = longest_to_int (exp->elts[elt].longconst);
-	elem_name = &exp->elts[elt + 1].string;
-
-	fprintf_filtered (stream, "Element name: `%.*s'", len, elem_name);
-	elt = dump_subexp (exp, stream, elt + 3 + BYTES_TO_EXP_ELEM (len + 1));
-      }
-      break;
-    case OP_SCOPE:
-      {
-	char *elem_name;
-	int len;
-
-	fprintf_filtered (stream, "Type @");
-	gdb_print_host_address (exp->elts[elt].type, stream);
-	fprintf_filtered (stream, " (");
-	type_print (exp->elts[elt].type, NULL, stream, 0);
-	fprintf_filtered (stream, ") ");
-
-	len = longest_to_int (exp->elts[elt + 1].longconst);
-	elem_name = &exp->elts[elt + 2].string;
-
-	fprintf_filtered (stream, "Field name: `%.*s'", len, elem_name);
-	elt += 4 + BYTES_TO_EXP_ELEM (len + 1);
-      }
-      break;
-
-    case OP_FUNC_STATIC_VAR:
-      {
-	int len = longest_to_int (exp->elts[elt].longconst);
-	const char *var_name = &exp->elts[elt + 1].string;
-	fprintf_filtered (stream, "Field name: `%.*s'", len, var_name);
-	elt += 3 + BYTES_TO_EXP_ELEM (len + 1);
-      }
-      break;
-
-    case TYPE_INSTANCE:
-      {
-	type_instance_flags flags
-	  = (type_instance_flag_value) longest_to_int (exp->elts[elt++].longconst);
-	LONGEST len = exp->elts[elt++].longconst;
-	fprintf_filtered (stream, "%s TypeInstance: ", plongest (len));
-	while (len-- > 0)
-	  {
-	    fprintf_filtered (stream, "Type @");
-	    gdb_print_host_address (exp->elts[elt].type, stream);
-	    fprintf_filtered (stream, " (");
-	    type_print (exp->elts[elt].type, NULL, stream, 0);
-	    fprintf_filtered (stream, ")");
-	    elt++;
-	    if (len > 0)
-	      fputs_filtered (", ", stream);
-	  }
-
-	fprintf_filtered (stream, " Flags: %s (", hex_string (flags));
-	bool space = false;
-	auto print_one = [&] (const char *mod)
-	  {
-	    if (space)
-	      fputs_filtered (" ", stream);
-	    space = true;
-	    fprintf_filtered (stream, "%s", mod);
-	  };
-	if (flags & TYPE_INSTANCE_FLAG_CONST)
-	  print_one ("const");
-	if (flags & TYPE_INSTANCE_FLAG_VOLATILE)
-	  print_one ("volatile");
-	fprintf_filtered (stream, ")");
-
-	/* Ending LEN and ending TYPE_INSTANCE.  */
-	elt += 2;
-	elt = dump_subexp (exp, stream, elt);
-      }
-      break;
-    case OP_STRING:
-      {
-	LONGEST len = exp->elts[elt].longconst;
-	LONGEST type = exp->elts[elt + 1].longconst;
-
-	fprintf_filtered (stream, "Language-specific string type: %s",
-			  plongest (type));
-
-	/* Skip length.  */
-	elt += 1;
-
-	/* Skip string content. */
-	elt += BYTES_TO_EXP_ELEM (len);
-
-	/* Skip length and ending OP_STRING. */
-	elt += 2;
-      }
-      break;
-    case OP_RANGE:
-      {
-	enum range_flag range_flag;
-
-	range_flag = (enum range_flag)
-	  longest_to_int (exp->elts[elt].longconst);
-	elt += 2;
-
-	if (range_flag & RANGE_HIGH_BOUND_EXCLUSIVE)
-	  fputs_filtered ("Exclusive", stream);
-	fputs_filtered ("Range '", stream);
-	if (!(range_flag & RANGE_LOW_BOUND_DEFAULT))
-	  fputs_filtered ("EXP", stream);
-	fputs_filtered ("..", stream);
-	if (!(range_flag & RANGE_HIGH_BOUND_DEFAULT))
-	  fputs_filtered ("EXP", stream);
-	if (range_flag & RANGE_HAS_STRIDE)
-	  fputs_filtered (":EXP", stream);
-	fputs_filtered ("'", stream);
-
-	if (!(range_flag & RANGE_LOW_BOUND_DEFAULT))
-	  elt = dump_subexp (exp, stream, elt);
-	if (!(range_flag & RANGE_HIGH_BOUND_DEFAULT))
-	  elt = dump_subexp (exp, stream, elt);
-	if (range_flag & RANGE_HAS_STRIDE)
-	  elt = dump_subexp (exp, stream, elt);
-      }
-      break;
-
-    default:
-    case OP_NULL:
-    case MULTI_SUBSCRIPT:
-    case OP_COMPLEX:
-    case OP_BOOL:
-    case OP_M2_STRING:
-    case OP_THIS:
-    case OP_NAME:
-      fprintf_filtered (stream, "Unknown format");
-    }
-
-  return elt;
-}
-
 void
 dump_prefix_expression (struct expression *exp, struct ui_file *stream)
 {
-  int elt;
-
-  if (exp->op != nullptr)
-    {
-      exp->op->dump (stream, 0);
-      return;
-    }
-
-  fprintf_filtered (stream, "Dump of expression @ ");
-  gdb_print_host_address (exp, stream);
-  fputs_filtered (", after conversion to prefix form:\nExpression: `", stream);
-
-  if (exp->op != nullptr)
-    {
-      exp->op->dump (stream, 0);
-      return;
-    }
-
-  print_expression (exp, stream);
-  fprintf_filtered (stream, "'\n\tLanguage %s, %d elements, %ld bytes each.\n",
-		    exp->language_defn->name (), exp->nelts,
-		    (long) sizeof (union exp_element));
-  fputs_filtered ("\n", stream);
-
-  for (elt = 0; elt < exp->nelts;)
-    elt = dump_subexp (exp, stream, elt);
-  fputs_filtered ("\n", stream);
+  exp->op->dump (stream, 0);
 }
 
 namespace expr
diff --git a/gdb/expression.h b/gdb/expression.h
index f9b7855346e..bca4c6d9fe2 100644
--- a/gdb/expression.h
+++ b/gdb/expression.h
@@ -40,21 +40,6 @@ enum innermost_block_tracker_type
 DEF_ENUM_FLAGS_TYPE (enum innermost_block_tracker_type,
 		     innermost_block_tracker_types);
 
-/* Definitions for saved C expressions.  */
-
-/* An expression is represented as a vector of union exp_element's.
-   Each exp_element is an opcode, except that some opcodes cause
-   the following exp_element to be treated as a long or double constant
-   or as a variable.  The opcodes are obeyed, using a stack for temporaries.
-   The value is left on the temporary stack at the end.  */
-
-/* When it is necessary to include a string,
-   it can occupy as many exp_elements as it needs.
-   We find the length of the string using strlen,
-   divide to find out how many exp_elements are used up,
-   and skip that many.  Strings, like numbers, are indicated
-   by the preceding opcode.  */
-
 enum exp_opcode : uint8_t
   {
 #define OP(name) name ,
@@ -197,37 +182,17 @@ make_operation (Arg... args)
 
 }
 
-union exp_element
-  {
-    enum exp_opcode opcode;
-    struct symbol *symbol;
-    struct minimal_symbol *msymbol;
-    LONGEST longconst;
-    gdb_byte floatconst[16];
-    /* Really sizeof (union exp_element) characters (or less for the last
-       element of a string).  */
-    char string;
-    struct type *type;
-    struct internalvar *internalvar;
-    const struct block *block;
-    struct objfile *objfile;
-  };
-
 struct expression
 {
-  expression (const struct language_defn *, struct gdbarch *, size_t);
+  expression (const struct language_defn *, struct gdbarch *);
   ~expression ();
   DISABLE_COPY_AND_ASSIGN (expression);
 
-  void resize (size_t);
-
   /* Return the opcode for the outermost sub-expression of this
      expression.  */
   enum exp_opcode first_opcode () const
   {
-    if (op != nullptr)
-      return op->opcode ();
-    return elts[0].opcode;
+    return op->opcode ();
   }
 
   /* Language it was entered in.  */
@@ -235,20 +200,10 @@ struct expression
   /* Architecture it was parsed in.  */
   struct gdbarch *gdbarch;
   expr::operation_up op;
-  int nelts = 0;
-  union exp_element *elts;
 };
 
 typedef std::unique_ptr<expression> expression_up;
 
-/* Macros for converting between number of expression elements and bytes
-   to store that many expression elements.  */
-
-#define EXP_ELEM_TO_BYTES(elements) \
-    ((elements) * sizeof (union exp_element))
-#define BYTES_TO_EXP_ELEM(bytes) \
-    (((bytes) + sizeof (union exp_element) - 1) / sizeof (union exp_element))
-
 /* From parse.c */
 
 class innermost_block_tracker;
@@ -268,9 +223,6 @@ extern expression_up parse_exp_1 (const char **, CORE_ADDR pc,
 
 /* From eval.c */
 
-extern struct value *evaluate_subexp_standard
-  (struct type *, struct expression *, int *, enum noside);
-
 /* Evaluate a function call.  The function to be called is in CALLEE and
    the arguments passed to the function are in ARGVEC.
    FUNCTION_NAME is the name of the function, if known.
@@ -286,14 +238,8 @@ extern struct value *evaluate_subexp_do_call (expression *exp,
 
 /* From expprint.c */
 
-extern void print_expression (struct expression *, struct ui_file *);
-
 extern const char *op_name (enum exp_opcode opcode);
 
-extern const char *op_string (enum exp_opcode);
-
-extern void dump_raw_expression (struct expression *,
-				 struct ui_file *, const char *);
 extern void dump_prefix_expression (struct expression *, struct ui_file *);
 
 /* In an OP_RANGE expression, either bound could be empty, indicating
diff --git a/gdb/f-lang.c b/gdb/f-lang.c
index e5b66c7fa3b..f86f961e7bb 100644
--- a/gdb/f-lang.c
+++ b/gdb/f-lang.c
@@ -101,34 +101,6 @@ f_language::get_encoding (struct type *type)
 
 \f
 
-/* Table of operators and their precedences for printing expressions.  */
-
-const struct op_print f_language::op_print_tab[] =
-{
-  {"+", BINOP_ADD, PREC_ADD, 0},
-  {"+", UNOP_PLUS, PREC_PREFIX, 0},
-  {"-", BINOP_SUB, PREC_ADD, 0},
-  {"-", UNOP_NEG, PREC_PREFIX, 0},
-  {"*", BINOP_MUL, PREC_MUL, 0},
-  {"/", BINOP_DIV, PREC_MUL, 0},
-  {"DIV", BINOP_INTDIV, PREC_MUL, 0},
-  {"MOD", BINOP_REM, PREC_MUL, 0},
-  {"=", BINOP_ASSIGN, PREC_ASSIGN, 1},
-  {".OR.", BINOP_LOGICAL_OR, PREC_LOGICAL_OR, 0},
-  {".AND.", BINOP_LOGICAL_AND, PREC_LOGICAL_AND, 0},
-  {".NOT.", UNOP_LOGICAL_NOT, PREC_PREFIX, 0},
-  {".EQ.", BINOP_EQUAL, PREC_EQUAL, 0},
-  {".NE.", BINOP_NOTEQUAL, PREC_EQUAL, 0},
-  {".LE.", BINOP_LEQ, PREC_ORDER, 0},
-  {".GE.", BINOP_GEQ, PREC_ORDER, 0},
-  {".GT.", BINOP_GTR, PREC_ORDER, 0},
-  {".LT.", BINOP_LESS, PREC_ORDER, 0},
-  {"**", UNOP_IND, PREC_PREFIX, 0},
-  {"@", BINOP_REPEAT, PREC_REPEAT, 0},
-  {NULL, OP_NULL, PREC_REPEAT, 0}
-};
-\f
-
 /* Return the number of dimensions for a Fortran array or string.  */
 
 int
diff --git a/gdb/f-lang.h b/gdb/f-lang.h
index 03b59102139..1ccdd3978ea 100644
--- a/gdb/f-lang.h
+++ b/gdb/f-lang.h
@@ -218,11 +218,6 @@ class f_language : public language_defn
   enum array_ordering array_ordering () const override
   { return array_column_major; }
 
-  /* See language.h.  */
-
-  const struct op_print *opcode_print_table () const override
-  { return op_print_tab; }
-
 protected:
 
   /* See language.h.  */
@@ -231,10 +226,6 @@ class f_language : public language_defn
 	(const lookup_name_info &lookup_name) const override;
 
 private:
-  /* Table of opcode data for use by OPCODE_PRINT_TABLE member function.  */
-
-  static const struct op_print op_print_tab[];
-
   /* Return the encoding that should be used for the character type
      TYPE.  */
 
diff --git a/gdb/go-lang.c b/gdb/go-lang.c
index eafd868baf4..2a4fb1a35b0 100644
--- a/gdb/go-lang.c
+++ b/gdb/go-lang.c
@@ -386,14 +386,6 @@ go_language::demangle_symbol (const char *mangled_name, int options) const
   return result;
 }
 
-/* See language.h.  */
-
-const struct exp_descriptor *
-go_language::expression_ops () const
-{
-  return &exp_descriptor_c;
-}
-
 /* Given a Go symbol, return its package or NULL if unknown.
    Space for the result is malloc'd, caller must free.  */
 
@@ -452,44 +444,6 @@ go_block_package_name (const struct block *block)
   return NULL;
 }
 
-/* See go-lang.h.
-
-   TODO(dje): &^ ?  */
-
-const struct op_print go_language::op_print_tab[] =
-{
-  {",", BINOP_COMMA, PREC_COMMA, 0},
-  {"=", BINOP_ASSIGN, PREC_ASSIGN, 1},
-  {"||", BINOP_LOGICAL_OR, PREC_LOGICAL_OR, 0},
-  {"&&", BINOP_LOGICAL_AND, PREC_LOGICAL_AND, 0},
-  {"|", BINOP_BITWISE_IOR, PREC_BITWISE_IOR, 0},
-  {"^", BINOP_BITWISE_XOR, PREC_BITWISE_XOR, 0},
-  {"&", BINOP_BITWISE_AND, PREC_BITWISE_AND, 0},
-  {"==", BINOP_EQUAL, PREC_EQUAL, 0},
-  {"!=", BINOP_NOTEQUAL, PREC_EQUAL, 0},
-  {"<=", BINOP_LEQ, PREC_ORDER, 0},
-  {">=", BINOP_GEQ, PREC_ORDER, 0},
-  {">", BINOP_GTR, PREC_ORDER, 0},
-  {"<", BINOP_LESS, PREC_ORDER, 0},
-  {">>", BINOP_RSH, PREC_SHIFT, 0},
-  {"<<", BINOP_LSH, PREC_SHIFT, 0},
-  {"+", BINOP_ADD, PREC_ADD, 0},
-  {"-", BINOP_SUB, PREC_ADD, 0},
-  {"*", BINOP_MUL, PREC_MUL, 0},
-  {"/", BINOP_DIV, PREC_MUL, 0},
-  {"%", BINOP_REM, PREC_MUL, 0},
-  {"@", BINOP_REPEAT, PREC_REPEAT, 0},
-  {"-", UNOP_NEG, PREC_PREFIX, 0},
-  {"!", UNOP_LOGICAL_NOT, PREC_PREFIX, 0},
-  {"^", UNOP_COMPLEMENT, PREC_PREFIX, 0},
-  {"*", UNOP_IND, PREC_PREFIX, 0},
-  {"&", UNOP_ADDR, PREC_PREFIX, 0},
-  {"unsafe.Sizeof ", UNOP_SIZEOF, PREC_PREFIX, 0},
-  {"++", UNOP_POSTINCREMENT, PREC_SUFFIX, 0},
-  {"--", UNOP_POSTDECREMENT, PREC_SUFFIX, 0},
-  {NULL, OP_NULL, PREC_SUFFIX, 0}
-};
-
 /* See language.h.  */
 
 void
diff --git a/gdb/go-lang.h b/gdb/go-lang.h
index 71f91803d6f..3495d98d15d 100644
--- a/gdb/go-lang.h
+++ b/gdb/go-lang.h
@@ -134,22 +134,6 @@ class go_language : public language_defn
 
   bool store_sym_names_in_linkage_form_p () const override
   { return true; }
-
-  /* See language.h.  */
-
-  const struct exp_descriptor *expression_ops () const override;
-
-  /* See language.h.  */
-
-  const struct op_print *opcode_print_table () const override
-  { return op_print_tab; }
-
-private:
-
-  /* Table of opcode data for use by OPCODE_PRINT_TABLE member function.  */
-
-  static const struct op_print op_print_tab[];
-
 };
 
 #endif /* !defined (GO_LANG_H) */
diff --git a/gdb/language.c b/gdb/language.c
index 1770ba1f8e1..8f14e9f9361 100644
--- a/gdb/language.c
+++ b/gdb/language.c
@@ -765,14 +765,6 @@ language_defn::varobj_ops () const
   return &c_varobj_ops;
 }
 
-/* See language.h.  */
-
-const struct exp_descriptor *
-language_defn::expression_ops () const
-{
-  return &exp_descriptor_standard;
-}
-
 /* Parent class for both the "auto" and "unknown" languages.  These two
    pseudo-languages are very similar so merging their implementations like
    this makes sense.  */
@@ -892,18 +884,6 @@ class auto_or_unknown_language : public language_defn
 
   const char *name_of_this () const override
   { return "this"; }
-
-  /* See language.h.  */
-
-  const struct op_print *opcode_print_table () const override
-  {
-    static const struct op_print unk_op_print_tab[] =
-      {
-	{NULL, OP_NULL, PREC_NULL, 0}
-      };
-
-    return unk_op_print_tab;
-  }
 };
 
 /* Class representing the fake "auto" language.  */
diff --git a/gdb/language.h b/gdb/language.h
index 44dbf3b8e6f..b5518629ff8 100644
--- a/gdb/language.h
+++ b/gdb/language.h
@@ -519,17 +519,6 @@ struct language_defn
 
   virtual int parser (struct parser_state *ps) const;
 
-  /* Given an expression *EXPP created by prefixifying the result of
-     la_parser, perform any remaining processing necessary to complete its
-     translation.  *EXPP may change; la_post_parser is responsible for
-     releasing its previous contents, if necessary.  */
-
-  virtual void post_parser (expression_up *expp, struct parser_state *ps)
-    const
-  {
-    /* By default the post-parser does nothing.  */
-  }
-
   /* Print the character CH (of type CHTYPE) on STREAM as part of the
      contents of a literal string whose delimiter is QUOTER.  */
 
@@ -646,15 +635,6 @@ struct language_defn
 
   virtual const struct lang_varobj_ops *varobj_ops () const;
 
-  /* Definitions related to expression printing, prefixifying, and
-     dumping.  */
-
-  virtual const struct exp_descriptor *expression_ops () const;
-
-  /* Table for printing expressions.  */
-
-  virtual const struct op_print *opcode_print_table () const = 0;
-
 protected:
 
   /* This is the overridable part of the GET_SYMBOL_NAME_MATCHER method.
diff --git a/gdb/m2-lang.c b/gdb/m2-lang.c
index 281fa8b9218..a165cf6b603 100644
--- a/gdb/m2-lang.c
+++ b/gdb/m2-lang.c
@@ -113,43 +113,6 @@ eval_op_m2_subscript (struct type *expect_type, struct expression *exp,
 
 \f
 
-/* Table of operators and their precedences for printing expressions.  */
-
-const struct op_print m2_language::op_print_tab[] =
-{
-  {"+", BINOP_ADD, PREC_ADD, 0},
-  {"+", UNOP_PLUS, PREC_PREFIX, 0},
-  {"-", BINOP_SUB, PREC_ADD, 0},
-  {"-", UNOP_NEG, PREC_PREFIX, 0},
-  {"*", BINOP_MUL, PREC_MUL, 0},
-  {"/", BINOP_DIV, PREC_MUL, 0},
-  {"DIV", BINOP_INTDIV, PREC_MUL, 0},
-  {"MOD", BINOP_REM, PREC_MUL, 0},
-  {":=", BINOP_ASSIGN, PREC_ASSIGN, 1},
-  {"OR", BINOP_LOGICAL_OR, PREC_LOGICAL_OR, 0},
-  {"AND", BINOP_LOGICAL_AND, PREC_LOGICAL_AND, 0},
-  {"NOT", UNOP_LOGICAL_NOT, PREC_PREFIX, 0},
-  {"=", BINOP_EQUAL, PREC_EQUAL, 0},
-  {"<>", BINOP_NOTEQUAL, PREC_EQUAL, 0},
-  {"<=", BINOP_LEQ, PREC_ORDER, 0},
-  {">=", BINOP_GEQ, PREC_ORDER, 0},
-  {">", BINOP_GTR, PREC_ORDER, 0},
-  {"<", BINOP_LESS, PREC_ORDER, 0},
-  {"^", UNOP_IND, PREC_PREFIX, 0},
-  {"@", BINOP_REPEAT, PREC_REPEAT, 0},
-  {"CAP", UNOP_CAP, PREC_BUILTIN_FUNCTION, 0},
-  {"CHR", UNOP_CHR, PREC_BUILTIN_FUNCTION, 0},
-  {"ORD", UNOP_ORD, PREC_BUILTIN_FUNCTION, 0},
-  {"FLOAT", UNOP_FLOAT, PREC_BUILTIN_FUNCTION, 0},
-  {"HIGH", UNOP_HIGH, PREC_BUILTIN_FUNCTION, 0},
-  {"MAX", UNOP_MAX, PREC_BUILTIN_FUNCTION, 0},
-  {"MIN", UNOP_MIN, PREC_BUILTIN_FUNCTION, 0},
-  {"ODD", UNOP_ODD, PREC_BUILTIN_FUNCTION, 0},
-  {"TRUNC", UNOP_TRUNC, PREC_BUILTIN_FUNCTION, 0},
-  {NULL, OP_NULL, PREC_BUILTIN_FUNCTION, 0}
-};
-\f
-
 /* Single instance of the M2 language.  */
 
 static m2_language m2_language_defn;
diff --git a/gdb/m2-lang.h b/gdb/m2-lang.h
index 20941429ff0..89b9d185b96 100644
--- a/gdb/m2-lang.h
+++ b/gdb/m2-lang.h
@@ -147,15 +147,6 @@ class m2_language : public language_defn
 
   bool range_checking_on_by_default () const override
   { return true; }
-
-  /* See language.h.  */
-
-  const struct op_print *opcode_print_table () const override
-  { return op_print_tab; }
-
-private:
-  /* Table of opcode data for use by OPCODE_PRINT_TABLE member function.  */
-  static const struct op_print op_print_tab[];
 };
 
 #endif /* M2_LANG_H */
diff --git a/gdb/objc-lang.c b/gdb/objc-lang.c
index aa0360b6818..4d594a973fb 100644
--- a/gdb/objc-lang.c
+++ b/gdb/objc-lang.c
@@ -282,44 +282,6 @@ objc_demangle (const char *mangled, int options)
     return NULL;	/* Not an objc mangled name.  */
 }
 
-
-/* Table mapping opcodes into strings for printing operators
-   and precedences of the operators.  */
-
-static const struct op_print objc_op_print_tab[] =
-  {
-    {",",  BINOP_COMMA, PREC_COMMA, 0},
-    {"=",  BINOP_ASSIGN, PREC_ASSIGN, 1},
-    {"||", BINOP_LOGICAL_OR, PREC_LOGICAL_OR, 0},
-    {"&&", BINOP_LOGICAL_AND, PREC_LOGICAL_AND, 0},
-    {"|",  BINOP_BITWISE_IOR, PREC_BITWISE_IOR, 0},
-    {"^",  BINOP_BITWISE_XOR, PREC_BITWISE_XOR, 0},
-    {"&",  BINOP_BITWISE_AND, PREC_BITWISE_AND, 0},
-    {"==", BINOP_EQUAL, PREC_EQUAL, 0},
-    {"!=", BINOP_NOTEQUAL, PREC_EQUAL, 0},
-    {"<=", BINOP_LEQ, PREC_ORDER, 0},
-    {">=", BINOP_GEQ, PREC_ORDER, 0},
-    {">",  BINOP_GTR, PREC_ORDER, 0},
-    {"<",  BINOP_LESS, PREC_ORDER, 0},
-    {">>", BINOP_RSH, PREC_SHIFT, 0},
-    {"<<", BINOP_LSH, PREC_SHIFT, 0},
-    {"+",  BINOP_ADD, PREC_ADD, 0},
-    {"-",  BINOP_SUB, PREC_ADD, 0},
-    {"*",  BINOP_MUL, PREC_MUL, 0},
-    {"/",  BINOP_DIV, PREC_MUL, 0},
-    {"%",  BINOP_REM, PREC_MUL, 0},
-    {"@",  BINOP_REPEAT, PREC_REPEAT, 0},
-    {"-",  UNOP_NEG, PREC_PREFIX, 0},
-    {"!",  UNOP_LOGICAL_NOT, PREC_PREFIX, 0},
-    {"~",  UNOP_COMPLEMENT, PREC_PREFIX, 0},
-    {"*",  UNOP_IND, PREC_PREFIX, 0},
-    {"&",  UNOP_ADDR, PREC_PREFIX, 0},
-    {"sizeof ", UNOP_SIZEOF, PREC_PREFIX, 0},
-    {"++", UNOP_PREINCREMENT, PREC_PREFIX, 0},
-    {"--", UNOP_PREDECREMENT, PREC_PREFIX, 0},
-    {NULL, OP_NULL, PREC_NULL, 0}
-};
-
 /* Class representing the Objective-C language.  */
 
 class objc_language : public language_defn
@@ -421,11 +383,6 @@ class objc_language : public language_defn
 
   enum macro_expansion macro_expansion () const override
   { return macro_expansion_c; }
-
-  /* See language.h.  */
-
-  const struct op_print *opcode_print_table () const override
-  { return objc_op_print_tab; }
 };
 
 /* Single instance of the class representing the Objective-C language.  */
diff --git a/gdb/opencl-lang.c b/gdb/opencl-lang.c
index b283be173c4..c168cd49344 100644
--- a/gdb/opencl-lang.c
+++ b/gdb/opencl-lang.c
@@ -973,11 +973,6 @@ class opencl_language : public language_defn
 
   enum macro_expansion macro_expansion () const override
   { return macro_expansion_c; }
-
-  /* See language.h.  */
-
-  const struct op_print *opcode_print_table () const override
-  { return c_op_print_tab; }
 };
 
 /* Single instance of the OpenCL language class.  */
diff --git a/gdb/p-lang.c b/gdb/p-lang.c
index 9654da11a8c..1d8e9408e54 100644
--- a/gdb/p-lang.c
+++ b/gdb/p-lang.c
@@ -185,40 +185,6 @@ pascal_language::printchar (int c, struct type *type,
 
 \f
 
-/* Table mapping opcodes into strings for printing operators
-   and precedences of the operators.  */
-
-const struct op_print pascal_language::op_print_tab[] =
-{
-  {",", BINOP_COMMA, PREC_COMMA, 0},
-  {":=", BINOP_ASSIGN, PREC_ASSIGN, 1},
-  {"or", BINOP_BITWISE_IOR, PREC_BITWISE_IOR, 0},
-  {"xor", BINOP_BITWISE_XOR, PREC_BITWISE_XOR, 0},
-  {"and", BINOP_BITWISE_AND, PREC_BITWISE_AND, 0},
-  {"=", BINOP_EQUAL, PREC_EQUAL, 0},
-  {"<>", BINOP_NOTEQUAL, PREC_EQUAL, 0},
-  {"<=", BINOP_LEQ, PREC_ORDER, 0},
-  {">=", BINOP_GEQ, PREC_ORDER, 0},
-  {">", BINOP_GTR, PREC_ORDER, 0},
-  {"<", BINOP_LESS, PREC_ORDER, 0},
-  {"shr", BINOP_RSH, PREC_SHIFT, 0},
-  {"shl", BINOP_LSH, PREC_SHIFT, 0},
-  {"+", BINOP_ADD, PREC_ADD, 0},
-  {"-", BINOP_SUB, PREC_ADD, 0},
-  {"*", BINOP_MUL, PREC_MUL, 0},
-  {"/", BINOP_DIV, PREC_MUL, 0},
-  {"div", BINOP_INTDIV, PREC_MUL, 0},
-  {"mod", BINOP_REM, PREC_MUL, 0},
-  {"@", BINOP_REPEAT, PREC_REPEAT, 0},
-  {"-", UNOP_NEG, PREC_PREFIX, 0},
-  {"not", UNOP_LOGICAL_NOT, PREC_PREFIX, 0},
-  {"^", UNOP_IND, PREC_SUFFIX, 1},
-  {"@", UNOP_ADDR, PREC_PREFIX, 0},
-  {"sizeof", UNOP_SIZEOF, PREC_PREFIX, 0},
-  {NULL, OP_NULL, PREC_PREFIX, 0}
-};
-\f
-
 /* See language.h.  */
 
 void pascal_language::language_arch_info
diff --git a/gdb/p-lang.h b/gdb/p-lang.h
index b93451dcaa3..95dca01f22e 100644
--- a/gdb/p-lang.h
+++ b/gdb/p-lang.h
@@ -154,17 +154,8 @@ class pascal_language : public language_defn
   bool range_checking_on_by_default () const override
   { return true; }
 
-  /* See language.h.  */
-
-  const struct op_print *opcode_print_table () const override
-  { return op_print_tab; }
-
 private:
 
-  /* Table of opcode data for use by OPCODE_PRINT_TABLE member function.  */
-
-  static const struct op_print op_print_tab[];
-
   /* Print the character C on STREAM as part of the contents of a literal
      string.  IN_QUOTES is reset to 0 if a char is written with #4 notation.  */
 
diff --git a/gdb/parse.c b/gdb/parse.c
index 28ac43f0d16..637a9f3d246 100644
--- a/gdb/parse.c
+++ b/gdb/parse.c
@@ -52,18 +52,6 @@
 #include "gdbsupport/gdb_optional.h"
 #include "c-exp.h"
 
-/* Standard set of definitions for printing, dumping, prefixifying,
- * and evaluating expressions.  */
-
-const struct exp_descriptor exp_descriptor_standard = 
-  {
-    print_subexp_standard,
-    operator_length_standard,
-    operator_check_standard,
-    dump_subexp_body_standard,
-    evaluate_subexp_standard
-  };
-\f
 static unsigned int expressiondebug = 0;
 static void
 show_expressiondebug (struct ui_file *file, int from_tty,
@@ -84,18 +72,11 @@ show_parserdebug (struct ui_file *file, int from_tty,
 }
 
 
-static int prefixify_subexp (struct expression *, struct expression *, int,
-			     int, int);
-
 static expression_up parse_exp_in_context (const char **, CORE_ADDR,
 					   const struct block *, int,
-					   bool, int *,
-					   innermost_block_tracker *,
+					   bool, innermost_block_tracker *,
 					   expr_completion_state *);
 
-static void increase_expout_size (struct expr_builder *ps, size_t lenelt);
-
-
 /* Documented at it's declaration.  */
 
 void
@@ -114,297 +95,24 @@ innermost_block_tracker::update (const struct block *b,
 
 expr_builder::expr_builder (const struct language_defn *lang,
 			    struct gdbarch *gdbarch)
-  : expout_size (10),
-    expout (new expression (lang, gdbarch, expout_size)),
-    expout_ptr (0)
+  : expout (new expression (lang, gdbarch))
 {
 }
 
 expression_up
 expr_builder::release ()
 {
-  /* Record the actual number of expression elements, and then
-     reallocate the expression memory so that we free up any
-     excess elements.  */
-
-  expout->nelts = expout_ptr;
-  expout->resize (expout_ptr);
-
   return std::move (expout);
 }
 
-expression::expression (const struct language_defn *lang, struct gdbarch *arch,
-			size_t n)
+expression::expression (const struct language_defn *lang, struct gdbarch *arch)
   : language_defn (lang),
-    gdbarch (arch),
-    elts (nullptr)
+    gdbarch (arch)
 {
-  resize (n);
 }
 
 expression::~expression ()
 {
-  xfree (elts);
-}
-
-void
-expression::resize (size_t n)
-{
-  elts = XRESIZEVAR (union exp_element, elts, EXP_ELEM_TO_BYTES (n));
-}
-
-/* This page contains the functions for adding data to the struct expression
-   being constructed.  */
-
-/* Add one element to the end of the expression.  */
-
-/* To avoid a bug in the Sun 4 compiler, we pass things that can fit into
-   a register through here.  */
-
-static void
-write_exp_elt (struct expr_builder *ps, const union exp_element *expelt)
-{
-  if (ps->expout_ptr >= ps->expout_size)
-    {
-      ps->expout_size *= 2;
-      ps->expout->resize (ps->expout_size);
-    }
-  ps->expout->elts[ps->expout_ptr++] = *expelt;
-}
-
-void
-write_exp_elt_opcode (struct expr_builder *ps, enum exp_opcode expelt)
-{
-  union exp_element tmp;
-
-  memset (&tmp, 0, sizeof (union exp_element));
-  tmp.opcode = expelt;
-  write_exp_elt (ps, &tmp);
-}
-
-void
-write_exp_elt_sym (struct expr_builder *ps, struct symbol *expelt)
-{
-  union exp_element tmp;
-
-  memset (&tmp, 0, sizeof (union exp_element));
-  tmp.symbol = expelt;
-  write_exp_elt (ps, &tmp);
-}
-
-static void
-write_exp_elt_msym (struct expr_builder *ps, minimal_symbol *expelt)
-{
-  union exp_element tmp;
-
-  memset (&tmp, 0, sizeof (union exp_element));
-  tmp.msymbol = expelt;
-  write_exp_elt (ps, &tmp);
-}
-
-void
-write_exp_elt_block (struct expr_builder *ps, const struct block *b)
-{
-  union exp_element tmp;
-
-  memset (&tmp, 0, sizeof (union exp_element));
-  tmp.block = b;
-  write_exp_elt (ps, &tmp);
-}
-
-void
-write_exp_elt_objfile (struct expr_builder *ps, struct objfile *objfile)
-{
-  union exp_element tmp;
-
-  memset (&tmp, 0, sizeof (union exp_element));
-  tmp.objfile = objfile;
-  write_exp_elt (ps, &tmp);
-}
-
-void
-write_exp_elt_longcst (struct expr_builder *ps, LONGEST expelt)
-{
-  union exp_element tmp;
-
-  memset (&tmp, 0, sizeof (union exp_element));
-  tmp.longconst = expelt;
-  write_exp_elt (ps, &tmp);
-}
-
-void
-write_exp_elt_floatcst (struct expr_builder *ps, const gdb_byte expelt[16])
-{
-  union exp_element tmp;
-  int index;
-
-  for (index = 0; index < 16; index++)
-    tmp.floatconst[index] = expelt[index];
-
-  write_exp_elt (ps, &tmp);
-}
-
-void
-write_exp_elt_type (struct expr_builder *ps, struct type *expelt)
-{
-  union exp_element tmp;
-
-  memset (&tmp, 0, sizeof (union exp_element));
-  tmp.type = expelt;
-  write_exp_elt (ps, &tmp);
-}
-
-void
-write_exp_elt_intern (struct expr_builder *ps, struct internalvar *expelt)
-{
-  union exp_element tmp;
-
-  memset (&tmp, 0, sizeof (union exp_element));
-  tmp.internalvar = expelt;
-  write_exp_elt (ps, &tmp);
-}
-
-/* Add a string constant to the end of the expression.
-
-   String constants are stored by first writing an expression element
-   that contains the length of the string, then stuffing the string
-   constant itself into however many expression elements are needed
-   to hold it, and then writing another expression element that contains
-   the length of the string.  I.e. an expression element at each end of
-   the string records the string length, so you can skip over the 
-   expression elements containing the actual string bytes from either
-   end of the string.  Note that this also allows gdb to handle
-   strings with embedded null bytes, as is required for some languages.
-
-   Don't be fooled by the fact that the string is null byte terminated,
-   this is strictly for the convenience of debugging gdb itself.
-   Gdb does not depend up the string being null terminated, since the
-   actual length is recorded in expression elements at each end of the
-   string.  The null byte is taken into consideration when computing how
-   many expression elements are required to hold the string constant, of
-   course.  */
-
-
-void
-write_exp_string (struct expr_builder *ps, struct stoken str)
-{
-  int len = str.length;
-  size_t lenelt;
-  char *strdata;
-
-  /* Compute the number of expression elements required to hold the string
-     (including a null byte terminator), along with one expression element
-     at each end to record the actual string length (not including the
-     null byte terminator).  */
-
-  lenelt = 2 + BYTES_TO_EXP_ELEM (len + 1);
-
-  increase_expout_size (ps, lenelt);
-
-  /* Write the leading length expression element (which advances the current
-     expression element index), then write the string constant followed by a
-     terminating null byte, and then write the trailing length expression
-     element.  */
-
-  write_exp_elt_longcst (ps, (LONGEST) len);
-  strdata = (char *) &ps->expout->elts[ps->expout_ptr];
-  memcpy (strdata, str.ptr, len);
-  *(strdata + len) = '\0';
-  ps->expout_ptr += lenelt - 2;
-  write_exp_elt_longcst (ps, (LONGEST) len);
-}
-
-/* Add a vector of string constants to the end of the expression.
-
-   This adds an OP_STRING operation, but encodes the contents
-   differently from write_exp_string.  The language is expected to
-   handle evaluation of this expression itself.
-   
-   After the usual OP_STRING header, TYPE is written into the
-   expression as a long constant.  The interpretation of this field is
-   up to the language evaluator.
-   
-   Next, each string in VEC is written.  The length is written as a
-   long constant, followed by the contents of the string.  */
-
-void
-write_exp_string_vector (struct expr_builder *ps, int type,
-			 struct stoken_vector *vec)
-{
-  int i, len;
-  size_t n_slots;
-
-  /* Compute the size.  We compute the size in number of slots to
-     avoid issues with string padding.  */
-  n_slots = 0;
-  for (i = 0; i < vec->len; ++i)
-    {
-      /* One slot for the length of this element, plus the number of
-	 slots needed for this string.  */
-      n_slots += 1 + BYTES_TO_EXP_ELEM (vec->tokens[i].length);
-    }
-
-  /* One more slot for the type of the string.  */
-  ++n_slots;
-
-  /* Now compute a phony string length.  */
-  len = EXP_ELEM_TO_BYTES (n_slots) - 1;
-
-  n_slots += 4;
-  increase_expout_size (ps, n_slots);
-
-  write_exp_elt_opcode (ps, OP_STRING);
-  write_exp_elt_longcst (ps, len);
-  write_exp_elt_longcst (ps, type);
-
-  for (i = 0; i < vec->len; ++i)
-    {
-      write_exp_elt_longcst (ps, vec->tokens[i].length);
-      memcpy (&ps->expout->elts[ps->expout_ptr], vec->tokens[i].ptr,
-	      vec->tokens[i].length);
-      ps->expout_ptr += BYTES_TO_EXP_ELEM (vec->tokens[i].length);
-    }
-
-  write_exp_elt_longcst (ps, len);
-  write_exp_elt_opcode (ps, OP_STRING);
-}
-
-/* Add a bitstring constant to the end of the expression.
-
-   Bitstring constants are stored by first writing an expression element
-   that contains the length of the bitstring (in bits), then stuffing the
-   bitstring constant itself into however many expression elements are
-   needed to hold it, and then writing another expression element that
-   contains the length of the bitstring.  I.e. an expression element at
-   each end of the bitstring records the bitstring length, so you can skip
-   over the expression elements containing the actual bitstring bytes from
-   either end of the bitstring.  */
-
-void
-write_exp_bitstring (struct expr_builder *ps, struct stoken str)
-{
-  int bits = str.length;	/* length in bits */
-  int len = (bits + HOST_CHAR_BIT - 1) / HOST_CHAR_BIT;
-  size_t lenelt;
-  char *strdata;
-
-  /* Compute the number of expression elements required to hold the bitstring,
-     along with one expression element at each end to record the actual
-     bitstring length in bits.  */
-
-  lenelt = 2 + BYTES_TO_EXP_ELEM (len);
-
-  increase_expout_size (ps, lenelt);
-
-  /* Write the leading length expression element (which advances the current
-     expression element index), then write the bitstring constant, and then
-     write the trailing length expression element.  */
-
-  write_exp_elt_longcst (ps, (LONGEST) bits);
-  strdata = (char *) &ps->expout->elts[ps->expout_ptr];
-  memcpy (strdata, str.ptr, len);
-  ps->expout_ptr += lenelt - 2;
-  write_exp_elt_longcst (ps, (LONGEST) bits);
 }
 
 /* Return the type of MSYMBOL, a minimal symbol of OBJFILE.  If
@@ -487,31 +195,6 @@ find_minsym_type_and_address (minimal_symbol *msymbol,
     }
 }
 
-/* Add the appropriate elements for a minimal symbol to the end of
-   the expression.  */
-
-void
-write_exp_msymbol (struct expr_builder *ps,
-		   struct bound_minimal_symbol bound_msym)
-{
-  write_exp_elt_opcode (ps, OP_VAR_MSYM_VALUE);
-  write_exp_elt_objfile (ps, bound_msym.objfile);
-  write_exp_elt_msym (ps, bound_msym.minsym);
-  write_exp_elt_opcode (ps, OP_VAR_MSYM_VALUE);
-}
-
-/* See parser-defs.h.  */
-
-void
-parser_state::mark_struct_expression ()
-{
-  gdb_assert (parse_completion
-	      && (m_completion_state.expout_tag_completion_type
-		  == TYPE_CODE_UNDEF)
-	      && m_completion_state.expout_last_op == nullptr);
-  m_completion_state.expout_last_struct = expout_ptr;
-}
-
 /* See parser-defs.h.  */
 
 void
@@ -519,8 +202,7 @@ parser_state::mark_struct_expression (expr::structop_base_operation *op)
 {
   gdb_assert (parse_completion
 	      && (m_completion_state.expout_tag_completion_type
-		  == TYPE_CODE_UNDEF)
-	      && m_completion_state.expout_last_struct == -1);
+		  == TYPE_CODE_UNDEF));
   m_completion_state.expout_last_op = op;
 }
 
@@ -536,7 +218,6 @@ parser_state::mark_completion_tag (enum type_code tag, const char *ptr,
 	      && (m_completion_state.expout_tag_completion_type
 		  == TYPE_CODE_UNDEF)
 	      && m_completion_state.expout_completion_name == NULL
-	      && m_completion_state.expout_last_struct == -1
 	      && m_completion_state.expout_last_op == nullptr);
   gdb_assert (tag == TYPE_CODE_UNION
 	      || tag == TYPE_CODE_STRUCT
@@ -670,150 +351,6 @@ parser_state::push_dollar (struct stoken str)
 }
 
 \f
-/* Recognize tokens that start with '$'.  These include:
-
-   $regname     A native register name or a "standard
-   register name".
-
-   $variable    A convenience variable with a name chosen
-   by the user.
-
-   $digits              Value history with index <digits>, starting
-   from the first value which has index 1.
-
-   $$digits     Value history with index <digits> relative
-   to the last value.  I.e. $$0 is the last
-   value, $$1 is the one previous to that, $$2
-   is the one previous to $$1, etc.
-
-   $ | $0 | $$0 The last value in the value history.
-
-   $$           An abbreviation for the second to the last
-   value in the value history, I.e. $$1  */
-
-void
-write_dollar_variable (struct parser_state *ps, struct stoken str)
-{
-  struct block_symbol sym;
-  struct bound_minimal_symbol msym;
-  struct internalvar *isym = NULL;
-  std::string copy;
-
-  /* Handle the tokens $digits; also $ (short for $0) and $$ (short for $$1)
-     and $$digits (equivalent to $<-digits> if you could type that).  */
-
-  int negate = 0;
-  int i = 1;
-  /* Double dollar means negate the number and add -1 as well.
-     Thus $$ alone means -1.  */
-  if (str.length >= 2 && str.ptr[1] == '$')
-    {
-      negate = 1;
-      i = 2;
-    }
-  if (i == str.length)
-    {
-      /* Just dollars (one or two).  */
-      i = -negate;
-      goto handle_last;
-    }
-  /* Is the rest of the token digits?  */
-  for (; i < str.length; i++)
-    if (!(str.ptr[i] >= '0' && str.ptr[i] <= '9'))
-      break;
-  if (i == str.length)
-    {
-      i = atoi (str.ptr + 1 + negate);
-      if (negate)
-	i = -i;
-      goto handle_last;
-    }
-
-  /* Handle tokens that refer to machine registers:
-     $ followed by a register name.  */
-  i = user_reg_map_name_to_regnum (ps->gdbarch (),
-				   str.ptr + 1, str.length - 1);
-  if (i >= 0)
-    goto handle_register;
-
-  /* Any names starting with $ are probably debugger internal variables.  */
-
-  copy = copy_name (str);
-  isym = lookup_only_internalvar (copy.c_str () + 1);
-  if (isym)
-    {
-      write_exp_elt_opcode (ps, OP_INTERNALVAR);
-      write_exp_elt_intern (ps, isym);
-      write_exp_elt_opcode (ps, OP_INTERNALVAR);
-      return;
-    }
-
-  /* On some systems, such as HP-UX and hppa-linux, certain system routines 
-     have names beginning with $ or $$.  Check for those, first.  */
-
-  sym = lookup_symbol (copy.c_str (), NULL, VAR_DOMAIN, NULL);
-  if (sym.symbol)
-    {
-      write_exp_elt_opcode (ps, OP_VAR_VALUE);
-      write_exp_elt_block (ps, sym.block);
-      write_exp_elt_sym (ps, sym.symbol);
-      write_exp_elt_opcode (ps, OP_VAR_VALUE);
-      return;
-    }
-  msym = lookup_bound_minimal_symbol (copy.c_str ());
-  if (msym.minsym)
-    {
-      write_exp_msymbol (ps, msym);
-      return;
-    }
-
-  /* Any other names are assumed to be debugger internal variables.  */
-
-  write_exp_elt_opcode (ps, OP_INTERNALVAR);
-  write_exp_elt_intern (ps, create_internalvar (copy.c_str () + 1));
-  write_exp_elt_opcode (ps, OP_INTERNALVAR);
-  return;
-handle_last:
-  write_exp_elt_opcode (ps, OP_LAST);
-  write_exp_elt_longcst (ps, (LONGEST) i);
-  write_exp_elt_opcode (ps, OP_LAST);
-  return;
-handle_register:
-  write_exp_elt_opcode (ps, OP_REGISTER);
-  str.length--;
-  str.ptr++;
-  write_exp_string (ps, str);
-  write_exp_elt_opcode (ps, OP_REGISTER);
-  ps->block_tracker->update (ps->expression_context_block,
-			     INNERMOST_BLOCK_FOR_REGISTERS);
-  return;
-}
-
-/* See parser-defs.h.  */
-
-void
-write_exp_symbol_reference (struct parser_state *pstate, const char *name,
-			    struct symbol *sym)
-{
-  if (sym != nullptr)
-    {
-      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
-      write_exp_elt_block (pstate, NULL);
-      write_exp_elt_sym (pstate, sym);
-      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
-    }
-  else
-    {
-      struct bound_minimal_symbol msymbol = lookup_bound_minimal_symbol (name);
-      if (msymbol.minsym != NULL)
-	write_exp_msymbol (pstate, msymbol);
-      else if (!have_full_symbols () && !have_partial_symbols ())
-	error (_("No symbol table is loaded.  Use the \"file\" command."));
-      else
-	error (_("No symbol \"%s\" in current context."),
-	       name);
-    }
-}
 
 const char *
 find_template_name_end (const char *p)
@@ -891,293 +428,6 @@ copy_name (struct stoken token)
 }
 \f
 
-/* See comments on parser-defs.h.  */
-
-int
-prefixify_expression (struct expression *expr, int last_struct)
-{
-  gdb_assert (expr->nelts > 0);
-  int len = EXP_ELEM_TO_BYTES (expr->nelts);
-  struct expression temp (expr->language_defn, expr->gdbarch, expr->nelts);
-  int inpos = expr->nelts, outpos = 0;
-
-  /* Copy the original expression into temp.  */
-  memcpy (temp.elts, expr->elts, len);
-
-  return prefixify_subexp (&temp, expr, inpos, outpos, last_struct);
-}
-
-/* Return the number of exp_elements in the postfix subexpression 
-   of EXPR whose operator is at index ENDPOS - 1 in EXPR.  */
-
-static int
-length_of_subexp (struct expression *expr, int endpos)
-{
-  int oplen, args;
-
-  operator_length (expr, endpos, &oplen, &args);
-
-  while (args > 0)
-    {
-      oplen += length_of_subexp (expr, endpos - oplen);
-      args--;
-    }
-
-  return oplen;
-}
-
-/* Sets *OPLENP to the length of the operator whose (last) index is 
-   ENDPOS - 1 in EXPR, and sets *ARGSP to the number of arguments that
-   operator takes.  */
-
-void
-operator_length (const struct expression *expr, int endpos, int *oplenp,
-		 int *argsp)
-{
-  expr->language_defn->expression_ops ()->operator_length (expr, endpos,
-							   oplenp, argsp);
-}
-
-/* Default value for operator_length in exp_descriptor vectors.  */
-
-void
-operator_length_standard (const struct expression *expr, int endpos,
-			  int *oplenp, int *argsp)
-{
-  int oplen = 1;
-  int args = 0;
-  enum range_flag range_flag;
-  int i;
-
-  if (endpos < 1)
-    error (_("?error in operator_length_standard"));
-
-  i = (int) expr->elts[endpos - 1].opcode;
-
-  switch (i)
-    {
-      /* C++  */
-    case OP_SCOPE:
-      oplen = longest_to_int (expr->elts[endpos - 2].longconst);
-      oplen = 5 + BYTES_TO_EXP_ELEM (oplen + 1);
-      break;
-
-    case OP_LONG:
-    case OP_FLOAT:
-    case OP_VAR_VALUE:
-    case OP_VAR_MSYM_VALUE:
-      oplen = 4;
-      break;
-
-    case OP_FUNC_STATIC_VAR:
-      oplen = longest_to_int (expr->elts[endpos - 2].longconst);
-      oplen = 4 + BYTES_TO_EXP_ELEM (oplen + 1);
-      args = 1;
-      break;
-
-    case OP_TYPE:
-    case OP_BOOL:
-    case OP_LAST:
-    case OP_INTERNALVAR:
-    case OP_VAR_ENTRY_VALUE:
-      oplen = 3;
-      break;
-
-    case OP_COMPLEX:
-      oplen = 3;
-      args = 2;
-      break;
-
-    case OP_FUNCALL:
-      oplen = 3;
-      args = 1 + longest_to_int (expr->elts[endpos - 2].longconst);
-      break;
-
-    case TYPE_INSTANCE:
-      oplen = 5 + longest_to_int (expr->elts[endpos - 2].longconst);
-      args = 1;
-      break;
-
-    case OP_OBJC_MSGCALL:	/* Objective C message (method) call.  */
-      oplen = 4;
-      args = 1 + longest_to_int (expr->elts[endpos - 2].longconst);
-      break;
-
-    case UNOP_MAX:
-    case UNOP_MIN:
-      oplen = 3;
-      break;
-
-    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;
-      break;
-
-    case UNOP_ABS:
-    case UNOP_CAP:
-    case UNOP_CHR:
-    case UNOP_FLOAT:
-    case UNOP_HIGH:
-    case UNOP_ODD:
-    case UNOP_ORD:
-    case UNOP_TRUNC:
-    case OP_TYPEOF:
-    case OP_DECLTYPE:
-    case OP_TYPEID:
-      oplen = 1;
-      args = 1;
-      break;
-
-    case OP_ADL_FUNC:
-      oplen = longest_to_int (expr->elts[endpos - 2].longconst);
-      oplen = 4 + BYTES_TO_EXP_ELEM (oplen + 1);
-      oplen++;
-      oplen++;
-      break;
-
-    case STRUCTOP_STRUCT:
-    case STRUCTOP_PTR:
-      args = 1;
-      /* fall through */
-    case OP_REGISTER:
-    case OP_M2_STRING:
-    case OP_STRING:
-    case OP_OBJC_NSSTRING:	/* Objective C Foundation Class
-				   NSString constant.  */
-    case OP_OBJC_SELECTOR:	/* Objective C "@selector" pseudo-op.  */
-    case OP_NAME:
-      oplen = longest_to_int (expr->elts[endpos - 2].longconst);
-      oplen = 4 + BYTES_TO_EXP_ELEM (oplen + 1);
-      break;
-
-    case OP_ARRAY:
-      oplen = 4;
-      args = longest_to_int (expr->elts[endpos - 2].longconst);
-      args -= longest_to_int (expr->elts[endpos - 3].longconst);
-      args += 1;
-      break;
-
-    case TERNOP_COND:
-    case TERNOP_SLICE:
-      args = 3;
-      break;
-
-      /* Modula-2 */
-    case MULTI_SUBSCRIPT:
-      oplen = 3;
-      args = 1 + longest_to_int (expr->elts[endpos - 2].longconst);
-      break;
-
-    case BINOP_ASSIGN_MODIFY:
-      oplen = 3;
-      args = 2;
-      break;
-
-      /* C++ */
-    case OP_THIS:
-      oplen = 2;
-      break;
-
-    case OP_RANGE:
-      oplen = 3;
-      range_flag = (enum range_flag)
-	longest_to_int (expr->elts[endpos - 2].longconst);
-
-      /* Assume the range has 2 arguments (low bound and high bound), then
-	 reduce the argument count if any bounds are set to default.  */
-      args = 2;
-      if (range_flag & RANGE_HAS_STRIDE)
-	++args;
-      if (range_flag & RANGE_LOW_BOUND_DEFAULT)
-	--args;
-      if (range_flag & RANGE_HIGH_BOUND_DEFAULT)
-	--args;
-
-      break;
-
-    default:
-      args = 1 + (i < (int) BINOP_END);
-    }
-
-  *oplenp = oplen;
-  *argsp = args;
-}
-
-/* Copy the subexpression ending just before index INEND in INEXPR
-   into OUTEXPR, starting at index OUTBEG.
-   In the process, convert it from suffix to prefix form.
-   If LAST_STRUCT is -1, then this function always returns -1.
-   Otherwise, it returns the index of the subexpression which is the
-   left-hand-side of the expression at LAST_STRUCT.  */
-
-static int
-prefixify_subexp (struct expression *inexpr,
-		  struct expression *outexpr, int inend, int outbeg,
-		  int last_struct)
-{
-  int oplen;
-  int args;
-  int i;
-  int *arglens;
-  int result = -1;
-
-  operator_length (inexpr, inend, &oplen, &args);
-
-  /* Copy the final operator itself, from the end of the input
-     to the beginning of the output.  */
-  inend -= oplen;
-  memcpy (&outexpr->elts[outbeg], &inexpr->elts[inend],
-	  EXP_ELEM_TO_BYTES (oplen));
-  outbeg += oplen;
-
-  if (last_struct == inend)
-    result = outbeg - oplen;
-
-  /* Find the lengths of the arg subexpressions.  */
-  arglens = (int *) alloca (args * sizeof (int));
-  for (i = args - 1; i >= 0; i--)
-    {
-      oplen = length_of_subexp (inexpr, inend);
-      arglens[i] = oplen;
-      inend -= oplen;
-    }
-
-  /* Now copy each subexpression, preserving the order of
-     the subexpressions, but prefixifying each one.
-     In this loop, inend starts at the beginning of
-     the expression this level is working on
-     and marches forward over the arguments.
-     outbeg does similarly in the output.  */
-  for (i = 0; i < args; i++)
-    {
-      int r;
-
-      oplen = arglens[i];
-      inend += oplen;
-      r = prefixify_subexp (inexpr, outexpr, inend, outbeg, last_struct);
-      if (r != -1)
-	{
-	  /* Return immediately.  We probably have only parsed a
-	     partial expression, so we don't want to try to reverse
-	     the other operands.  */
-	  return r;
-	}
-      outbeg += oplen;
-    }
-
-  return result;
-}
-\f
 /* Read an expression from the string *STRINGPTR points to,
    parse it, and return a pointer to a struct expression that we malloc.
    Use block BLOCK as the lexical context for variable names;
@@ -1192,26 +442,21 @@ expression_up
 parse_exp_1 (const char **stringptr, CORE_ADDR pc, const struct block *block,
 	     int comma, innermost_block_tracker *tracker)
 {
-  return parse_exp_in_context (stringptr, pc, block, comma, false, NULL,
+  return parse_exp_in_context (stringptr, pc, block, comma, false,
 			       tracker, nullptr);
 }
 
 /* As for parse_exp_1, except that if VOID_CONTEXT_P, then
-   no value is expected from the expression.
-   OUT_SUBEXP is set when attempting to complete a field name; in this
-   case it is set to the index of the subexpression on the
-   left-hand-side of the struct op.  If not doing such completion, it
-   is left untouched.  */
+   no value is expected from the expression.  */
 
 static expression_up
 parse_exp_in_context (const char **stringptr, CORE_ADDR pc,
 		      const struct block *block,
-		      int comma, bool void_context_p, int *out_subexp,
+		      int comma, bool void_context_p,
 		      innermost_block_tracker *tracker,
 		      expr_completion_state *cstate)
 {
   const struct language_defn *lang = NULL;
-  int subexp;
 
   if (*stringptr == 0 || **stringptr == 0)
     error_no_arg (_("expression to compute"));
@@ -1291,30 +536,12 @@ parse_exp_in_context (const char **stringptr, CORE_ADDR pc,
       /* If parsing for completion, allow this to succeed; but if no
 	 expression elements have been written, then there's nothing
 	 to do, so fail.  */
-      if (! ps.parse_completion
-	  || (ps.expout->op == nullptr && ps.expout_ptr == 0))
+      if (! ps.parse_completion || ps.expout->op == nullptr)
 	throw;
     }
 
-  /* We have to operate on an "expression *", due to la_post_parser,
-     which explains this funny-looking double release.  */
   expression_up result = ps.release ();
 
-  /* Convert expression from postfix form as generated by yacc
-     parser, to a prefix form.  */
-
-  if (expressiondebug)
-    dump_raw_expression (result.get (), gdb_stdlog,
-			 "before conversion to prefix form");
-
-  if (result->op == nullptr)
-    subexp = prefixify_expression (result.get (),
-				   ps.m_completion_state.expout_last_struct);
-  if (out_subexp)
-    *out_subexp = subexp;
-
-  lang->post_parser (&result, &ps);
-
   if (expressiondebug)
     dump_prefix_expression (result.get (), gdb_stdlog);
 
@@ -1365,14 +592,11 @@ parse_expression_for_completion (const char *string,
 				 enum type_code *code)
 {
   expression_up exp;
-  struct value *val;
-  int subexp;
   expr_completion_state cstate;
 
   try
     {
-      exp = parse_exp_in_context (&string, 0, 0, 0, false, &subexp,
-				  nullptr, &cstate);
+      exp = parse_exp_in_context (&string, 0, 0, 0, false, nullptr, &cstate);
     }
   catch (const gdb_exception_error &except)
     {
@@ -1389,30 +613,13 @@ parse_expression_for_completion (const char *string,
       return NULL;
     }
 
-  if (cstate.expout_last_op != nullptr)
-    {
-      expr::structop_base_operation *op = cstate.expout_last_op;
-      const std::string &fld = op->get_string ();
-      *name = make_unique_xstrdup (fld.c_str ());
-      return value_type (op->evaluate_lhs (exp.get ()));
-    }
+  if (cstate.expout_last_op == nullptr)
+    return nullptr;
 
-  if (cstate.expout_last_struct == -1)
-    return NULL;
-
-  const char *fieldname = extract_field_op (exp.get (), &subexp);
-  if (fieldname == NULL)
-    {
-      name->reset ();
-      return NULL;
-    }
-
-  name->reset (xstrdup (fieldname));
-  /* This might throw an exception.  If so, we want to let it
-     propagate.  */
-  val = evaluate_subexpression_type (exp.get (), subexp);
-
-  return value_type (val);
+  expr::structop_base_operation *op = cstate.expout_last_op;
+  const std::string &fld = op->get_string ();
+  *name = make_unique_xstrdup (fld.c_str ());
+  return value_type (op->evaluate_lhs (exp.get ()));
 }
 
 /* Parse floating point value P of length LEN.
@@ -1447,132 +654,6 @@ parser_fprintf (FILE *x, const char *y, ...)
   va_end (args);
 }
 
-/* Implementation of the exp_descriptor method operator_check.  */
-
-int
-operator_check_standard (struct expression *exp, int pos,
-			 int (*objfile_func) (struct objfile *objfile,
-					      void *data),
-			 void *data)
-{
-  const union exp_element *const elts = exp->elts;
-  struct type *type = NULL;
-  struct objfile *objfile = NULL;
-
-  /* Extended operators should have been already handled by exp_descriptor
-     iterate method of its specific language.  */
-  gdb_assert (elts[pos].opcode < OP_EXTENDED0);
-
-  /* Track the callers of write_exp_elt_type for this table.  */
-
-  switch (elts[pos].opcode)
-    {
-    case BINOP_VAL:
-    case OP_COMPLEX:
-    case OP_FLOAT:
-    case OP_LONG:
-    case OP_SCOPE:
-    case OP_TYPE:
-    case UNOP_CAST:
-    case UNOP_MAX:
-    case UNOP_MEMVAL:
-    case UNOP_MIN:
-      type = elts[pos + 1].type;
-      break;
-
-    case TYPE_INSTANCE:
-      {
-	LONGEST arg, nargs = elts[pos + 2].longconst;
-
-	for (arg = 0; arg < nargs; arg++)
-	  {
-	    struct type *inst_type = elts[pos + 3 + arg].type;
-	    struct objfile *inst_objfile = TYPE_OBJFILE (inst_type);
-
-	    if (inst_objfile && (*objfile_func) (inst_objfile, data))
-	      return 1;
-	  }
-      }
-      break;
-
-    case OP_VAR_VALUE:
-      {
-	const struct block *const block = elts[pos + 1].block;
-	const struct symbol *const symbol = elts[pos + 2].symbol;
-
-	/* Check objfile where the variable itself is placed.
-	   SYMBOL_OBJ_SECTION (symbol) may be NULL.  */
-	if ((*objfile_func) (symbol_objfile (symbol), data))
-	  return 1;
-
-	/* Check objfile where is placed the code touching the variable.  */
-	objfile = block_objfile (block);
-
-	type = SYMBOL_TYPE (symbol);
-      }
-      break;
-    case OP_VAR_MSYM_VALUE:
-      objfile = elts[pos + 1].objfile;
-      break;
-    }
-
-  /* Invoke callbacks for TYPE and OBJFILE if they were set as non-NULL.  */
-
-  if (type && TYPE_OBJFILE (type)
-      && (*objfile_func) (TYPE_OBJFILE (type), data))
-    return 1;
-  if (objfile && (*objfile_func) (objfile, data))
-    return 1;
-
-  return 0;
-}
-
-/* Call OBJFILE_FUNC for any objfile found being referenced by EXP.
-   OBJFILE_FUNC is never called with NULL OBJFILE.  OBJFILE_FUNC get
-   passed an arbitrary caller supplied DATA pointer.  If OBJFILE_FUNC
-   returns non-zero value then (any other) non-zero value is immediately
-   returned to the caller.  Otherwise zero is returned after iterating
-   through whole EXP.  */
-
-static int
-exp_iterate (struct expression *exp,
-	     int (*objfile_func) (struct objfile *objfile, void *data),
-	     void *data)
-{
-  int endpos;
-
-  for (endpos = exp->nelts; endpos > 0; )
-    {
-      int pos, args, oplen = 0;
-
-      operator_length (exp, endpos, &oplen, &args);
-      gdb_assert (oplen > 0);
-
-      pos = endpos - oplen;
-      if (exp->language_defn->expression_ops ()->operator_check (exp, pos,
-								 objfile_func,
-								 data))
-	return 1;
-
-      endpos = pos;
-    }
-
-  return 0;
-}
-
-/* Helper for exp_uses_objfile.  */
-
-static int
-exp_uses_objfile_iter (struct objfile *exp_objfile, void *objfile_voidp)
-{
-  struct objfile *objfile = (struct objfile *) objfile_voidp;
-
-  if (exp_objfile->separate_debug_objfile_backlink)
-    exp_objfile = exp_objfile->separate_debug_objfile_backlink;
-
-  return exp_objfile == objfile;
-}
-
 /* Return 1 if EXP uses OBJFILE (and will become dangling when OBJFILE
    is unloaded), otherwise return 0.  OBJFILE must not be a separate debug info
    file.  */
@@ -1582,25 +663,7 @@ exp_uses_objfile (struct expression *exp, struct objfile *objfile)
 {
   gdb_assert (objfile->separate_debug_objfile_backlink == NULL);
 
-  if (exp->op != nullptr)
-    return exp->op->uses_objfile (objfile);
-
-  return exp_iterate (exp, exp_uses_objfile_iter, objfile);
-}
-
-/* Reallocate the `expout' pointer inside PS so that it can accommodate
-   at least LENELT expression elements.  This function does nothing if
-   there is enough room for the elements.  */
-
-static void
-increase_expout_size (struct expr_builder *ps, size_t lenelt)
-{
-  if ((ps->expout_ptr + lenelt) >= ps->expout_size)
-    {
-      ps->expout_size = std::max (ps->expout_size * 2,
-				  ps->expout_ptr + lenelt + 10);
-      ps->expout->resize (ps->expout_size);
-    }
+  return exp->op->uses_objfile (objfile);
 }
 
 void _initialize_parse ();
diff --git a/gdb/parser-defs.h b/gdb/parser-defs.h
index 8ddbac2c134..b6cf4a694c7 100644
--- a/gdb/parser-defs.h
+++ b/gdb/parser-defs.h
@@ -71,29 +71,15 @@ struct expr_builder
     expout->op = std::move (op);
   }
 
-  /* The size of the expression above.  */
-
-  size_t expout_size;
-
   /* The expression related to this parser state.  */
 
   expression_up expout;
-
-  /* The number of elements already in the expression.  This is used
-     to know where to put new elements.  */
-
-  size_t expout_ptr;
 };
 
 /* This is used for expression completion.  */
 
 struct expr_completion_state
 {
-  /* The index of the last struct expression directly before a '.' or
-     '->'.  This is set when parsing and is only used when completing a
-     field name.  It is -1 if no dereference operation was found.  */
-  int expout_last_struct = -1;
-
   /* The last struct expression directly before a '.' or '->'.  This
      is set when parsing and is only used when completing a field
      name.  It is nullptr if no dereference operation was found.  */
@@ -157,11 +143,6 @@ struct parser_state : public expr_builder
     return val;
   }
 
-  /* Mark the current index as the starting location of a structure
-     expression.  This is used when completing on field names.  */
-
-  void mark_struct_expression ();
-
   /* Mark the given operation as the starting location of a structure
      expression.  This is used when completing on field names.  */
 
@@ -376,173 +357,13 @@ struct objc_class_str
     int theclass;
   };
 
-/* 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
-   is not -1 (i.e., we are trying to complete a field name), it will
-   return the index of the subexpression which is the left-hand-side
-   of the struct operation at LAST_STRUCT.  */
-
-extern int prefixify_expression (struct expression *expr,
-				 int last_struct = -1);
-
-extern void write_exp_elt_opcode (struct expr_builder *, enum exp_opcode);
-
-extern void write_exp_elt_sym (struct expr_builder *, struct symbol *);
-
-extern void write_exp_elt_longcst (struct expr_builder *, LONGEST);
-
-extern void write_exp_elt_floatcst (struct expr_builder *, const gdb_byte *);
-
-extern void write_exp_elt_type (struct expr_builder *, struct type *);
-
-extern void write_exp_elt_intern (struct expr_builder *, struct internalvar *);
-
-extern void write_exp_string (struct expr_builder *, struct stoken);
-
-void write_exp_string_vector (struct expr_builder *, int type,
-			      struct stoken_vector *vec);
-
-extern void write_exp_bitstring (struct expr_builder *, struct stoken);
-
-extern void write_exp_elt_block (struct expr_builder *, const struct block *);
-
-extern void write_exp_elt_objfile (struct expr_builder *,
-				   struct objfile *objfile);
-
-extern void write_exp_msymbol (struct expr_builder *,
-			       struct bound_minimal_symbol);
-
-extern void write_dollar_variable (struct parser_state *, struct stoken str);
-
-/* Write a reference to a symbol to the expression being built in PS.
-   NAME is the name of the symbol to write; SYM is the symbol.  If SYM
-   is nullptr, a minimal symbol will be searched for and used if
-   available.  Throws an exception if SYM is nullptr and no minimal
-   symbol can be found.  */
-
-extern void write_exp_symbol_reference (struct parser_state *ps,
-					const char *name,
-					struct symbol *sym);
-
 extern const char *find_template_name_end (const char *);
 
 extern std::string copy_name (struct stoken);
 
-extern int dump_subexp (struct expression *, struct ui_file *, int);
-
-extern int dump_subexp_body_standard (struct expression *, 
-				      struct ui_file *, int);
-
-/* Dump (to STREAM) a function call like expression at position ELT in the
-   expression array EXP.  Return a new value for ELT just after the
-   function call expression.  */
-
-extern int dump_subexp_body_funcall (struct expression *exp,
-				     struct ui_file *stream, int elt);
-
-extern void operator_length (const struct expression *, int, int *, int *);
-
-extern void operator_length_standard (const struct expression *, int, int *,
-				      int *);
-
-extern int operator_check_standard (struct expression *exp, int pos,
-				    int (*objfile_func)
-				      (struct objfile *objfile, void *data),
-				    void *data);
-
 extern bool parse_float (const char *p, int len,
 			 const struct type *type, gdb_byte *data);
 \f
-/* These codes indicate operator precedences for expression printing,
-   least tightly binding first.  */
-/* Adding 1 to a precedence value is done for binary operators,
-   on the operand which is more tightly bound, so that operators
-   of equal precedence within that operand will get parentheses.  */
-/* PREC_HYPER and PREC_ABOVE_COMMA are not the precedence of any operator;
-   they are used as the "surrounding precedence" to force
-   various kinds of things to be parenthesized.  */
-enum precedence
-  {
-    PREC_NULL, PREC_COMMA, PREC_ABOVE_COMMA, PREC_ASSIGN, PREC_LOGICAL_OR,
-    PREC_LOGICAL_AND, PREC_BITWISE_IOR, PREC_BITWISE_AND, PREC_BITWISE_XOR,
-    PREC_EQUAL, PREC_ORDER, PREC_SHIFT, PREC_ADD, PREC_MUL, PREC_REPEAT,
-    PREC_HYPER, PREC_PREFIX, PREC_SUFFIX, PREC_BUILTIN_FUNCTION
-  };
-
-/* Table mapping opcodes into strings for printing operators
-   and precedences of the operators.  */
-
-struct op_print
-  {
-    const char *string;
-    enum exp_opcode opcode;
-    /* Precedence of operator.  These values are used only by comparisons.  */
-    enum precedence precedence;
-
-    /* For a binary operator:  1 iff right associate.
-       For a unary operator:  1 iff postfix.  */
-    int right_assoc;
-  };
-
-/* Information needed to print, prefixify, and evaluate expressions for 
-   a given language.  */
-
-struct exp_descriptor
-  {
-    /* Print subexpression.  */
-    void (*print_subexp) (struct expression *, int *, struct ui_file *,
-			  enum precedence);
-
-    /* Returns number of exp_elements needed to represent an operator and
-       the number of subexpressions it takes.  */
-    void (*operator_length) (const struct expression*, int, int*, int *);
-
-    /* Call OBJFILE_FUNC for any objfile found being referenced by the
-       single operator of EXP at position POS.  Operator parameters are
-       located at positive (POS + number) offsets in EXP.  OBJFILE_FUNC
-       should never be called with NULL OBJFILE.  OBJFILE_FUNC should
-       get passed an arbitrary caller supplied DATA pointer.  If it
-       returns non-zero value then (any other) non-zero value should be
-       immediately returned to the caller.  Otherwise zero should be
-       returned.  */
-    int (*operator_check) (struct expression *exp, int pos,
-			   int (*objfile_func) (struct objfile *objfile,
-						void *data),
-			   void *data);
-
-    /* Dump the rest of this (prefix) expression after the operator
-       itself has been printed.  See dump_subexp_body_standard in
-       (expprint.c).  */
-    int (*dump_subexp_body) (struct expression *, struct ui_file *, int);
-
-    /* Evaluate an expression.  */
-    struct value *(*evaluate_exp) (struct type *, struct expression *,
-				   int *, enum noside);
-  };
-
-
-/* Default descriptor containing standard definitions of all
-   elements.  */
-extern const struct exp_descriptor exp_descriptor_standard;
-
-/* Functions used by language-specific extended operators to (recursively)
-   print/dump subexpressions.  */
-
-extern void print_subexp (struct expression *, int *, struct ui_file *,
-			  enum precedence);
-
-extern void print_subexp_standard (struct expression *, int *, 
-				   struct ui_file *, enum precedence);
-
-/* Print a function call like expression to STREAM.  This is called as a
-   helper function by which point the expression node identifying this as a
-   function call has already been stripped off and POS should point to the
-   number of function call arguments.  EXP is the object containing the
-   list of expression elements.  */
-
-extern void print_subexp_funcall (struct expression *exp, int *pos,
-				  struct ui_file *stream);
 
 /* Function used to avoid direct calls to fprintf
    in the code generated by the bison parser.  */
diff --git a/gdb/ppc-linux-nat.c b/gdb/ppc-linux-nat.c
index 72f0283e4af..f1ba165d540 100644
--- a/gdb/ppc-linux-nat.c
+++ b/gdb/ppc-linux-nat.c
@@ -2488,33 +2488,24 @@ ppc_linux_nat_target::check_condition (CORE_ADDR watch_addr,
 				       struct expression *cond,
 				       CORE_ADDR *data_value, int *len)
 {
-  int pc = 1, num_accesses_left, num_accesses_right;
+  int num_accesses_left, num_accesses_right;
   struct value *left_val, *right_val;
   std::vector<value_ref_ptr> left_chain, right_chain;
 
-  if (cond->first_opcode () != BINOP_EQUAL)
+  expr::equal_operation *eqop
+    = dynamic_cast<expr::equal_operation *> (cond->op.get ());
+  if (eqop == nullptr)
     return 0;
+  expr::operation *lhs = eqop->get_lhs ();
+  expr::operation *rhs = eqop->get_rhs ();
 
-  expr::operation *lhs = nullptr;
-  expr::operation *rhs = nullptr;
-  if (cond->op != nullptr)
-    {
-      expr::equal_operation *eqop
-	= dynamic_cast<expr::equal_operation *> (cond->op.get ());
-      if (eqop != nullptr)
-	{
-	  lhs = eqop->get_lhs ();
-	  rhs = eqop->get_rhs ();
-	}
-    }
-
-  fetch_subexp_value (cond, &pc, lhs, &left_val, NULL, &left_chain, false);
+  fetch_subexp_value (cond, lhs, &left_val, NULL, &left_chain, false);
   num_accesses_left = num_memory_accesses (left_chain);
 
   if (left_val == NULL || num_accesses_left < 0)
     return 0;
 
-  fetch_subexp_value (cond, &pc, rhs, &right_val, NULL, &right_chain, false);
+  fetch_subexp_value (cond, rhs, &right_val, NULL, &right_chain, false);
   num_accesses_right = num_memory_accesses (right_chain);
 
   if (right_val == NULL || num_accesses_right < 0)
diff --git a/gdb/printcmd.c b/gdb/printcmd.c
index 5b399489c70..484a2dbf228 100644
--- a/gdb/printcmd.c
+++ b/gdb/printcmd.c
@@ -1373,14 +1373,8 @@ set_command (const char *exp, int from_tty)
 {
   expression_up expr = parse_expression (exp);
 
-  enum exp_opcode opcode = OP_NULL;
   if (expr->op != nullptr)
-    opcode = expr->op->opcode ();
-  else if (expr->nelts >= 1)
-    opcode = expr->elts[0].opcode;
-
-  if (opcode != OP_NULL)
-    switch (opcode)
+    switch (expr->op->opcode ())
       {
       case UNOP_PREINCREMENT:
       case UNOP_POSTINCREMENT:
diff --git a/gdb/rust-lang.h b/gdb/rust-lang.h
index ec97cac3dae..ea3f974c979 100644
--- a/gdb/rust-lang.h
+++ b/gdb/rust-lang.h
@@ -209,11 +209,6 @@ class rust_language : public language_defn
   bool range_checking_on_by_default () const override
   { return true; }
 
-  /* See language.h.  */
-
-  const struct op_print *opcode_print_table () const override
-  { return c_op_print_tab; }
-
 private:
 
   /* Helper for value_print_inner, arguments are as for that function.
diff --git a/gdb/stap-probe.c b/gdb/stap-probe.c
index 51f04b9e40b..7f09b65f31f 100644
--- a/gdb/stap-probe.c
+++ b/gdb/stap-probe.c
@@ -1416,15 +1416,10 @@ stap_probe::compile_to_ax (struct agent_expr *expr, struct axs_value *value,
 			   unsigned n)
 {
   struct stap_probe_arg *arg;
-  union exp_element *pc;
 
   arg = this->get_arg_by_number (n, expr->gdbarch);
 
-  pc = arg->aexpr->elts;
-  if (arg->aexpr->op != nullptr)
-    arg->aexpr->op->generate_ax (arg->aexpr.get (), expr, value);
-  else
-    gen_expr (arg->aexpr.get (), &pc, expr, value);
+  arg->aexpr->op->generate_ax (arg->aexpr.get (), expr, value);
 
   require_rvalue (expr, value);
   value->type = arg->atype;
diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c
index ec46446c8bf..1530165c350 100644
--- a/gdb/tracepoint.c
+++ b/gdb/tracepoint.c
@@ -691,15 +691,10 @@ validate_actionline (const char *line, struct breakpoint *b)
 	      if (exp->first_opcode () == OP_VAR_VALUE)
 		{
 		  symbol *sym;
-		  if (exp->op != nullptr)
-		    {
-		      expr::var_value_operation *vvop
-			= (dynamic_cast<expr::var_value_operation *>
-			   (exp->op.get ()));
-		      sym = vvop->get_symbol ();
-		    }
-		  else
-		    sym = exp->elts[2].symbol;
+		  expr::var_value_operation *vvop
+		    = (dynamic_cast<expr::var_value_operation *>
+		       (exp->op.get ()));
+		  sym = vvop->get_symbol ();
 
 		  if (SYMBOL_CLASS (sym) == LOC_CONST)
 		    {
@@ -1395,16 +1390,10 @@ encode_actions_1 (struct command_line *action,
 		    {
 		    case OP_REGISTER:
 		      {
-			const char *name;
-			if (exp->op != nullptr)
-			  {
-			    expr::register_operation *regop
-			      = (dynamic_cast<expr::register_operation *>
-				 (exp->op.get ()));
-			    name = regop->get_name ();
-			  }
-			else
-			  name = &exp->elts[2].string;
+			expr::register_operation *regop
+			  = (dynamic_cast<expr::register_operation *>
+			     (exp->op.get ()));
+			const char *name = regop->get_name ();
 
 			i = user_reg_map_name_to_regnum (target_gdbarch (),
 							 name, strlen (name));
@@ -1424,16 +1413,10 @@ encode_actions_1 (struct command_line *action,
 			/* Safe because we know it's a simple expression.  */
 			tempval = evaluate_expression (exp.get ());
 			addr = value_address (tempval);
-			struct type *type;
-			if (exp->op != nullptr)
-			  {
-			    expr::unop_memval_operation *memop
-			      = (dynamic_cast<expr::unop_memval_operation *>
-				 (exp->op.get ()));
-			    type = memop->get_type ();
-			  }
-			else
-			  type = exp->elts[1].type;
+			expr::unop_memval_operation *memop
+			  = (dynamic_cast<expr::unop_memval_operation *>
+			     (exp->op.get ()));
+			struct type *type = memop->get_type ();
 			/* Initialize the TYPE_LENGTH if it is a typedef.  */
 			check_typedef (type);
 			collect->add_memrange (target_gdbarch (),
@@ -1447,17 +1430,10 @@ encode_actions_1 (struct command_line *action,
 
 		    case OP_VAR_VALUE:
 		      {
-			struct symbol *sym;
-
-			if (exp->op != nullptr)
-			  {
-			    expr::var_value_operation *vvo
-			      = (dynamic_cast<expr::var_value_operation *>
-				 (exp->op.get ()));
-			    sym = vvo->get_symbol ();
-			  }
-			else
-			  sym = exp->elts[2].symbol;
+			expr::var_value_operation *vvo
+			  = (dynamic_cast<expr::var_value_operation *>
+			     (exp->op.get ()));
+			struct symbol *sym = vvo->get_symbol ();
 			const char *name = sym->natural_name ();
 
 			collect->collect_symbol (sym,
diff --git a/gdb/value.c b/gdb/value.c
index 806c5449052..7a9128df642 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -1982,29 +1982,19 @@ init_if_undefined_command (const char* args, int from_tty)
   /* Validate the expression.
      Was the expression an assignment?
      Or even an expression at all?  */
-  if ((expr->nelts == 0 && expr->op == nullptr)
-      || expr->first_opcode () != BINOP_ASSIGN)
+  if (expr->op == nullptr || expr->first_opcode () != BINOP_ASSIGN)
     error (_("Init-if-undefined requires an assignment expression."));
 
-  /* Extract the variable from the parsed expression.
-     In the case of an assign the lvalue will be in elts[1] and elts[2].  */
-  if (expr->op == nullptr)
+  /* Extract the variable from the parsed expression.  */
+  expr::assign_operation *assign
+    = dynamic_cast<expr::assign_operation *> (expr->op.get ());
+  if (assign != nullptr)
     {
-      if (expr->elts[1].opcode == OP_INTERNALVAR)
-	intvar = expr->elts[2].internalvar;
-    }
-  else
-    {
-      expr::assign_operation *assign
-	= dynamic_cast<expr::assign_operation *> (expr->op.get ());
-      if (assign != nullptr)
-	{
-	  expr::operation *lhs = assign->get_lhs ();
-	  expr::internalvar_operation *ivarop
-	    = dynamic_cast<expr::internalvar_operation *> (lhs);
-	  if (ivarop != nullptr)
-	    intvar = ivarop->get_internalvar ();
-	}
+      expr::operation *lhs = assign->get_lhs ();
+      expr::internalvar_operation *ivarop
+	= dynamic_cast<expr::internalvar_operation *> (lhs);
+      if (ivarop != nullptr)
+	intvar = ivarop->get_internalvar ();
     }
 
   if (intvar == nullptr)
diff --git a/gdb/value.h b/gdb/value.h
index 7075a08d653..88995cfeafe 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -916,13 +916,6 @@ extern struct value *evaluate_expression (struct expression *exp,
 
 extern struct value *evaluate_type (struct expression *exp);
 
-extern struct value *evaluate_subexp (struct type *expect_type,
-				      struct expression *exp,
-				      int *pos, enum noside noside);
-
-extern struct value *evaluate_subexpression_type (struct expression *exp,
-						  int subexp);
-
 extern value *evaluate_var_value (enum noside noside, const block *blk,
 				  symbol *var);
 
@@ -933,17 +926,12 @@ extern value *evaluate_var_msym_value (enum noside noside,
 extern value *eval_skip_value (expression *exp);
 
 namespace expr { class operation; };
-extern void fetch_subexp_value (struct expression *exp, int *pc,
+extern void fetch_subexp_value (struct expression *exp,
 				expr::operation *op,
 				struct value **valp, struct value **resultp,
 				std::vector<value_ref_ptr> *val_chain,
 				bool preserve_errors);
 
-extern const char *extract_field_op (struct expression *exp, int *subexp);
-
-extern struct value *evaluate_subexp_with_coercion (struct expression *,
-						    int *, enum noside);
-
 extern struct value *parse_and_eval (const char *exp);
 
 extern struct value *parse_to_comma_and_eval (const char **expp);
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 191/203] Remove two Ada opcodes
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (189 preceding siblings ...)
  2021-01-01 21:47 ` [PATCH 190/203] Remove union exp_element Tom Tromey
@ 2021-01-01 21:47 ` Tom Tromey
  2021-01-01 21:47 ` [PATCH 192/203] Remove unused Modula-2 opcodes Tom Tromey
                   ` (12 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:47 UTC (permalink / raw)
  To: gdb-patches

The OP_ATR_MIN and OP_ATR_MAX constants aren't truly needed.
Internally, they are converted to BINOP_MIN and BINOP_MAX.  This patch
removes them in favor of simple reuse.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* std-operator.def (OP_ATR_MIN, OP_ATR_MAX): Remove.
	* ada-lang.c (ada_binop_minmax): Update.
	* ada-exp.h (ada_binop_min_operation, ada_binop_max_operation):
	Use BINOP_MIN and BINOP_MAX.
---
 gdb/ChangeLog        | 7 +++++++
 gdb/ada-exp.h        | 4 ++--
 gdb/ada-lang.c       | 3 +--
 gdb/std-operator.def | 2 --
 4 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/gdb/ada-exp.h b/gdb/ada-exp.h
index 7dfc64e2ec7..b215c58dfb3 100644
--- a/gdb/ada-exp.h
+++ b/gdb/ada-exp.h
@@ -195,8 +195,8 @@ using ada_binop_div_operation = binop_operation<BINOP_DIV, ada_mult_binop>;
 using ada_binop_rem_operation = binop_operation<BINOP_REM, ada_mult_binop>;
 using ada_binop_mod_operation = binop_operation<BINOP_MOD, ada_mult_binop>;
 
-using ada_binop_min_operation = binop_operation<OP_ATR_MIN, ada_binop_minmax>;
-using ada_binop_max_operation = binop_operation<OP_ATR_MAX, ada_binop_minmax>;
+using ada_binop_min_operation = binop_operation<BINOP_MIN, ada_binop_minmax>;
+using ada_binop_max_operation = binop_operation<BINOP_MAX, ada_binop_minmax>;
 
 using ada_binop_exp_operation = binop_operation<BINOP_EXP, ada_binop_exp>;
 
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index e7bfe9967e9..4331a063cb0 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -10265,8 +10265,7 @@ ada_binop_minmax (struct type *expect_type,
   else
     {
       binop_promote (exp->language_defn, exp->gdbarch, &arg1, &arg2);
-      return value_binop (arg1, arg2,
-			  op == OP_ATR_MIN ? BINOP_MIN : BINOP_MAX);
+      return value_binop (arg1, arg2, op);
     }
 }
 
diff --git a/gdb/std-operator.def b/gdb/std-operator.def
index 925e2b6484e..de3d9ec18a9 100644
--- a/gdb/std-operator.def
+++ b/gdb/std-operator.def
@@ -359,8 +359,6 @@ OP (OP_ATR_FIRST)
 OP (OP_ATR_LAST)
 OP (OP_ATR_LENGTH)
 OP (OP_ATR_IMAGE)
-OP (OP_ATR_MAX)
-OP (OP_ATR_MIN)
 OP (OP_ATR_MODULUS)
 OP (OP_ATR_POS)
 OP (OP_ATR_SIZE)
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 192/203] Remove unused Modula-2 opcodes
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (190 preceding siblings ...)
  2021-01-01 21:47 ` [PATCH 191/203] Remove two Ada opcodes Tom Tromey
@ 2021-01-01 21:47 ` Tom Tromey
  2021-01-01 21:47 ` [PATCH 193/203] Remove unused Ada opcodes Tom Tromey
                   ` (11 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:47 UTC (permalink / raw)
  To: gdb-patches

As noted in an earlier patch, Modula-2 defined some opcodes but then
never implemented them.  This patch removes the unnecessary constants.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* std-operator.def (UNOP_CAP, UNOP_CHR, UNOP_ORD, UNOP_FLOAT)
	(UNOP_MAX, UNOP_MIN, UNOP_ODD, UNOP_TRUNC, OP_M2_STRING): Remove.
---
 gdb/ChangeLog        | 5 +++++
 gdb/std-operator.def | 9 ---------
 2 files changed, 5 insertions(+), 9 deletions(-)

diff --git a/gdb/std-operator.def b/gdb/std-operator.def
index de3d9ec18a9..ab94636b83f 100644
--- a/gdb/std-operator.def
+++ b/gdb/std-operator.def
@@ -230,19 +230,10 @@ OP (UNOP_ALIGNOF)		/* Unary alignof (followed by expression) */
 
 OP (UNOP_PLUS)			/* Unary plus */
 
-OP (UNOP_CAP)			/* Modula-2 standard (unary) procedures */
-OP (UNOP_CHR)
-OP (UNOP_ORD)
 OP (UNOP_ABS)
-OP (UNOP_FLOAT)
 OP (UNOP_HIGH)
-OP (UNOP_MAX)
-OP (UNOP_MIN)
-OP (UNOP_ODD)
-OP (UNOP_TRUNC)
 
 OP (OP_BOOL)			/* Modula-2 builtin BOOLEAN type */
-OP (OP_M2_STRING)		/* Modula-2 string constants */
 
 /* STRUCTOP_... operate on a value from a following subexpression
    by extracting a structure component specified by a string
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 193/203] Remove unused Ada opcodes
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (191 preceding siblings ...)
  2021-01-01 21:47 ` [PATCH 192/203] Remove unused Modula-2 opcodes Tom Tromey
@ 2021-01-01 21:47 ` Tom Tromey
  2021-01-01 21:47 ` [PATCH 194/203] Remove OP_EXTENDED0 Tom Tromey
                   ` (10 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:47 UTC (permalink / raw)
  To: gdb-patches

Several Ada expression opcodes are now unused, and can be removed.
Most of these are handled in a different way by the code.
OP_ATR_IMAGE, however, was never implemented.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* std-operator.def (OP_NAME, OP_ATR_IMAGE, OP_ATR_MODULUS)
	(OP_OTHERS, OP_CHOICES, OP_POSITIONAL, OP_DISCRETE_RANGE):
	Remove.
---
 gdb/ChangeLog        |  6 ++++++
 gdb/std-operator.def | 43 -------------------------------------------
 2 files changed, 6 insertions(+), 43 deletions(-)

diff --git a/gdb/std-operator.def b/gdb/std-operator.def
index ab94636b83f..dbd920974da 100644
--- a/gdb/std-operator.def
+++ b/gdb/std-operator.def
@@ -299,9 +299,6 @@ OP (OP_FUNC_STATIC_VAR)
    the GDB "::" operator, or the Modula-2 '.' operator.  */
 OP (OP_TYPE)
 
-/* An un-looked-up identifier.  */
-OP (OP_NAME)
-
 /* An Objective C Foundation Class NSString constant.  */
 OP (OP_OBJC_NSSTRING)
 
@@ -349,8 +346,6 @@ OP (TERNOP_IN_RANGE)
 OP (OP_ATR_FIRST)
 OP (OP_ATR_LAST)
 OP (OP_ATR_LENGTH)
-OP (OP_ATR_IMAGE)
-OP (OP_ATR_MODULUS)
 OP (OP_ATR_POS)
 OP (OP_ATR_SIZE)
 OP (OP_ATR_TAG)
@@ -375,44 +370,6 @@ OP (UNOP_IN_RANGE)
    occur only as the right sides of assignments. */
 OP (OP_AGGREGATE)
 
-/* An others clause.  Followed by a single expression. */
-OP (OP_OTHERS)
-
-/* An aggregate component association.  A single immediate operand, N, 
-   gives the number of choices that follow.  This is followed by a second
-   OP_CHOICES operator.  Next come N operands, each of which is an
-   expression, an OP_DISCRETE_RANGE, or an OP_NAME---the latter 
-   for a simple name that must be a record component name and does 
-   not correspond to a single existing symbol.  After the N choice 
-   indicators comes an expression giving the value.
-
-   In an aggregate such as (X => E1, ...), where X is a simple
-   name, X could syntactically be either a component_selector_name 
-   or an expression used as a discrete_choice, depending on the
-   aggregate's type context.  Since this is not known at parsing
-   time, we don't attempt to disambiguate X if it has multiple
-   definitions, but instead supply an OP_NAME.  If X has a single
-   definition, we represent it with an OP_VAR_VALUE, even though
-   it may turn out to be within a record aggregate.  Aggregate 
-   evaluation can use either OP_NAMEs or OP_VAR_VALUEs to get a
-   record field name, and can evaluate OP_VAR_VALUE normally to
-   get its value as an expression.  Unfortunately, we lose out in
-   cases where X has multiple meanings and is part of an array
-   aggregate.  I hope these are not common enough to annoy users,
-   who can work around the problem in any case by putting
-   parentheses around X. */
-OP (OP_CHOICES)
-
-/* A positional aggregate component association.  The operator is 
-   followed by a single integer indicating the position in the 
-   aggregate (0-based), followed by a second OP_POSITIONAL.  Next 
-   follows a single expression giving the component value.  */
-OP (OP_POSITIONAL)
-
-/* A range of values.  Followed by two expressions giving the
-   upper and lower bounds of the range. */
-OP (OP_DISCRETE_RANGE)
-
 /* ================ Fortran operators ================ */
 
 /* This is EXACTLY like OP_FUNCALL but is semantically different.
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 194/203] Remove OP_EXTENDED0
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (192 preceding siblings ...)
  2021-01-01 21:47 ` [PATCH 193/203] Remove unused Ada opcodes Tom Tromey
@ 2021-01-01 21:47 ` Tom Tromey
  2021-01-01 21:47 ` [PATCH 195/203] Remove OP_UNUSED_LAST Tom Tromey
                   ` (9 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:47 UTC (permalink / raw)
  To: gdb-patches

OP_EXTENDED0 was only used for an assertion in the code to rewrite an
expression into prefix form.  That code is gone, so this patch removes
the constant.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* std-operator.def (OP_EXTENDED0): Remove.
---
 gdb/ChangeLog        | 4 ++++
 gdb/std-operator.def | 4 ----
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/gdb/std-operator.def b/gdb/std-operator.def
index dbd920974da..980f9cd7850 100644
--- a/gdb/std-operator.def
+++ b/gdb/std-operator.def
@@ -326,10 +326,6 @@ OP (OP_TYPEID)
    takes two expression arguments.  */
 OP (OP_RUST_ARRAY)
 
-/* First extension operator.  Some language modules define extra
-   operators below with numbers higher than OP_EXTENDED0.  */
-OP (OP_EXTENDED0)
-
 /* ================ Ada operators ================ */
 
 /* X IN A'RANGE(N).  N is an immediate operand, surrounded by 
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 195/203] Remove OP_UNUSED_LAST
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (193 preceding siblings ...)
  2021-01-01 21:47 ` [PATCH 194/203] Remove OP_EXTENDED0 Tom Tromey
@ 2021-01-01 21:47 ` Tom Tromey
  2021-01-01 21:47 ` [PATCH 196/203] Remove BINOP_END Tom Tromey
                   ` (8 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:47 UTC (permalink / raw)
  To: gdb-patches

OP_UNUSED_LAST is no longer needed with C++ -- the trailing comma is
fine.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* expression.h (enum exp_opcode) <OP_UNUSED_LAST>: Remove.
---
 gdb/ChangeLog    | 4 ++++
 gdb/expression.h | 3 ---
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/gdb/expression.h b/gdb/expression.h
index bca4c6d9fe2..3f0ab4ec38b 100644
--- a/gdb/expression.h
+++ b/gdb/expression.h
@@ -47,9 +47,6 @@ enum exp_opcode : uint8_t
 #include "std-operator.def"
 
 #undef OP
-
-    /* Existing only to swallow the last comma (',') from last .inc file.  */
-    OP_UNUSED_LAST
   };
 
 /* Values of NOSIDE argument to eval_subexp.  */
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 196/203] Remove BINOP_END
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (194 preceding siblings ...)
  2021-01-01 21:47 ` [PATCH 195/203] Remove OP_UNUSED_LAST Tom Tromey
@ 2021-01-01 21:47 ` Tom Tromey
  2021-01-01 21:47 ` [PATCH 197/203] Inline expression constructor Tom Tromey
                   ` (7 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:47 UTC (permalink / raw)
  To: gdb-patches

BINOP_END is used only as a "meaningless" value in various tables.
This patch changes these to use OP_NULL instead, and removes
BINOP_END.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* std-operator.def (BINOP_END): Remove.
	* p-exp.y (tokentab3, tokentab2): Use OP_NULL, not BINOP_END.
	* go-exp.y (tokentab2): Use OP_NULL, not BINOP_END.
	* f-exp.y (dot_ops, f77_keywords): Use OP_NULL, not BINOP_END.
	* d-exp.y (tokentab2, ident_tokens): Use OP_NULL, not BINOP_END.
	* c-exp.y (tokentab3, tokentab2, ident_tokens): Use OP_NULL, not
	BINOP_END.
---
 gdb/ChangeLog        | 10 ++++++++
 gdb/c-exp.y          | 36 +++++++++++++-------------
 gdb/d-exp.y          | 28 ++++++++++-----------
 gdb/f-exp.y          | 60 ++++++++++++++++++++++----------------------
 gdb/go-exp.y         | 26 +++++++++----------
 gdb/p-exp.y          | 30 +++++++++++-----------
 gdb/std-operator.def |  3 ---
 7 files changed, 100 insertions(+), 93 deletions(-)

diff --git a/gdb/c-exp.y b/gdb/c-exp.y
index 37a7f2c9e56..3ce08838080 100644
--- a/gdb/c-exp.y
+++ b/gdb/c-exp.y
@@ -2479,8 +2479,8 @@ static const struct token tokentab3[] =
   {
     {">>=", ASSIGN_MODIFY, BINOP_RSH, 0},
     {"<<=", ASSIGN_MODIFY, BINOP_LSH, 0},
-    {"->*", ARROW_STAR, BINOP_END, FLAG_CXX},
-    {"...", DOTDOTDOT, BINOP_END, 0}
+    {"->*", ARROW_STAR, OP_NULL, FLAG_CXX},
+    {"...", DOTDOTDOT, OP_NULL, 0}
   };
 
 static const struct token tokentab2[] =
@@ -2493,21 +2493,21 @@ static const struct token tokentab2[] =
     {"|=", ASSIGN_MODIFY, BINOP_BITWISE_IOR, 0},
     {"&=", ASSIGN_MODIFY, BINOP_BITWISE_AND, 0},
     {"^=", ASSIGN_MODIFY, BINOP_BITWISE_XOR, 0},
-    {"++", INCREMENT, BINOP_END, 0},
-    {"--", DECREMENT, BINOP_END, 0},
-    {"->", ARROW, BINOP_END, 0},
-    {"&&", ANDAND, BINOP_END, 0},
-    {"||", OROR, BINOP_END, 0},
+    {"++", INCREMENT, OP_NULL, 0},
+    {"--", DECREMENT, OP_NULL, 0},
+    {"->", ARROW, OP_NULL, 0},
+    {"&&", ANDAND, OP_NULL, 0},
+    {"||", OROR, OP_NULL, 0},
     /* "::" is *not* only C++: gdb overrides its meaning in several
        different ways, e.g., 'filename'::func, function::variable.  */
-    {"::", COLONCOLON, BINOP_END, 0},
-    {"<<", LSH, BINOP_END, 0},
-    {">>", RSH, BINOP_END, 0},
-    {"==", EQUAL, BINOP_END, 0},
-    {"!=", NOTEQUAL, BINOP_END, 0},
-    {"<=", LEQ, BINOP_END, 0},
-    {">=", GEQ, BINOP_END, 0},
-    {".*", DOT_STAR, BINOP_END, FLAG_CXX}
+    {"::", COLONCOLON, OP_NULL, 0},
+    {"<<", LSH, OP_NULL, 0},
+    {">>", RSH, OP_NULL, 0},
+    {"==", EQUAL, OP_NULL, 0},
+    {"!=", NOTEQUAL, OP_NULL, 0},
+    {"<=", LEQ, OP_NULL, 0},
+    {">=", GEQ, OP_NULL, 0},
+    {".*", DOT_STAR, OP_NULL, FLAG_CXX}
   };
 
 /* Identifier-like tokens.  Only type-specifiers than can appear in
@@ -2546,14 +2546,14 @@ static const struct token ident_tokens[] =
     {"delete", DELETE, OP_NULL, FLAG_CXX},
     {"operator", OPERATOR, OP_NULL, FLAG_CXX},
 
-    {"and", ANDAND, BINOP_END, FLAG_CXX},
+    {"and", ANDAND, OP_NULL, FLAG_CXX},
     {"and_eq", ASSIGN_MODIFY, BINOP_BITWISE_AND, FLAG_CXX},
     {"bitand", '&', OP_NULL, FLAG_CXX},
     {"bitor", '|', OP_NULL, FLAG_CXX},
     {"compl", '~', OP_NULL, FLAG_CXX},
     {"not", '!', OP_NULL, FLAG_CXX},
-    {"not_eq", NOTEQUAL, BINOP_END, FLAG_CXX},
-    {"or", OROR, BINOP_END, FLAG_CXX},
+    {"not_eq", NOTEQUAL, OP_NULL, FLAG_CXX},
+    {"or", OROR, OP_NULL, FLAG_CXX},
     {"or_eq", ASSIGN_MODIFY, BINOP_BITWISE_IOR, FLAG_CXX},
     {"xor", '^', OP_NULL, FLAG_CXX},
     {"xor_eq", ASSIGN_MODIFY, BINOP_BITWISE_XOR, FLAG_CXX},
diff --git a/gdb/d-exp.y b/gdb/d-exp.y
index 61ddb983d64..d79eaf14a8f 100644
--- a/gdb/d-exp.y
+++ b/gdb/d-exp.y
@@ -965,25 +965,25 @@ static const struct token tokentab2[] =
     {"|=", ASSIGN_MODIFY, BINOP_BITWISE_IOR},
     {"&=", ASSIGN_MODIFY, BINOP_BITWISE_AND},
     {"^=", ASSIGN_MODIFY, BINOP_BITWISE_XOR},
-    {"++", INCREMENT, BINOP_END},
-    {"--", DECREMENT, BINOP_END},
-    {"&&", ANDAND, BINOP_END},
-    {"||", OROR, BINOP_END},
-    {"^^", HATHAT, BINOP_END},
-    {"<<", LSH, BINOP_END},
-    {">>", RSH, BINOP_END},
-    {"==", EQUAL, BINOP_END},
-    {"!=", NOTEQUAL, BINOP_END},
-    {"<=", LEQ, BINOP_END},
-    {">=", GEQ, BINOP_END},
-    {"..", DOTDOT, BINOP_END},
+    {"++", INCREMENT, OP_NULL},
+    {"--", DECREMENT, OP_NULL},
+    {"&&", ANDAND, OP_NULL},
+    {"||", OROR, OP_NULL},
+    {"^^", HATHAT, OP_NULL},
+    {"<<", LSH, OP_NULL},
+    {">>", RSH, OP_NULL},
+    {"==", EQUAL, OP_NULL},
+    {"!=", NOTEQUAL, OP_NULL},
+    {"<=", LEQ, OP_NULL},
+    {">=", GEQ, OP_NULL},
+    {"..", DOTDOT, OP_NULL},
   };
 
 /* Identifier-like tokens.  */
 static const struct token ident_tokens[] =
   {
-    {"is", IDENTITY, BINOP_END},
-    {"!is", NOTIDENTITY, BINOP_END},
+    {"is", IDENTITY, OP_NULL},
+    {"!is", NOTIDENTITY, OP_NULL},
 
     {"cast", CAST_KEYWORD, OP_NULL},
     {"const", CONST_KEYWORD, OP_NULL},
diff --git a/gdb/f-exp.y b/gdb/f-exp.y
index 3aee19facce..29575f90a3a 100644
--- a/gdb/f-exp.y
+++ b/gdb/f-exp.y
@@ -1019,17 +1019,17 @@ struct token
 
 static const struct token dot_ops[] =
 {
-  { ".and.", BOOL_AND, BINOP_END, false },
-  { ".or.", BOOL_OR, BINOP_END, false },
-  { ".not.", BOOL_NOT, BINOP_END, false },
-  { ".eq.", EQUAL, BINOP_END, false },
-  { ".eqv.", EQUAL, BINOP_END, false },
-  { ".neqv.", NOTEQUAL, BINOP_END, false },
-  { ".ne.", NOTEQUAL, BINOP_END, false },
-  { ".le.", LEQ, BINOP_END, false },
-  { ".ge.", GEQ, BINOP_END, false },
-  { ".gt.", GREATERTHAN, BINOP_END, false },
-  { ".lt.", LESSTHAN, BINOP_END, false },
+  { ".and.", BOOL_AND, OP_NULL, false },
+  { ".or.", BOOL_OR, OP_NULL, false },
+  { ".not.", BOOL_NOT, OP_NULL, false },
+  { ".eq.", EQUAL, OP_NULL, false },
+  { ".eqv.", EQUAL, OP_NULL, false },
+  { ".neqv.", NOTEQUAL, OP_NULL, false },
+  { ".ne.", NOTEQUAL, OP_NULL, false },
+  { ".le.", LEQ, OP_NULL, false },
+  { ".ge.", GEQ, OP_NULL, false },
+  { ".gt.", GREATERTHAN, OP_NULL, false },
+  { ".lt.", LESSTHAN, OP_NULL, false },
 };
 
 /* Holds the Fortran representation of a boolean, and the integer value we
@@ -1053,27 +1053,27 @@ static const struct f77_boolean_val boolean_values[]  =
 static const struct token f77_keywords[] =
 {
   /* Historically these have always been lowercase only in GDB.  */
-  { "complex_16", COMPLEX_S16_KEYWORD, BINOP_END, true },
-  { "complex_32", COMPLEX_S32_KEYWORD, BINOP_END, true },
-  { "character", CHARACTER, BINOP_END, true },
-  { "integer_2", INT_S2_KEYWORD, BINOP_END, true },
-  { "logical_1", LOGICAL_S1_KEYWORD, BINOP_END, true },
-  { "logical_2", LOGICAL_S2_KEYWORD, BINOP_END, true },
-  { "logical_8", LOGICAL_S8_KEYWORD, BINOP_END, true },
-  { "complex_8", COMPLEX_S8_KEYWORD, BINOP_END, true },
-  { "integer", INT_KEYWORD, BINOP_END, true },
-  { "logical", LOGICAL_KEYWORD, BINOP_END, true },
-  { "real_16", REAL_S16_KEYWORD, BINOP_END, true },
-  { "complex", COMPLEX_KEYWORD, BINOP_END, true },
-  { "sizeof", SIZEOF, BINOP_END, true },
-  { "real_8", REAL_S8_KEYWORD, BINOP_END, true },
-  { "real", REAL_KEYWORD, BINOP_END, true },
-  { "single", SINGLE, BINOP_END, true },
-  { "double", DOUBLE, BINOP_END, true },
-  { "precision", PRECISION, BINOP_END, true },
+  { "complex_16", COMPLEX_S16_KEYWORD, OP_NULL, true },
+  { "complex_32", COMPLEX_S32_KEYWORD, OP_NULL, true },
+  { "character", CHARACTER, OP_NULL, true },
+  { "integer_2", INT_S2_KEYWORD, OP_NULL, true },
+  { "logical_1", LOGICAL_S1_KEYWORD, OP_NULL, true },
+  { "logical_2", LOGICAL_S2_KEYWORD, OP_NULL, true },
+  { "logical_8", LOGICAL_S8_KEYWORD, OP_NULL, true },
+  { "complex_8", COMPLEX_S8_KEYWORD, OP_NULL, true },
+  { "integer", INT_KEYWORD, OP_NULL, true },
+  { "logical", LOGICAL_KEYWORD, OP_NULL, true },
+  { "real_16", REAL_S16_KEYWORD, OP_NULL, true },
+  { "complex", COMPLEX_KEYWORD, OP_NULL, true },
+  { "sizeof", SIZEOF, OP_NULL, true },
+  { "real_8", REAL_S8_KEYWORD, OP_NULL, true },
+  { "real", REAL_KEYWORD, OP_NULL, true },
+  { "single", SINGLE, OP_NULL, true },
+  { "double", DOUBLE, OP_NULL, true },
+  { "precision", PRECISION, OP_NULL, true },
   /* The following correspond to actual functions in Fortran and are case
      insensitive.  */
-  { "kind", KIND, BINOP_END, false },
+  { "kind", KIND, OP_NULL, false },
   { "abs", UNOP_INTRINSIC, UNOP_ABS, false },
   { "mod", BINOP_INTRINSIC, BINOP_MOD, false },
   { "floor", UNOP_INTRINSIC, UNOP_FORTRAN_FLOOR, false },
diff --git a/gdb/go-exp.y b/gdb/go-exp.y
index 6e070a7f4ff..d096cc8b7c9 100644
--- a/gdb/go-exp.y
+++ b/gdb/go-exp.y
@@ -966,19 +966,19 @@ static const struct token tokentab2[] =
     {"|=", ASSIGN_MODIFY, BINOP_BITWISE_IOR},
     {"&=", ASSIGN_MODIFY, BINOP_BITWISE_AND},
     {"^=", ASSIGN_MODIFY, BINOP_BITWISE_XOR},
-    {"++", INCREMENT, BINOP_END},
-    {"--", DECREMENT, BINOP_END},
-    /*{"->", RIGHT_ARROW, BINOP_END}, Doesn't exist in Go.  */
-    {"<-", LEFT_ARROW, BINOP_END},
-    {"&&", ANDAND, BINOP_END},
-    {"||", OROR, BINOP_END},
-    {"<<", LSH, BINOP_END},
-    {">>", RSH, BINOP_END},
-    {"==", EQUAL, BINOP_END},
-    {"!=", NOTEQUAL, BINOP_END},
-    {"<=", LEQ, BINOP_END},
-    {">=", GEQ, BINOP_END},
-    /*{"&^", ANDNOT, BINOP_END}, TODO */
+    {"++", INCREMENT, OP_NULL},
+    {"--", DECREMENT, OP_NULL},
+    /*{"->", RIGHT_ARROW, OP_NULL}, Doesn't exist in Go.  */
+    {"<-", LEFT_ARROW, OP_NULL},
+    {"&&", ANDAND, OP_NULL},
+    {"||", OROR, OP_NULL},
+    {"<<", LSH, OP_NULL},
+    {">>", RSH, OP_NULL},
+    {"==", EQUAL, OP_NULL},
+    {"!=", NOTEQUAL, OP_NULL},
+    {"<=", LEQ, OP_NULL},
+    {">=", GEQ, OP_NULL},
+    /*{"&^", ANDNOT, OP_NULL}, TODO */
   };
 
 /* Identifier-like tokens.  */
diff --git a/gdb/p-exp.y b/gdb/p-exp.y
index 87fabc2ec11..4ac2f1f268d 100644
--- a/gdb/p-exp.y
+++ b/gdb/p-exp.y
@@ -1050,25 +1050,25 @@ struct token
 
 static const struct token tokentab3[] =
   {
-    {"shr", RSH, BINOP_END},
-    {"shl", LSH, BINOP_END},
-    {"and", ANDAND, BINOP_END},
-    {"div", DIV, BINOP_END},
-    {"not", NOT, BINOP_END},
-    {"mod", MOD, BINOP_END},
-    {"inc", INCREMENT, BINOP_END},
-    {"dec", DECREMENT, BINOP_END},
-    {"xor", XOR, BINOP_END}
+    {"shr", RSH, OP_NULL},
+    {"shl", LSH, OP_NULL},
+    {"and", ANDAND, OP_NULL},
+    {"div", DIV, OP_NULL},
+    {"not", NOT, OP_NULL},
+    {"mod", MOD, OP_NULL},
+    {"inc", INCREMENT, OP_NULL},
+    {"dec", DECREMENT, OP_NULL},
+    {"xor", XOR, OP_NULL}
   };
 
 static const struct token tokentab2[] =
   {
-    {"or", OR, BINOP_END},
-    {"<>", NOTEQUAL, BINOP_END},
-    {"<=", LEQ, BINOP_END},
-    {">=", GEQ, BINOP_END},
-    {":=", ASSIGN, BINOP_END},
-    {"::", COLONCOLON, BINOP_END} };
+    {"or", OR, OP_NULL},
+    {"<>", NOTEQUAL, OP_NULL},
+    {"<=", LEQ, OP_NULL},
+    {">=", GEQ, OP_NULL},
+    {":=", ASSIGN, OP_NULL},
+    {"::", COLONCOLON, OP_NULL} };
 
 /* Allocate uppercased var: */
 /* make an uppercased copy of tokstart.  */
diff --git a/gdb/std-operator.def b/gdb/std-operator.def
index 980f9cd7850..c60d60b976f 100644
--- a/gdb/std-operator.def
+++ b/gdb/std-operator.def
@@ -87,9 +87,6 @@ OP (BINOP_VAL)
    the second operand with itself that many times.  */
 OP (BINOP_CONCAT)
 
-/* This must be the highest BINOP_ value, for expprint.c.  */
-OP (BINOP_END)
-
 /* Operates on three values computed by following subexpressions.  */
 OP (TERNOP_COND)		/* ?: */
 
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 197/203] Inline expression constructor
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (195 preceding siblings ...)
  2021-01-01 21:47 ` [PATCH 196/203] Remove BINOP_END Tom Tromey
@ 2021-01-01 21:47 ` Tom Tromey
  2021-01-01 21:47 ` [PATCH 198/203] Inline expr_builder methods Tom Tromey
                   ` (6 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:47 UTC (permalink / raw)
  To: gdb-patches

The struct expression constructor no longer does any real work, so
this inlines it.  The default destructor can also be used now as well.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* parse.c (expression::expression, expression::~expression):
	Remove.
	* expression.h (struct expression): Inline constructor.  Remove
	destructor.
---
 gdb/ChangeLog    |  7 +++++++
 gdb/expression.h |  8 ++++++--
 gdb/parse.c      | 10 ----------
 3 files changed, 13 insertions(+), 12 deletions(-)

diff --git a/gdb/expression.h b/gdb/expression.h
index 3f0ab4ec38b..83bfe753d84 100644
--- a/gdb/expression.h
+++ b/gdb/expression.h
@@ -181,8 +181,12 @@ make_operation (Arg... args)
 
 struct expression
 {
-  expression (const struct language_defn *, struct gdbarch *);
-  ~expression ();
+  expression (const struct language_defn *lang, struct gdbarch *arch)
+    : language_defn (lang),
+      gdbarch (arch)
+  {
+  }
+
   DISABLE_COPY_AND_ASSIGN (expression);
 
   /* Return the opcode for the outermost sub-expression of this
diff --git a/gdb/parse.c b/gdb/parse.c
index 637a9f3d246..0c4a2c6fa01 100644
--- a/gdb/parse.c
+++ b/gdb/parse.c
@@ -105,16 +105,6 @@ expr_builder::release ()
   return std::move (expout);
 }
 
-expression::expression (const struct language_defn *lang, struct gdbarch *arch)
-  : language_defn (lang),
-    gdbarch (arch)
-{
-}
-
-expression::~expression ()
-{
-}
-
 /* Return the type of MSYMBOL, a minimal symbol of OBJFILE.  If
    ADDRESS_P is not NULL, set it to the MSYMBOL's resolved
    address.  */
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 198/203] Inline expr_builder methods
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (196 preceding siblings ...)
  2021-01-01 21:47 ` [PATCH 197/203] Inline expression constructor Tom Tromey
@ 2021-01-01 21:47 ` Tom Tromey
  2021-01-01 21:47 ` [PATCH 199/203] Merge namespace scopes in eval.c Tom Tromey
                   ` (5 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:47 UTC (permalink / raw)
  To: gdb-patches

This inlines the expr_builder constructor and release method.  These
are straightforward, so this seemed simpler.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* parser-defs.h (struct expr_builder) <expr_builder>: Inline.
	<release>: Inline.
	* parse.c (expr_builder::expr_builder, expr_builder::release):
	Remove.
---
 gdb/ChangeLog     |  7 +++++++
 gdb/parse.c       | 14 --------------
 gdb/parser-defs.h | 10 ++++++++--
 3 files changed, 15 insertions(+), 16 deletions(-)

diff --git a/gdb/parse.c b/gdb/parse.c
index 0c4a2c6fa01..8cdaa83b60b 100644
--- a/gdb/parse.c
+++ b/gdb/parse.c
@@ -91,20 +91,6 @@ innermost_block_tracker::update (const struct block *b,
 
 \f
 
-/* See definition in parser-defs.h.  */
-
-expr_builder::expr_builder (const struct language_defn *lang,
-			    struct gdbarch *gdbarch)
-  : expout (new expression (lang, gdbarch))
-{
-}
-
-expression_up
-expr_builder::release ()
-{
-  return std::move (expout);
-}
-
 /* Return the type of MSYMBOL, a minimal symbol of OBJFILE.  If
    ADDRESS_P is not NULL, set it to the MSYMBOL's resolved
    address.  */
diff --git a/gdb/parser-defs.h b/gdb/parser-defs.h
index b6cf4a694c7..31be5e80bd9 100644
--- a/gdb/parser-defs.h
+++ b/gdb/parser-defs.h
@@ -42,13 +42,19 @@ struct expr_builder
      And GDBARCH is the gdbarch to use during parsing.  */
 
   expr_builder (const struct language_defn *lang,
-		struct gdbarch *gdbarch);
+		struct gdbarch *gdbarch)
+    : expout (new expression (lang, gdbarch))
+  {
+  }
 
   DISABLE_COPY_AND_ASSIGN (expr_builder);
 
   /* Resize the allocated expression to the correct size, and return
      it as an expression_up -- passing ownership to the caller.  */
-  ATTRIBUTE_UNUSED_RESULT expression_up release ();
+  ATTRIBUTE_UNUSED_RESULT expression_up release ()
+  {
+    return std::move (expout);
+  }
 
   /* Return the gdbarch that was passed to the constructor.  */
 
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 199/203] Merge namespace scopes in eval.c
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (197 preceding siblings ...)
  2021-01-01 21:47 ` [PATCH 198/203] Inline expr_builder methods Tom Tromey
@ 2021-01-01 21:47 ` Tom Tromey
  2021-01-01 21:47 ` [PATCH 200/203] Remove EVAL_SKIP Tom Tromey
                   ` (4 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:47 UTC (permalink / raw)
  To: gdb-patches

The big deletion patch left some identical namespace scopes sitting
next to one another.  This patch removes the redundant "namespace
expr"s.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* eval.c: Merge "namespace" scopes.
---
 gdb/ChangeLog |  4 ++++
 gdb/eval.c    | 10 ----------
 2 files changed, 4 insertions(+), 10 deletions(-)

diff --git a/gdb/eval.c b/gdb/eval.c
index 1f87748e80b..4d467cd436d 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -2618,11 +2618,6 @@ unop_memval_type_operation::evaluate_for_address (struct expression *exp,
 		     std::get<1> (m_storage)->evaluate (nullptr, exp, noside));
 }
 
-}
-
-namespace expr
-{
-
 value *
 var_value_operation::evaluate_for_address (struct expression *exp,
 					   enum noside noside)
@@ -2803,11 +2798,6 @@ var_value_operation::evaluate_for_sizeof (struct expression *exp,
   return evaluate_subexp_for_sizeof_base (exp, type);
 }
 
-}
-
-namespace expr
-{
-
 value *
 var_msym_value_operation::evaluate_for_cast (struct type *to_type,
 					     struct expression *exp,
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 200/203] Remove EVAL_SKIP
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (198 preceding siblings ...)
  2021-01-01 21:47 ` [PATCH 199/203] Merge namespace scopes in eval.c Tom Tromey
@ 2021-01-01 21:47 ` Tom Tromey
  2021-01-01 21:47 ` [PATCH 201/203] Change exp_uses_objfile to return bool Tom Tromey
                   ` (3 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:47 UTC (permalink / raw)
  To: gdb-patches

EVAL_SKIP was needed in the old expression implementation due to its
linearized tree structure.  This is not needed in the new
implementation, because it is trivial to not evaluate a subexpression.
This patch removes the last vestiges of EVAL_SKIP.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* value.h (eval_skip_value): Don't declare.
	* opencl-lang.c (eval_opencl_assign): Update.
	* m2-lang.c (eval_op_m2_high, eval_op_m2_subscript): Update.
	* f-lang.c (eval_op_f_abs, eval_op_f_mod, eval_op_f_ceil)
	(eval_op_f_floor, eval_op_f_modulo, eval_op_f_cmplx): Remove.
	* expression.h (enum noside) <EVAL_SKIP>: Remove.
	* expop.h (typeof_operation::evaluate)
	(decltype_operation::evaluate, unop_addr_operation::evaluate)
	(unop_sizeof_operation::evaluate, assign_operation::evaluate)
	(cxx_cast_operation::evaluate): Update.
	* eval.c (eval_skip_value): Remove.
	(eval_op_scope, eval_op_var_entry_value)
	(eval_op_func_static_var, eval_op_string, eval_op_objc_selector)
	(eval_op_concat, eval_op_ternop, eval_op_structop_struct)
	(eval_op_structop_ptr, eval_op_member, eval_op_add, eval_op_sub)
	(eval_op_binary, eval_op_subscript, eval_op_equal)
	(eval_op_notequal, eval_op_less, eval_op_gtr, eval_op_geq)
	(eval_op_leq, eval_op_repeat, eval_op_plus, eval_op_neg)
	(eval_op_complement, eval_op_lognot, eval_op_ind)
	(eval_op_memval, eval_op_preinc, eval_op_predec)
	(eval_op_postinc, eval_op_postdec, eval_op_type)
	(eval_binop_assign_modify, eval_op_objc_msgcall)
	(eval_multi_subscript, logical_and_operation::evaluate)
	(logical_or_operation::evaluate, array_operation::evaluate)
	(operation::evaluate_for_cast)
	(var_msym_value_operation::evaluate_for_cast)
	(var_value_operation::evaluate_for_cast): Update.
	* c-lang.c (c_string_operation::evaluate): Update.
	* c-exp.h (objc_nsstring_operation::evaluate)
	(objc_selector_operation::evaluate): Update.
	* ada-lang.c (ada_assign_operation::evaluate)
	(eval_ternop_in_range, ada_unop_neg, ada_unop_in_range)
	(ada_atr_size): Update.
---
 gdb/ChangeLog     |  36 ++++++++++++++++
 gdb/ada-lang.c    |  16 ++-----
 gdb/c-exp.h       |   4 --
 gdb/c-lang.c      |  21 ++--------
 gdb/eval.c        | 103 ++++------------------------------------------
 gdb/expop.h       |  19 ++-------
 gdb/expression.h  |   3 --
 gdb/f-lang.c      |  12 ------
 gdb/m2-lang.c     |   4 +-
 gdb/opencl-lang.c |   2 +-
 gdb/value.h       |   2 -
 11 files changed, 57 insertions(+), 165 deletions(-)

diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 4331a063cb0..4ab9172cc81 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -9509,7 +9509,7 @@ ada_assign_operation::evaluate (struct type *expect_type,
   if (VALUE_LVAL (arg1) == lval_internalvar)
     type = NULL;
   value *arg2 = std::get<1> (m_storage)->evaluate (type, exp, noside);
-  if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS)
+  if (noside == EVAL_AVOID_SIDE_EFFECTS)
     return arg1;
   if (VALUE_LVAL (arg1) == lval_internalvar)
     {
@@ -9843,9 +9843,6 @@ eval_ternop_in_range (struct type *expect_type, struct expression *exp,
 		      enum noside noside,
 		      value *arg1, value *arg2, value *arg3)
 {
-  if (noside == EVAL_SKIP)
-    return eval_skip_value (exp);
-
   binop_promote (exp->language_defn, exp->gdbarch, &arg1, &arg2);
   binop_promote (exp->language_defn, exp->gdbarch, &arg1, &arg3);
   struct type *type = language_bool_type (exp->language_defn, exp->gdbarch);
@@ -9865,9 +9862,7 @@ ada_unop_neg (struct type *expect_type,
 	      enum noside noside, enum exp_opcode op,
 	      struct value *arg1)
 {
-  if (noside == EVAL_SKIP)
-    return eval_skip_value (exp);
-  else if (ada_is_gnat_encoded_fixed_point_type (value_type (arg1)))
+  if (ada_is_gnat_encoded_fixed_point_type (value_type (arg1)))
     return value_cast (value_type (arg1), value_neg (arg1));
   else
     {
@@ -9884,9 +9879,6 @@ ada_unop_in_range (struct type *expect_type,
 		   enum noside noside, enum exp_opcode op,
 		   struct value *arg1, struct type *type)
 {
-  if (noside == EVAL_SKIP)
-    return eval_skip_value (exp);
-
   struct value *arg2, *arg3;
   switch (type->code ())
     {
@@ -9943,9 +9935,7 @@ ada_atr_size (struct type *expect_type,
   if (type->code () == TYPE_CODE_REF)
     type = TYPE_TARGET_TYPE (type);
 
-  if (noside == EVAL_SKIP)
-    return eval_skip_value (exp);
-  else if (noside == EVAL_AVOID_SIDE_EFFECTS)
+  if (noside == EVAL_AVOID_SIDE_EFFECTS)
     return value_zero (builtin_type (exp->gdbarch)->builtin_int, not_lval);
   else
     return value_from_longest (builtin_type (exp->gdbarch)->builtin_int,
diff --git a/gdb/c-exp.h b/gdb/c-exp.h
index 0ce2bd6eb22..1a69b1c7960 100644
--- a/gdb/c-exp.h
+++ b/gdb/c-exp.h
@@ -74,8 +74,6 @@ class objc_nsstring_operation
 		   struct expression *exp,
 		   enum noside noside) override
   {
-    if (noside == EVAL_SKIP)
-      return eval_skip_value (exp);
     const std::string &str = std::get<0> (m_storage);
     return value_nsstring (exp->gdbarch, str.c_str (), str.size () + 1);
   }
@@ -95,8 +93,6 @@ class objc_selector_operation
 		   struct expression *exp,
 		   enum noside noside) override
   {
-    if (noside == EVAL_SKIP)
-      return eval_skip_value (exp);
     return eval_op_objc_selector (expect_type, exp, noside,
 				  std::get<0> (m_storage).c_str ());
   }
diff --git a/gdb/c-lang.c b/gdb/c-lang.c
index 5dd27329726..36fc4fcad5c 100644
--- a/gdb/c-lang.c
+++ b/gdb/c-lang.c
@@ -638,24 +638,9 @@ c_string_operation::evaluate (struct type *expect_type,
 
   dest_charset = charset_for_string_type (dest_type, exp->gdbarch);
 
-  if (noside != EVAL_SKIP)
-    {
-      for (const std::string &item : std::get<1> (m_storage))
-	parse_one_string (&output, item.c_str (), item.size (),
-			  dest_charset, type);
-    }
-
-  if (noside == EVAL_SKIP)
-    {
-      /* Return a dummy value of the appropriate type.  */
-      if (expect_type != NULL)
-	result = allocate_value (expect_type);
-      else if ((dest_type & C_CHAR) != 0)
-	result = allocate_value (type);
-      else
-	result = value_cstring ("", 0, type);
-      return result;
-    }
+  for (const std::string &item : std::get<1> (m_storage))
+    parse_one_string (&output, item.c_str (), item.size (),
+		      dest_charset, type);
 
   if ((dest_type & C_CHAR) != 0)
     {
diff --git a/gdb/eval.c b/gdb/eval.c
index 4d467cd436d..49e53f930b9 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -603,14 +603,6 @@ evaluate_var_msym_value (enum noside noside,
     return value_at_lazy (the_type, address);
 }
 
-/* Helper for returning a value when handling EVAL_SKIP.  */
-
-value *
-eval_skip_value (expression *exp)
-{
-  return value_from_longest (builtin_type (exp->gdbarch)->builtin_int, 1);
-}
-
 /* See expression.h.  */
 
 value *
@@ -984,8 +976,6 @@ eval_op_scope (struct type *expect_type, struct expression *exp,
 	       enum noside noside,
 	       struct type *type, const char *string)
 {
-  if (noside == EVAL_SKIP)
-    return eval_skip_value (exp);
   struct value *arg1 = value_aggregate_elt (type, string, expect_type,
 					    0, noside);
   if (arg1 == NULL)
@@ -999,8 +989,6 @@ struct value *
 eval_op_var_entry_value (struct type *expect_type, struct expression *exp,
 			 enum noside noside, symbol *sym)
 {
-  if (noside == EVAL_SKIP)
-    return eval_skip_value (exp);
   if (noside == EVAL_AVOID_SIDE_EFFECTS)
     return value_zero (SYMBOL_TYPE (sym), not_lval);
 
@@ -1032,8 +1020,6 @@ eval_op_func_static_var (struct type *expect_type, struct expression *exp,
 			 enum noside noside,
 			 value *func, const char *var)
 {
-  if (noside == EVAL_SKIP)
-    return eval_skip_value (exp);
   CORE_ADDR addr = value_address (func);
   const block *blk = block_for_pc (addr);
   struct block_symbol sym = lookup_symbol (var, blk, VAR_DOMAIN, NULL);
@@ -1074,8 +1060,6 @@ struct value *
 eval_op_string (struct type *expect_type, struct expression *exp,
 		enum noside noside, int len, const char *string)
 {
-  if (noside == EVAL_SKIP)
-    return eval_skip_value (exp);
   struct type *type = language_string_char_type (exp->language_defn,
 						 exp->gdbarch);
   return value_string (string, len, type);
@@ -1086,9 +1070,6 @@ eval_op_objc_selector (struct type *expect_type, struct expression *exp,
 		       enum noside noside,
 		       const char *sel)
 {
-  if (noside == EVAL_SKIP)
-    return eval_skip_value (exp);
-
   struct type *selector_type = builtin_type (exp->gdbarch)->builtin_data_ptr;
   return value_from_longest (selector_type,
 			     lookup_child_selector (exp->gdbarch, sel));
@@ -1098,8 +1079,6 @@ struct value *
 eval_op_concat (struct type *expect_type, struct expression *exp,
 		enum noside noside, struct value *arg1, struct value *arg2)
 {
-  if (noside == EVAL_SKIP)
-    return eval_skip_value (exp);
   if (binop_user_defined_p (BINOP_CONCAT, arg1, arg2))
     return value_x_binop (arg1, arg2, BINOP_CONCAT, OP_NULL, noside);
   else
@@ -1113,8 +1092,6 @@ eval_op_ternop (struct type *expect_type, struct expression *exp,
 		enum noside noside,
 		struct value *array, struct value *low, struct value *upper)
 {
-  if (noside == EVAL_SKIP)
-    return eval_skip_value (exp);
   int lowbound = value_as_long (low);
   int upperbound = value_as_long (upper);
   return value_slice (array, lowbound, upperbound - lowbound + 1);
@@ -1127,8 +1104,6 @@ eval_op_structop_struct (struct type *expect_type, struct expression *exp,
 			 enum noside noside,
 			 struct value *arg1, const char *string)
 {
-  if (noside == EVAL_SKIP)
-    return eval_skip_value (exp);
   struct value *arg3 = value_struct_elt (&arg1, NULL, string,
 					 NULL, "structure");
   if (noside == EVAL_AVOID_SIDE_EFFECTS)
@@ -1143,9 +1118,6 @@ eval_op_structop_ptr (struct type *expect_type, struct expression *exp,
 		      enum noside noside,
 		      struct value *arg1, const char *string)
 {
-  if (noside == EVAL_SKIP)
-    return eval_skip_value (exp);
-
   /* Check to see if operator '->' has been overloaded.  If so replace
      arg1 with the value returned by evaluating operator->().  */
   while (unop_user_defined_p (STRUCTOP_PTR, arg1))
@@ -1204,9 +1176,6 @@ eval_op_member (struct type *expect_type, struct expression *exp,
 {
   long mem_offset;
 
-  if (noside == EVAL_SKIP)
-    return eval_skip_value (exp);
-
   struct value *arg3;
   struct type *type = check_typedef (value_type (arg2));
   switch (type->code ())
@@ -1245,8 +1214,6 @@ eval_op_add (struct type *expect_type, struct expression *exp,
 	     enum noside noside,
 	     struct value *arg1, struct value *arg2)
 {
-  if (noside == EVAL_SKIP)
-    return eval_skip_value (exp);
   if (binop_user_defined_p (BINOP_ADD, arg1, arg2))
     return value_x_binop (arg1, arg2, BINOP_ADD, OP_NULL, noside);
   else if (ptrmath_type_p (exp->language_defn, value_type (arg1))
@@ -1269,8 +1236,6 @@ eval_op_sub (struct type *expect_type, struct expression *exp,
 	     enum noside noside,
 	     struct value *arg1, struct value *arg2)
 {
-  if (noside == EVAL_SKIP)
-    return eval_skip_value (exp);
   if (binop_user_defined_p (BINOP_SUB, arg1, arg2))
     return value_x_binop (arg1, arg2, BINOP_SUB, OP_NULL, noside);
   else if (ptrmath_type_p (exp->language_defn, value_type (arg1))
@@ -1297,8 +1262,6 @@ eval_op_binary (struct type *expect_type, struct expression *exp,
 		enum noside noside, enum exp_opcode op,
 		struct value *arg1, struct value *arg2)
 {
-  if (noside == EVAL_SKIP)
-    return eval_skip_value (exp);
   if (binop_user_defined_p (op, arg1, arg2))
     return value_x_binop (arg1, arg2, op, OP_NULL, noside);
   else
@@ -1344,8 +1307,6 @@ eval_op_subscript (struct type *expect_type, struct expression *exp,
 		   enum noside noside, enum exp_opcode op,
 		   struct value *arg1, struct value *arg2)
 {
-  if (noside == EVAL_SKIP)
-    return eval_skip_value (exp);
   if (binop_user_defined_p (op, arg1, arg2))
     return value_x_binop (arg1, arg2, op, OP_NULL, noside);
   else
@@ -1380,8 +1341,6 @@ eval_op_equal (struct type *expect_type, struct expression *exp,
 	       enum noside noside, enum exp_opcode op,
 	       struct value *arg1, struct value *arg2)
 {
-  if (noside == EVAL_SKIP)
-    return eval_skip_value (exp);
   if (binop_user_defined_p (op, arg1, arg2))
     {
       return value_x_binop (arg1, arg2, op, OP_NULL, noside);
@@ -1403,8 +1362,6 @@ eval_op_notequal (struct type *expect_type, struct expression *exp,
 		  enum noside noside, enum exp_opcode op,
 		  struct value *arg1, struct value *arg2)
 {
-  if (noside == EVAL_SKIP)
-    return eval_skip_value (exp);
   if (binop_user_defined_p (op, arg1, arg2))
     {
       return value_x_binop (arg1, arg2, op, OP_NULL, noside);
@@ -1426,8 +1383,6 @@ eval_op_less (struct type *expect_type, struct expression *exp,
 	      enum noside noside, enum exp_opcode op,
 	      struct value *arg1, struct value *arg2)
 {
-  if (noside == EVAL_SKIP)
-    return eval_skip_value (exp);
   if (binop_user_defined_p (op, arg1, arg2))
     {
       return value_x_binop (arg1, arg2, op, OP_NULL, noside);
@@ -1449,8 +1404,6 @@ eval_op_gtr (struct type *expect_type, struct expression *exp,
 	     enum noside noside, enum exp_opcode op,
 	     struct value *arg1, struct value *arg2)
 {
-  if (noside == EVAL_SKIP)
-    return eval_skip_value (exp);
   if (binop_user_defined_p (op, arg1, arg2))
     {
       return value_x_binop (arg1, arg2, op, OP_NULL, noside);
@@ -1472,8 +1425,6 @@ eval_op_geq (struct type *expect_type, struct expression *exp,
 	     enum noside noside, enum exp_opcode op,
 	     struct value *arg1, struct value *arg2)
 {
-  if (noside == EVAL_SKIP)
-    return eval_skip_value (exp);
   if (binop_user_defined_p (op, arg1, arg2))
     {
       return value_x_binop (arg1, arg2, op, OP_NULL, noside);
@@ -1495,8 +1446,6 @@ eval_op_leq (struct type *expect_type, struct expression *exp,
 	     enum noside noside, enum exp_opcode op,
 	     struct value *arg1, struct value *arg2)
 {
-  if (noside == EVAL_SKIP)
-    return eval_skip_value (exp);
   if (binop_user_defined_p (op, arg1, arg2))
     {
       return value_x_binop (arg1, arg2, op, OP_NULL, noside);
@@ -1518,8 +1467,6 @@ eval_op_repeat (struct type *expect_type, struct expression *exp,
 		enum noside noside, enum exp_opcode op,
 		struct value *arg1, struct value *arg2)
 {
-  if (noside == EVAL_SKIP)
-    return eval_skip_value (exp);
   struct type *type = check_typedef (value_type (arg2));
   if (type->code () != TYPE_CODE_INT
       && type->code () != TYPE_CODE_ENUM)
@@ -1540,8 +1487,6 @@ eval_op_plus (struct type *expect_type, struct expression *exp,
 	      enum noside noside, enum exp_opcode op,
 	      struct value *arg1)
 {
-  if (noside == EVAL_SKIP)
-    return eval_skip_value (exp);
   if (unop_user_defined_p (op, arg1))
     return value_x_unop (arg1, op, noside);
   else
@@ -1558,8 +1503,6 @@ eval_op_neg (struct type *expect_type, struct expression *exp,
 	     enum noside noside, enum exp_opcode op,
 	     struct value *arg1)
 {
-  if (noside == EVAL_SKIP)
-    return eval_skip_value (exp);
   if (unop_user_defined_p (op, arg1))
     return value_x_unop (arg1, op, noside);
   else
@@ -1576,8 +1519,6 @@ eval_op_complement (struct type *expect_type, struct expression *exp,
 		    enum noside noside, enum exp_opcode op,
 		    struct value *arg1)
 {
-  if (noside == EVAL_SKIP)
-    return eval_skip_value (exp);
   if (unop_user_defined_p (UNOP_COMPLEMENT, arg1))
     return value_x_unop (arg1, UNOP_COMPLEMENT, noside);
   else
@@ -1594,8 +1535,6 @@ eval_op_lognot (struct type *expect_type, struct expression *exp,
 		enum noside noside, enum exp_opcode op,
 		struct value *arg1)
 {
-  if (noside == EVAL_SKIP)
-    return eval_skip_value (exp);
   if (unop_user_defined_p (op, arg1))
     return value_x_unop (arg1, op, noside);
   else
@@ -1618,8 +1557,6 @@ eval_op_ind (struct type *expect_type, struct expression *exp,
       || type->code () == TYPE_CODE_MEMBERPTR)
     error (_("Attempt to dereference pointer "
 	     "to member without an object"));
-  if (noside == EVAL_SKIP)
-    return eval_skip_value (exp);
   if (unop_user_defined_p (UNOP_IND, arg1))
     return value_x_unop (arg1, UNOP_IND, noside);
   else if (noside == EVAL_AVOID_SIDE_EFFECTS)
@@ -1673,8 +1610,6 @@ eval_op_memval (struct type *expect_type, struct expression *exp,
 		enum noside noside,
 		struct value *arg1, struct type *type)
 {
-  if (noside == EVAL_SKIP)
-    return eval_skip_value (exp);
   if (noside == EVAL_AVOID_SIDE_EFFECTS)
     return value_zero (type, lval_memory);
   else
@@ -1688,7 +1623,7 @@ eval_op_preinc (struct type *expect_type, struct expression *exp,
 		enum noside noside, enum exp_opcode op,
 		struct value *arg1)
 {
-  if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS)
+  if (noside == EVAL_AVOID_SIDE_EFFECTS)
     return arg1;
   else if (unop_user_defined_p (op, arg1))
     {
@@ -1719,7 +1654,7 @@ eval_op_predec (struct type *expect_type, struct expression *exp,
 		enum noside noside, enum exp_opcode op,
 		struct value *arg1)
 {
-  if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS)
+  if (noside == EVAL_AVOID_SIDE_EFFECTS)
     return arg1;
   else if (unop_user_defined_p (op, arg1))
     {
@@ -1750,7 +1685,7 @@ eval_op_postinc (struct type *expect_type, struct expression *exp,
 		 enum noside noside, enum exp_opcode op,
 		 struct value *arg1)
 {
-  if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS)
+  if (noside == EVAL_AVOID_SIDE_EFFECTS)
     return arg1;
   else if (unop_user_defined_p (op, arg1))
     {
@@ -1784,7 +1719,7 @@ eval_op_postdec (struct type *expect_type, struct expression *exp,
 		 enum noside noside, enum exp_opcode op,
 		 struct value *arg1)
 {
-  if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS)
+  if (noside == EVAL_AVOID_SIDE_EFFECTS)
     return arg1;
   else if (unop_user_defined_p (op, arg1))
     {
@@ -1817,9 +1752,7 @@ struct value *
 eval_op_type (struct type *expect_type, struct expression *exp,
 	      enum noside noside, struct type *type)
 {
-  if (noside == EVAL_SKIP)
-    return eval_skip_value (exp);
-  else if (noside == EVAL_AVOID_SIDE_EFFECTS)
+  if (noside == EVAL_AVOID_SIDE_EFFECTS)
     return allocate_value (type);
   else
     error (_("Attempt to use a type name as an expression"));
@@ -1832,7 +1765,7 @@ eval_binop_assign_modify (struct type *expect_type, struct expression *exp,
 			  enum noside noside, enum exp_opcode op,
 			  struct value *arg1, struct value *arg2)
 {
-  if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS)
+  if (noside == EVAL_AVOID_SIDE_EFFECTS)
     return arg1;
   if (binop_user_defined_p (op, arg1, arg2))
     return value_x_binop (arg1, arg2, BINOP_ASSIGN_MODIFY, op, noside);
@@ -2082,8 +2015,6 @@ eval_op_objc_msgcall (struct type *expect_type, struct expression *exp,
 	called_method = msg_send;
     }
 
-  if (noside == EVAL_SKIP)
-    return eval_skip_value (exp);
 
   if (noside == EVAL_AVOID_SIDE_EFFECTS)
     {
@@ -2139,8 +2070,6 @@ eval_multi_subscript (struct type *expect_type, struct expression *exp,
 		      enum noside noside, value *arg1,
 		      gdb::array_view<value *> args)
 {
-  if (noside == EVAL_SKIP)
-    return arg1;
   for (value *arg2 : args)
     {
       if (binop_user_defined_p (MULTI_SUBSCRIPT, arg1, arg2))
@@ -2228,8 +2157,6 @@ logical_and_operation::evaluate (struct type *expect_type,
 				 enum noside noside)
 {
   value *arg1 = std::get<0> (m_storage)->evaluate (nullptr, exp, noside);
-  if (noside == EVAL_SKIP)
-    return eval_skip_value (exp);
 
   value *arg2 = std::get<1> (m_storage)->evaluate (nullptr, exp,
 						   EVAL_AVOID_SIDE_EFFECTS);
@@ -2259,8 +2186,6 @@ logical_or_operation::evaluate (struct type *expect_type,
 				enum noside noside)
 {
   value *arg1 = std::get<0> (m_storage)->evaluate (nullptr, exp, noside);
-  if (noside == EVAL_SKIP)
-    return eval_skip_value (exp);
 
   value *arg2 = std::get<1> (m_storage)->evaluate (nullptr, exp,
 						   EVAL_AVOID_SIDE_EFFECTS);
@@ -2385,7 +2310,7 @@ array_operation::evaluate (struct type *expect_type,
   int nargs = tem3 - tem2 + 1;
   struct type *type = expect_type ? check_typedef (expect_type) : nullptr;
 
-  if (expect_type != nullptr && noside != EVAL_SKIP
+  if (expect_type != nullptr
       && type->code () == TYPE_CODE_STRUCT)
     {
       struct value *rec = allocate_value (expect_type);
@@ -2394,7 +2319,7 @@ array_operation::evaluate (struct type *expect_type,
       return evaluate_struct_tuple (rec, exp, noside, nargs);
     }
 
-  if (expect_type != nullptr && noside != EVAL_SKIP
+  if (expect_type != nullptr
       && type->code () == TYPE_CODE_ARRAY)
     {
       struct type *range_type = type->index_type ();
@@ -2430,7 +2355,7 @@ array_operation::evaluate (struct type *expect_type,
       return array;
     }
 
-  if (expect_type != nullptr && noside != EVAL_SKIP
+  if (expect_type != nullptr
       && type->code () == TYPE_CODE_SET)
     {
       struct value *set = allocate_value (expect_type);
@@ -2503,8 +2428,6 @@ array_operation::evaluate (struct type *expect_type,
 	 objects.  */
       argvec[tem] = in_args[tem]->evaluate_with_coercion (exp, noside);
     }
-  if (noside == EVAL_SKIP)
-    return eval_skip_value (exp);
   return value_array (tem2, tem3, argvec);
 }
 
@@ -2543,8 +2466,6 @@ operation::evaluate_for_cast (struct type *expect_type,
 			      enum noside noside)
 {
   value *val = evaluate (expect_type, exp, noside);
-  if (noside == EVAL_SKIP)
-    return eval_skip_value (exp);
   return value_cast (expect_type, val);
 }
 
@@ -2810,9 +2731,6 @@ var_msym_value_operation::evaluate_for_cast (struct type *to_type,
 					std::get<1> (m_storage),
 					std::get<0> (m_storage));
 
-  if (noside == EVAL_SKIP)
-    return eval_skip_value (exp);
-
   val = value_cast (to_type, val);
 
   /* Don't allow e.g. '&(int)var_with_no_debug_info'.  */
@@ -2834,9 +2752,6 @@ var_value_operation::evaluate_for_cast (struct type *to_type,
 				   std::get<1> (m_storage),
 				   std::get<0> (m_storage));
 
-  if (noside == EVAL_SKIP)
-    return eval_skip_value (exp);
-
   val = value_cast (to_type, val);
 
   /* Don't allow e.g. '&(int)var_with_no_debug_info'.  */
diff --git a/gdb/expop.h b/gdb/expop.h
index 7449ef60562..0abe6dac90b 100644
--- a/gdb/expop.h
+++ b/gdb/expop.h
@@ -1569,9 +1569,7 @@ class typeof_operation
 		   struct expression *exp,
 		   enum noside noside) override
   {
-    if (noside == EVAL_SKIP)
-      return eval_skip_value (exp);
-    else if (noside == EVAL_AVOID_SIDE_EFFECTS)
+    if (noside == EVAL_AVOID_SIDE_EFFECTS)
       return std::get<0> (m_storage)->evaluate (nullptr, exp,
 						EVAL_AVOID_SIDE_EFFECTS);
     else
@@ -1594,9 +1592,7 @@ class decltype_operation
 		   struct expression *exp,
 		   enum noside noside) override
   {
-    if (noside == EVAL_SKIP)
-      return eval_skip_value (exp);
-    else if (noside == EVAL_AVOID_SIDE_EFFECTS)
+    if (noside == EVAL_AVOID_SIDE_EFFECTS)
       {
 	value *result
 	  = std::get<0> (m_storage)->evaluate (nullptr, exp,
@@ -1671,10 +1667,7 @@ class unop_addr_operation
 		   enum noside noside) override
   {
     /* C++: check for and handle pointer to members.  */
-    if (noside == EVAL_SKIP)
-      return eval_skip_value (exp);
-    else
-      return std::get<0> (m_storage)->evaluate_for_address (exp, noside);
+    return std::get<0> (m_storage)->evaluate_for_address (exp, noside);
   }
 
   enum exp_opcode opcode () const override
@@ -1706,8 +1699,6 @@ class unop_sizeof_operation
 		   struct expression *exp,
 		   enum noside noside) override
   {
-    if (noside == EVAL_SKIP)
-      return eval_skip_value (exp);
     return std::get<0> (m_storage)->evaluate_for_sizeof (exp, noside);
   }
 
@@ -1890,7 +1881,7 @@ class assign_operation
 			  : value_type (lhs));
     value *rhs = std::get<1> (m_storage)->evaluate (xtype, exp, noside);
 
-    if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS)
+    if (noside == EVAL_AVOID_SIDE_EFFECTS)
       return lhs;
     if (binop_user_defined_p (BINOP_ASSIGN, lhs, rhs))
       return value_x_binop (lhs, rhs, BINOP_ASSIGN, OP_NULL, noside);
@@ -2031,8 +2022,6 @@ class cxx_cast_operation
 						    EVAL_AVOID_SIDE_EFFECTS);
     struct type *type = value_type (val);
     value *rhs = std::get<1> (m_storage)->evaluate (type, exp, noside);
-    if (noside == EVAL_SKIP)
-      return eval_skip_value (exp);
     return FUNC (type, rhs);
   }
 
diff --git a/gdb/expression.h b/gdb/expression.h
index 83bfe753d84..244f4e8ad33 100644
--- a/gdb/expression.h
+++ b/gdb/expression.h
@@ -54,9 +54,6 @@ enum exp_opcode : uint8_t
 enum noside
   {
     EVAL_NORMAL,
-    EVAL_SKIP,			/* Only effect is to increment pos.
-				   Return type information where
-				   possible.  */
     EVAL_AVOID_SIDE_EFFECTS	/* Don't modify any variables or
 				   call any functions.  The value
 				   returned will have the correct
diff --git a/gdb/f-lang.c b/gdb/f-lang.c
index f86f961e7bb..bf828d536f3 100644
--- a/gdb/f-lang.c
+++ b/gdb/f-lang.c
@@ -272,8 +272,6 @@ eval_op_f_abs (struct type *expect_type, struct expression *exp,
 	       enum exp_opcode opcode,
 	       struct value *arg1)
 {
-  if (noside == EVAL_SKIP)
-    return eval_skip_value (exp);
   struct type *type = value_type (arg1);
   switch (type->code ())
     {
@@ -302,8 +300,6 @@ eval_op_f_mod (struct type *expect_type, struct expression *exp,
 	       enum exp_opcode opcode,
 	       struct value *arg1, struct value *arg2)
 {
-  if (noside == EVAL_SKIP)
-    return eval_skip_value (exp);
   struct type *type = value_type (arg1);
   if (type->code () != value_type (arg2)->code ())
     error (_("non-matching types for parameters to MOD ()"));
@@ -341,8 +337,6 @@ eval_op_f_ceil (struct type *expect_type, struct expression *exp,
 		enum exp_opcode opcode,
 		struct value *arg1)
 {
-  if (noside == EVAL_SKIP)
-    return eval_skip_value (exp);
   struct type *type = value_type (arg1);
   if (type->code () != TYPE_CODE_FLT)
     error (_("argument to CEILING must be of type float"));
@@ -361,8 +355,6 @@ eval_op_f_floor (struct type *expect_type, struct expression *exp,
 		 enum exp_opcode opcode,
 		 struct value *arg1)
 {
-  if (noside == EVAL_SKIP)
-    return eval_skip_value (exp);
   struct type *type = value_type (arg1);
   if (type->code () != TYPE_CODE_FLT)
     error (_("argument to FLOOR must be of type float"));
@@ -381,8 +373,6 @@ eval_op_f_modulo (struct type *expect_type, struct expression *exp,
 		  enum exp_opcode opcode,
 		  struct value *arg1, struct value *arg2)
 {
-  if (noside == EVAL_SKIP)
-    return eval_skip_value (exp);
   struct type *type = value_type (arg1);
   if (type->code () != value_type (arg2)->code ())
     error (_("non-matching types for parameters to MODULO ()"));
@@ -423,8 +413,6 @@ eval_op_f_cmplx (struct type *expect_type, struct expression *exp,
 		 enum exp_opcode opcode,
 		 struct value *arg1, struct value *arg2)
 {
-  if (noside == EVAL_SKIP)
-    return eval_skip_value (exp);
   struct type *type = builtin_f_type(exp->gdbarch)->builtin_complex_s16;
   return value_literal_complex (arg1, arg2, type);
 }
diff --git a/gdb/m2-lang.c b/gdb/m2-lang.c
index a165cf6b603..6f6192937a4 100644
--- a/gdb/m2-lang.c
+++ b/gdb/m2-lang.c
@@ -37,7 +37,7 @@ eval_op_m2_high (struct type *expect_type, struct expression *exp,
 		 enum noside noside,
 		 struct value *arg1)
 {
-  if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS)
+  if (noside == EVAL_AVOID_SIDE_EFFECTS)
     return arg1;
   else
     {
@@ -68,8 +68,6 @@ eval_op_m2_subscript (struct type *expect_type, struct expression *exp,
 		      enum noside noside,
 		      struct value *arg1, struct value *arg2)
 {
-  if (noside == EVAL_SKIP)
-    return eval_skip_value (exp);
   /* If the user attempts to subscript something that is not an
      array or pointer type (like a plain int variable for example),
      then report this as an error.  */
diff --git a/gdb/opencl-lang.c b/gdb/opencl-lang.c
index c168cd49344..1d6117a9285 100644
--- a/gdb/opencl-lang.c
+++ b/gdb/opencl-lang.c
@@ -681,7 +681,7 @@ eval_opencl_assign (struct type *expect_type, struct expression *exp,
 		    enum noside noside, enum exp_opcode op,
 		    struct value *arg1, struct value *arg2)
 {
-  if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS)
+  if (noside == EVAL_AVOID_SIDE_EFFECTS)
     return arg1;
 
   struct type *type1 = value_type (arg1);
diff --git a/gdb/value.h b/gdb/value.h
index 88995cfeafe..59036b070aa 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -923,8 +923,6 @@ extern value *evaluate_var_msym_value (enum noside noside,
 				       struct objfile *objfile,
 				       minimal_symbol *msymbol);
 
-extern value *eval_skip_value (expression *exp);
-
 namespace expr { class operation; };
 extern void fetch_subexp_value (struct expression *exp,
 				expr::operation *op,
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 201/203] Change exp_uses_objfile to return bool
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (199 preceding siblings ...)
  2021-01-01 21:47 ` [PATCH 200/203] Remove EVAL_SKIP Tom Tromey
@ 2021-01-01 21:47 ` Tom Tromey
  2021-01-01 21:47 ` [PATCH 202/203] Use bound_minimal_symbol in var_msym_value_operation Tom Tromey
                   ` (2 subsequent siblings)
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:47 UTC (permalink / raw)
  To: gdb-patches

This change exp_uses_objfile to return bool.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* parser-defs.h (exp_uses_objfile): Return bool.
	* parse.c (exp_uses_objfile): Return bool.
---
 gdb/ChangeLog     | 5 +++++
 gdb/parse.c       | 8 ++++----
 gdb/parser-defs.h | 2 +-
 3 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/gdb/parse.c b/gdb/parse.c
index 8cdaa83b60b..3b7680e3127 100644
--- a/gdb/parse.c
+++ b/gdb/parse.c
@@ -630,11 +630,11 @@ parser_fprintf (FILE *x, const char *y, ...)
   va_end (args);
 }
 
-/* Return 1 if EXP uses OBJFILE (and will become dangling when OBJFILE
-   is unloaded), otherwise return 0.  OBJFILE must not be a separate debug info
-   file.  */
+/* Return rue if EXP uses OBJFILE (and will become dangling when
+   OBJFILE is unloaded), otherwise return false.  OBJFILE must not be
+   a separate debug info file.  */
 
-int
+bool
 exp_uses_objfile (struct expression *exp, struct objfile *objfile)
 {
   gdb_assert (objfile->separate_debug_objfile_backlink == NULL);
diff --git a/gdb/parser-defs.h b/gdb/parser-defs.h
index 31be5e80bd9..401ed378524 100644
--- a/gdb/parser-defs.h
+++ b/gdb/parser-defs.h
@@ -376,7 +376,7 @@ extern bool parse_float (const char *p, int len,
 
 extern void parser_fprintf (FILE *, const char *, ...) ATTRIBUTE_PRINTF (2, 3);
 
-extern int exp_uses_objfile (struct expression *exp, struct objfile *objfile);
+extern bool exp_uses_objfile (struct expression *exp, struct objfile *objfile);
 
 #endif /* PARSER_DEFS_H */
 
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 202/203] Use bound_minimal_symbol in var_msym_value_operation
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (200 preceding siblings ...)
  2021-01-01 21:47 ` [PATCH 201/203] Change exp_uses_objfile to return bool Tom Tromey
@ 2021-01-01 21:47 ` Tom Tromey
  2021-01-01 21:47 ` [PATCH 203/203] Remove some null checks Tom Tromey
  2021-01-03  7:02 ` [PATCH 000/203] Refactor expressions Joel Brobecker
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:47 UTC (permalink / raw)
  To: gdb-patches

This changes var_msym_value_operation to use a bound_minimal_symbol
rather than separate minsym and objfile parameters.  The main benefit
of this is removing the possibly-confusing check_objfile overload for
a plain minimal symbol.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* parse.c (parser_state::push_symbol, parser_state::push_dollar):
	Update.
	* p-exp.y (variable): Update.
	* go-exp.y (variable): Update.
	* expprint.c (dump_for_expression): Use bound_minimal_symbol.
	Remove overload for objfile.
	* expop.h (eval_op_var_msym_value): Use bound_minimal_symbol
	parameter.
	(check_objfile): Likewise.
	(dump_for_expression): Likewise.  Remove overload for objfile.
	(class var_msym_value_operation): Use bound_minimal_symbol.
	* eval.c (eval_op_var_msym_value): Use bound_minimal_symbol
	parameter.
	(var_msym_value_operation::evaluate_for_address)
	(var_msym_value_operation::evaluate_for_sizeof)
	(var_msym_value_operation::evaluate_for_cast): Update.
	* d-exp.y (PrimaryExpression): Update.
	* c-exp.y (variable): Update.
	* ax-gdb.c (var_msym_value_operation::do_generate_ax): Update.
	* ada-lang.c (ada_var_msym_value_operation::evaluate_for_cast):
	Update.
	* ada-exp.y (write_var_or_type): Update.
---
 gdb/ChangeLog  | 25 +++++++++++++++++++++++++
 gdb/ada-exp.y  |  3 +--
 gdb/ada-lang.c |  5 ++---
 gdb/ax-gdb.c   |  6 +++---
 gdb/c-exp.y    |  4 ++--
 gdb/d-exp.y    |  3 +--
 gdb/eval.c     | 25 +++++++++++--------------
 gdb/expop.h    | 26 +++++++-------------------
 gdb/expprint.c | 14 ++++----------
 gdb/go-exp.y   |  2 +-
 gdb/p-exp.y    |  2 +-
 gdb/parse.c    |  5 ++---
 12 files changed, 60 insertions(+), 60 deletions(-)

diff --git a/gdb/ada-exp.y b/gdb/ada-exp.y
index 033bde38d3c..ca37ec602e1 100644
--- a/gdb/ada-exp.y
+++ b/gdb/ada-exp.y
@@ -1518,8 +1518,7 @@ write_var_or_type (struct parser_state *par_state,
 		= ada_lookup_simple_minsym (encoded_name);
 	      if (msym.minsym != NULL)
 		{
-		  par_state->push_new<ada_var_msym_value_operation>
-		    (msym.minsym, msym.objfile);
+		  par_state->push_new<ada_var_msym_value_operation> (msym);
 		  /* Maybe cause error here rather than later? FIXME? */
 		  write_selectors (par_state, encoded_name + tail_index);
 		  return NULL;
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 4ab9172cc81..e848e141465 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -10407,9 +10407,8 @@ ada_var_msym_value_operation::evaluate_for_cast (struct type *expect_type,
   if (noside == EVAL_AVOID_SIDE_EFFECTS)
     return value_zero (expect_type, not_lval);
 
-  value *val = evaluate_var_msym_value (noside,
-					std::get<1> (m_storage),
-					std::get<0> (m_storage));
+  const bound_minimal_symbol &b = std::get<0> (m_storage);
+  value *val = evaluate_var_msym_value (noside, b.objfile, b.minsym);
 
   val = ada_value_cast (expect_type, val);
 
diff --git a/gdb/ax-gdb.c b/gdb/ax-gdb.c
index 788be528d1b..33fc5383764 100644
--- a/gdb/ax-gdb.c
+++ b/gdb/ax-gdb.c
@@ -1631,13 +1631,13 @@ var_msym_value_operation::do_generate_ax (struct expression *exp,
 					  struct axs_value *value,
 					  struct type *cast_type)
 {
-  gen_msym_var_ref (ax, value, std::get<0> (m_storage),
-		    std::get<1> (m_storage));
+  const bound_minimal_symbol &b = std::get<0> (m_storage);
+  gen_msym_var_ref (ax, value, b.minsym, b.objfile);
 
   if (value->type->code () == TYPE_CODE_ERROR)
     {
       if (cast_type == nullptr)
-	error_unknown_type (std::get<0> (m_storage)->linkage_name ());
+	error_unknown_type (b.minsym->linkage_name ());
       value->type = cast_type;
     }
 }
diff --git a/gdb/c-exp.y b/gdb/c-exp.y
index 3ce08838080..dbdd68fb183 100644
--- a/gdb/c-exp.y
+++ b/gdb/c-exp.y
@@ -1195,7 +1195,7 @@ variable:	name_not_typename
 				= find_gnu_ifunc (sym.symbol);
 			      if (resolver.minsym != NULL)
 				pstate->push_new<var_msym_value_operation>
-				  (resolver.minsym, resolver.objfile);
+				  (resolver);
 			      else
 				pstate->push_new<var_value_operation>
 				  (sym.symbol, sym.block);
@@ -1243,7 +1243,7 @@ variable:	name_not_typename
 				  (alias_target, SYMBOL_BLOCK_VALUE (alias_target));
 			      else
 				pstate->push_new<var_msym_value_operation>
-				  (msymbol.minsym, msymbol.objfile);
+				  (msymbol);
 			    }
 			}
 	;
diff --git a/gdb/d-exp.y b/gdb/d-exp.y
index d79eaf14a8f..34b97d03489 100644
--- a/gdb/d-exp.y
+++ b/gdb/d-exp.y
@@ -470,8 +470,7 @@ PrimaryExpression:
 		      /* Lookup foreign name in global static symbols.  */
 		      msymbol = lookup_bound_minimal_symbol (copy.c_str ());
 		      if (msymbol.minsym != NULL)
-			pstate->push_new<var_msym_value_operation>
-			  (msymbol.minsym, msymbol.objfile);
+			pstate->push_new<var_msym_value_operation> (msymbol);
 		      else if (!have_full_symbols () && !have_partial_symbols ())
 			error (_("No symbol table is loaded.  Use the \"file\" command"));
 		      else
diff --git a/gdb/eval.c b/gdb/eval.c
index 49e53f930b9..bf865296baa 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -1004,14 +1004,15 @@ eval_op_var_entry_value (struct type *expect_type, struct expression *exp,
 struct value *
 eval_op_var_msym_value (struct type *expect_type, struct expression *exp,
 			enum noside noside,
-			minimal_symbol *msymbol, struct objfile *objfile)
+			bound_minimal_symbol msymbol)
 {
-  value *val = evaluate_var_msym_value (noside, objfile, msymbol);
+  value *val = evaluate_var_msym_value (noside, msymbol.objfile,
+					msymbol.minsym);
 
   struct type *type = value_type (val);
   if (type->code () == TYPE_CODE_ERROR
       && (noside != EVAL_AVOID_SIDE_EFFECTS))
-    error_unknown_type (msymbol->print_name ());
+    error_unknown_type (msymbol.minsym->print_name ());
   return val;
 }
 
@@ -2508,9 +2509,8 @@ value *
 var_msym_value_operation::evaluate_for_address (struct expression *exp,
 						enum noside noside)
 {
-  value *val = evaluate_var_msym_value (noside,
-					std::get<1> (m_storage),
-					std::get<0> (m_storage));
+  const bound_minimal_symbol &b = std::get<0> (m_storage);
+  value *val = evaluate_var_msym_value (noside, b.objfile, b.minsym);
   if (noside == EVAL_AVOID_SIDE_EFFECTS)
     {
       struct type *type = lookup_pointer_type (value_type (val));
@@ -2616,14 +2616,12 @@ var_msym_value_operation::evaluate_for_sizeof (struct expression *exp,
 					       enum noside noside)
 
 {
-  minimal_symbol *msymbol = std::get<0> (m_storage);
-  value *mval = evaluate_var_msym_value (noside,
-					 std::get<1> (m_storage),
-					 msymbol);
+  const bound_minimal_symbol &b = std::get<0> (m_storage);
+  value *mval = evaluate_var_msym_value (noside, b.objfile, b.minsym);
 
   struct type *type = value_type (mval);
   if (type->code () == TYPE_CODE_ERROR)
-    error_unknown_type (msymbol->print_name ());
+    error_unknown_type (b.minsym->print_name ());
 
   /* FIXME: This should be size_t.  */
   struct type *size_type = builtin_type (exp->gdbarch)->builtin_int;
@@ -2727,9 +2725,8 @@ var_msym_value_operation::evaluate_for_cast (struct type *to_type,
   if (noside == EVAL_AVOID_SIDE_EFFECTS)
     return value_zero (to_type, not_lval);
 
-  value *val = evaluate_var_msym_value (noside,
-					std::get<1> (m_storage),
-					std::get<0> (m_storage));
+  const bound_minimal_symbol &b = std::get<0> (m_storage);
+  value *val = evaluate_var_msym_value (noside, b.objfile, b.minsym);
 
   val = value_cast (to_type, val);
 
diff --git a/gdb/expop.h b/gdb/expop.h
index 0abe6dac90b..98d5d34c7f5 100644
--- a/gdb/expop.h
+++ b/gdb/expop.h
@@ -52,8 +52,7 @@ extern struct value *eval_op_scope (struct type *expect_type,
 extern struct value *eval_op_var_msym_value (struct type *expect_type,
 					     struct expression *exp,
 					     enum noside noside,
-					     minimal_symbol *msymbol,
-					     struct objfile *objfile);
+					     bound_minimal_symbol msymbol);
 extern struct value *eval_op_var_entry_value (struct type *expect_type,
 					      struct expression *exp,
 					      enum noside noside, symbol *sym);
@@ -243,11 +242,9 @@ check_objfile (const struct block *block, struct objfile *objfile)
 }
 
 static inline bool
-check_objfile (minimal_symbol *minsym, struct objfile *objfile)
+check_objfile (bound_minimal_symbol minsym, struct objfile *objfile)
 {
-  /* This may seem strange but minsyms are only used with an objfile
-     as well.  */
-  return false;
+  return check_objfile (minsym.objfile, objfile);
 }
 
 static inline bool
@@ -330,7 +327,7 @@ extern void dump_for_expression (struct ui_file *stream, int depth,
 extern void dump_for_expression (struct ui_file *stream, int depth,
 				 symbol *sym);
 extern void dump_for_expression (struct ui_file *stream, int depth,
-				 minimal_symbol *msym);
+				 bound_minimal_symbol msym);
 extern void dump_for_expression (struct ui_file *stream, int depth,
 				 const block *bl);
 extern void dump_for_expression (struct ui_file *stream, int depth,
@@ -339,8 +336,6 @@ extern void dump_for_expression (struct ui_file *stream, int depth,
 				 enum c_string_type_values flags);
 extern void dump_for_expression (struct ui_file *stream, int depth,
 				 enum range_flag flags);
-extern void dump_for_expression (struct ui_file *stream, int depth,
-				 objfile *objf);
 extern void dump_for_expression (struct ui_file *stream, int depth,
 				 const std::unique_ptr<ada_component> &comp);
 
@@ -445,7 +440,7 @@ check_constant (const operation_up &item)
 }
 
 static inline bool
-check_constant (struct minimal_symbol *msym)
+check_constant (bound_minimal_symbol msym)
 {
   return false;
 }
@@ -468,12 +463,6 @@ check_constant (const std::string &str)
   return true;
 }
 
-static inline bool
-check_constant (struct objfile *objfile)
-{
-  return true;
-}
-
 static inline bool
 check_constant (ULONGEST cst)
 {
@@ -705,7 +694,7 @@ class long_const_operation
 };
 
 class var_msym_value_operation
-  : public maybe_constant_operation<minimal_symbol *, struct objfile *>
+  : public maybe_constant_operation<bound_minimal_symbol>
 {
 public:
 
@@ -716,8 +705,7 @@ class var_msym_value_operation
 		   enum noside noside) override
   {
     return eval_op_var_msym_value (expect_type, exp, noside,
-				   std::get<0> (m_storage),
-				   std::get<1> (m_storage));
+				   std::get<0> (m_storage));
   }
 
   value *evaluate_for_sizeof (struct expression *exp, enum noside noside)
diff --git a/gdb/expprint.c b/gdb/expprint.c
index 5e55e77b5a2..c0969e37295 100644
--- a/gdb/expprint.c
+++ b/gdb/expprint.c
@@ -110,10 +110,11 @@ dump_for_expression (struct ui_file *stream, int depth, symbol *sym)
 }
 
 void
-dump_for_expression (struct ui_file *stream, int depth, minimal_symbol *msym)
+dump_for_expression (struct ui_file *stream, int depth,
+		     bound_minimal_symbol msym)
 {
-  fprintf_filtered (stream, _("%*sMinsym: %s\n"), depth, "",
-		     msym->print_name ());
+  fprintf_filtered (stream, _("%*sMinsym %s in objfile %s\n"), depth, "",
+		    msym.minsym->print_name (), objfile_name (msym.objfile));
 }
 
 void
@@ -162,13 +163,6 @@ dump_for_expression (struct ui_file *stream, int depth,
   fputs_unfiltered ("\n", stream);
 }
 
-void
-dump_for_expression (struct ui_file *stream, int depth, objfile *objf)
-{
-  fprintf_filtered (stream, _("%*sObjfile: %s\n"), depth, "",
-		     objfile_name (objf));
-}
-
 void
 dump_for_expression (struct ui_file *stream, int depth,
 		     enum range_flag flags)
diff --git a/gdb/go-exp.y b/gdb/go-exp.y
index d096cc8b7c9..05822d142db 100644
--- a/gdb/go-exp.y
+++ b/gdb/go-exp.y
@@ -581,7 +581,7 @@ variable:	name_not_typename
 				lookup_bound_minimal_symbol (arg.c_str ());
 			      if (msymbol.minsym != NULL)
 				pstate->push_new<var_msym_value_operation>
-				  (msymbol.minsym, msymbol.objfile);
+				  (msymbol);
 			      else if (!have_full_symbols ()
 				       && !have_partial_symbols ())
 				error (_("No symbol table is loaded.  "
diff --git a/gdb/p-exp.y b/gdb/p-exp.y
index 4ac2f1f268d..c10402e4e5c 100644
--- a/gdb/p-exp.y
+++ b/gdb/p-exp.y
@@ -730,7 +730,7 @@ variable:	name_not_typename
 				lookup_bound_minimal_symbol (arg.c_str ());
 			      if (msymbol.minsym != NULL)
 				pstate->push_new<var_msym_value_operation>
-				  (msymbol.minsym, msymbol.objfile);
+				  (msymbol);
 			      else if (!have_full_symbols ()
 				       && !have_partial_symbols ())
 				error (_("No symbol table is loaded.  "
diff --git a/gdb/parse.c b/gdb/parse.c
index 3b7680e3127..d5215d89d14 100644
--- a/gdb/parse.c
+++ b/gdb/parse.c
@@ -226,8 +226,7 @@ parser_state::push_symbol (const char *name, struct symbol *sym)
     {
       struct bound_minimal_symbol msymbol = lookup_bound_minimal_symbol (name);
       if (msymbol.minsym != NULL)
-	push_new<expr::var_msym_value_operation> (msymbol.minsym,
-						  msymbol.objfile);
+	push_new<expr::var_msym_value_operation> (msymbol);
       else if (!have_full_symbols () && !have_partial_symbols ())
 	error (_("No symbol table is loaded.  Use the \"file\" command."));
       else
@@ -305,7 +304,7 @@ parser_state::push_dollar (struct stoken str)
   msym = lookup_bound_minimal_symbol (copy.c_str ());
   if (msym.minsym)
     {
-      push_new<expr::var_msym_value_operation> (msym.minsym, msym.objfile);
+      push_new<expr::var_msym_value_operation> (msym);
       return;
     }
 
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* [PATCH 203/203] Remove some null checks
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (201 preceding siblings ...)
  2021-01-01 21:47 ` [PATCH 202/203] Use bound_minimal_symbol in var_msym_value_operation Tom Tromey
@ 2021-01-01 21:47 ` Tom Tromey
  2021-01-03  7:02 ` [PATCH 000/203] Refactor expressions Joel Brobecker
  203 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-01 21:47 UTC (permalink / raw)
  To: gdb-patches

When not parsing for completion, parse_expression ensures that the
resulting expression has operations.  This patch removes a couple of
unnecessary checks for this situation.

gdb/ChangeLog
2021-01-01  Tom Tromey  <tom@tromey.com>

	* printcmd.c (set_command): Remove null check.
	* value.c (init_if_undefined_command): Remove null check.
---
 gdb/ChangeLog  |  5 +++++
 gdb/printcmd.c | 29 ++++++++++++++---------------
 gdb/value.c    |  2 +-
 3 files changed, 20 insertions(+), 16 deletions(-)

diff --git a/gdb/printcmd.c b/gdb/printcmd.c
index 484a2dbf228..c3e75de0bce 100644
--- a/gdb/printcmd.c
+++ b/gdb/printcmd.c
@@ -1373,21 +1373,20 @@ set_command (const char *exp, int from_tty)
 {
   expression_up expr = parse_expression (exp);
 
-  if (expr->op != nullptr)
-    switch (expr->op->opcode ())
-      {
-      case UNOP_PREINCREMENT:
-      case UNOP_POSTINCREMENT:
-      case UNOP_PREDECREMENT:
-      case UNOP_POSTDECREMENT:
-      case BINOP_ASSIGN:
-      case BINOP_ASSIGN_MODIFY:
-      case BINOP_COMMA:
-	break;
-      default:
-	warning
-	  (_("Expression is not an assignment (and might have no effect)"));
-      }
+  switch (expr->op->opcode ())
+    {
+    case UNOP_PREINCREMENT:
+    case UNOP_POSTINCREMENT:
+    case UNOP_PREDECREMENT:
+    case UNOP_POSTDECREMENT:
+    case BINOP_ASSIGN:
+    case BINOP_ASSIGN_MODIFY:
+    case BINOP_COMMA:
+      break;
+    default:
+      warning
+	(_("Expression is not an assignment (and might have no effect)"));
+    }
 
   evaluate_expression (expr.get ());
 }
diff --git a/gdb/value.c b/gdb/value.c
index 7a9128df642..1bd43a53db6 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -1982,7 +1982,7 @@ init_if_undefined_command (const char* args, int from_tty)
   /* Validate the expression.
      Was the expression an assignment?
      Or even an expression at all?  */
-  if (expr->op == nullptr || expr->first_opcode () != BINOP_ASSIGN)
+  if (expr->first_opcode () != BINOP_ASSIGN)
     error (_("Init-if-undefined requires an assignment expression."));
 
   /* Extract the variable from the parsed expression.  */
-- 
2.26.2


^ permalink raw reply	[flat|nested] 225+ messages in thread

* Re: [PATCH 009/203] what is this code for
  2021-01-01 21:44 ` [PATCH 009/203] what is this code for Tom Tromey
@ 2021-01-03  6:00   ` Joel Brobecker
  2021-01-25  2:28     ` Simon Marchi
  0 siblings, 1 reply; 225+ messages in thread
From: Joel Brobecker @ 2021-01-03  6:00 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

Hi Tom,

> @@ -1224,7 +1224,7 @@ eval_op_var_msym_value (struct type *expect_type, struct expression *exp,
>  
>    struct type *type = value_type (val);
>    if (type->code () == TYPE_CODE_ERROR
> -      && (noside != EVAL_AVOID_SIDE_EFFECTS || pc != 0))
> +      && (noside != EVAL_AVOID_SIDE_EFFECTS))
>      error_unknown_type (msymbol->print_name ());
>    return val;

I tracked the origin of this code down to the following commit...

    commit 46a4882b3c7d9ec981568b8b13a3c9c39c8f8e61
    Author: Pedro Alves <palves@redhat.com>
    Date:   Mon Sep 4 20:21:15 2017 +0100
    Subject: Stop assuming no-debug-info variables have type int

... which was the second stage of a similar change for functions.
The revision log did not really give an explicit explanation for
this code, but after a bit of thinking, I think I was able to
figure it out.

Consider the case where you're trying to investigate a variable
called "opaque" which is declared in the symbol table but does not
have any debug info.

  * If noside != EVAL_AVOID_SIDE_EFFECTS (typically, we're trying
    to print the value, then we always error out with:

        | 'opaque' has unknown type; cast it to its declared type

    ... This is what the patch is about. That's not what you are
    asking about, because it's easy to understand. OK.

  * So, if noside == EVAL_AVOID_SIDE_EFFECTS, what does it mean
    to only print the error message above if pc != 0?

    Well, if pc == 0, it means OP_VAR_MSYM_VALUE node is first,
    and since that operator doesn't have any "parameters", what
    it means to me is that it must actually be the only operand
    of the expression. Thus, we must be facing the following
    situation:

        | (gdb) ptype opaque

    And what do we do in that scenario? Well, we have code in gdbtype.c
    which gives default types for the various kinds of minimal symbols.
    For data symbols, it looks like this:

        | objfile_type->nodebug_data_symbol
        |   = init_nodebug_var_type (objfile, "<data variable, no debug info>");

    So, when we do a ptype, we don't get an error, but instead, get
    some information about the symbol:

        | (gdb) ptype opaque
        | type = <data variable, no debug info>


    If, on the other hand pc != 0, it means our minsym is part
    of a larger expression, such as, for instance "opaque + 1".
    With today's GDB, a "ptype" of the expression above generates
    the same error message when when in EVAL_NORMAL mode:

        | (gdb) ptype opaque + 1
        | 'opaque' has unknown type; cast it to its declared type

    If you remove the check above, then we no longer trigger
    the "has unknown type" error. So, instead, we just evaluate
    the minsym as is, which means we get a value whose type is
    the type of "objfile_type->nodebug_data_symbol", in other words
    TYPE_CODE_ERROR, which leads to:

        | (gdb) ptype opaque + 1
        | Argument to arithmetic operation not a number or boolean.

    For minimal symbols which are text symbols, these get a default
    type of TYPE_CODE_FUNC, so removing the above breaks the check
    which forces the user to specify the return type.

We should probably add a test or two in gdb.base/nodebug.exp for that...

-- 
Joel

^ permalink raw reply	[flat|nested] 225+ messages in thread

* Re: [PATCH 000/203] Refactor expressions
  2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
                   ` (202 preceding siblings ...)
  2021-01-01 21:47 ` [PATCH 203/203] Remove some null checks Tom Tromey
@ 2021-01-03  7:02 ` Joel Brobecker
  2021-01-04 12:16   ` Andrew Burgess
  2021-02-13 19:54   ` Tom Tromey
  203 siblings, 2 replies; 225+ messages in thread
From: Joel Brobecker @ 2021-01-03  7:02 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

Hi Tom,

On Fri, Jan 01, 2021 at 02:44:00PM -0700, Tom Tromey wrote:
> I have long thought that struct expression is the worst data structure
> in GDB.  In fact, I've sometimes told people it is the worst data
> structure I've encountered in my career.  I've wanted to rewrite it
> for many years, and this year I finally found a workable plan and the
> motivation to do so.  This series is the result.

Thanks for the (mega) series!

Because of the length of the series, I think it's going to be potentially
more difficult for you to maintain it over time. I so I think it would
be nice if we could put a priority on its review.

I've now started with part 1:

> 1. Split functions out from the evaluators.
> 
>    Each evaluator function is fairly long, and mixes knowledge about
>    the structure of the expression (how the exp_elements are laid out)
>    with knowledge of the semantics of the operation.
> 
>    This part of the series, which is about 70 patches, splits out the
>    semantics of most operations into their own functions.  These
>    functions can be then be reused -- which is helpful for ensuring
>    that changes don't sneak in.
> 
>    In this part of the series, sometimes the newly-introduced
>    functions have extraneous arguments.  This was done partly so that
>    some could be reused by generic code in part 2; but also partly
>    because it was just simpler to write patches by rote.

Aside from the commit "what is this code for", I think this part
of the series is a nice improvement on its own. independently
of redesigning struct expression, I've always found the evaluator
functions to be overly long and harder to navigate as a result.
So I think it could go in ahead of the rest if we agree that
this part is good.

For me, I've gone through the patches, more or less carefully
based on a random sample, and they look good. I paused a bit
about the Ada ones, were you excluded the hanlding of noside ==
EVAL_SKIP. I'm not entirely sure why that is, perhaps because
the block consists in a goto nosideret? Looking at what that
nosideret does, it's just...

    | nosideret:
    |   return eval_skip_value (exp);

... so we could inline this in the new functions.

However, this is really a very minor detail that doesn't need to be
addressed here.

So, to summarize, if others agree, I'm happy for this part of
the series to go in.

> 
> 2. Introduce 'class operation' and its subclasses.
> 
>    This sub-series is around 100 patches.  It introduces the new base
>    class for an expression operation, and then proceeds to add
>    operations for every necessary opcode.  In some cases multiple such
>    operations are needed -- for example when multiple languages
>    implement an opcode in different ways.
> 
>    Some discussion of the design & tradeoffs appear in the "Introduce
>    class operation" patch.
> 
> 3. Convert existing code to use operations.
> 
>    This is a short sub-series of around 10 patches.  Each parser is
>    converted separately, as are DTrace and SystemTap probes
> 
> 4. Delete obsolete code.
> 
>    The final 20 patches or so are concerned with removing all the code
>    that is now obsolete, and with doing some minor tidying of the
>    result.
> 
> The overall approach here is to replace the current data structure --
> but only the data structure.  I didn't generally try to clean up
> things that seemed a bit weird.
> 
> I also didn't try to add new features, like async evaluation.  After
> starting the project, I felt that trying to combine this refactoring
> with another, different one would be too difficult.
> 
> This is all on the branch t/expression-rewrite-incr in my github.
> 
> Regression tested on x86-64 Fedora 32.  I also built it on PPC Linux
> to ensure that the ppc-linux-nat.c changes would build.
> 
> Tom
> 

-- 
Joel

^ permalink raw reply	[flat|nested] 225+ messages in thread

* Re: [PATCH 073/203] Introduce class operation
  2021-01-01 21:45 ` [PATCH 073/203] Introduce class operation Tom Tromey
@ 2021-01-03  7:09   ` Joel Brobecker
  2021-01-03 13:55     ` Lancelot SIX
  0 siblings, 1 reply; 225+ messages in thread
From: Joel Brobecker @ 2021-01-03  7:09 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

Hi Tom,

> This patch introduces class operation, the new base class for all
> expression operations.
> 
> In the new approach, an operation is simply a class that presents a
> certain interface.  Operations own their operands, and management is
> done via unique_ptr.
> 
> The operation interface is largely ad hoc, based on the evolution of
> expression handling in GDB.  Parts (for example,
> evaluate_with_coercion) are probably redundant; however I took this
> approach to try to avoid mixing different kinds of refactorings.
> 
> In some specific situations, rather than add a generic method across
> the entire operation class hierarchy, I chose instead to use
> dynamic_cast and specialized methods on certain concrete subclasses.
> This will appear in some subsequent patches.
> 
> One goal of this work is to avoid the kinds of easy-to-make errors
> that affected the old implementation.  To this end, some helper
> subclasses are also added here.  These helpers automate the
> implementation of the 'dump', 'uses_objfile', and 'constant_p'
> methods.  Nearly every concrete operation that is subsequently added
> will use these facilities.  (Note that the 'dump' implementation is
> only outlined here, the body appears in the next patch.)
> 
> gdb/ChangeLog
> 2021-01-01  Tom Tromey  <tom@tromey.com>
> 
> 	* expression.h (expr::operation): New class.
> 	(expr::make_operation): New function.
> 	(expr::operation_up): New typedef.
> 	* expop.h: New file.
> 	* eval.c (operation::evaluate_for_cast)
> 	(operation::evaluate_for_address, operation::evaluate_for_sizeof):
> 	New methods.
> 	* ax-gdb.c (operation::generate_ax): New method.

Thanks for this!

I don't have much comment to share on this, at least not just yet
until I have had a chance to see this new API in action in the rest
of the patch series. I do have one small-tiny-mini suggestion:

It's about:

> +typedef std::unique_ptr<operation> operation_up;

FWIW, the connection between "up" and the rest of the declaration
wasn't immediately obvious to me. I think this is because "up"
is an english word, and spelled like that, all in lowercase,
that's really what my brain keeps analyzing it as first. It takes
an effort to adjust my thinking against this bias.

It's not a problem for me if we decide to keep this like that,
but what do you think about about renaming this to something like
"operation_uptr"? I think it'll make the intention more immediately
clear to the reader.

-- 
Joel

^ permalink raw reply	[flat|nested] 225+ messages in thread

* Re: [PATCH 151/203] Split out some Ada type resolution code
  2021-01-01 21:46 ` [PATCH 151/203] Split out some Ada type resolution code Tom Tromey
@ 2021-01-03  7:46   ` Joel Brobecker
  2021-02-13 19:47     ` Tom Tromey
  0 siblings, 1 reply; 225+ messages in thread
From: Joel Brobecker @ 2021-01-03  7:46 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

Hi Tom,

On Fri, Jan 01, 2021 at 02:46:31PM -0700, Tom Tromey wrote:
> This splits some Ada type resolution code out of resolve_subexp into
> new functions that can be reused.
> 
> gdb/ChangeLog
> 2021-01-01  Tom Tromey  <tom@tromey.com>
> 
> 	* ada-lang.h (ada_find_operator_symbol, ada_resolve_funcall)
> 	(ada_resolve_variable): Declare.
> 	* ada-lang.c (ada_find_operator_symbol, ada_resolve_funcall)
> 	(ada_resolve_variable): New functions.
> 	(resolve_subexp): Update.

Could this patch go in early, and independently of this patch series
(or perhaps right after the first third of the patches splitting
the various eval routines go in)?

As far as I can tell, all it needs is documentation of the new routines
in ada-lang.h. Other than that, this patch looks like a nice little
improvement of the code's organization.

Thanks!

> ---
>  gdb/ChangeLog  |   8 ++
>  gdb/ada-lang.c | 266 ++++++++++++++++++++++++++++---------------------
>  gdb/ada-lang.h |  18 ++++
>  3 files changed, 176 insertions(+), 116 deletions(-)
> 
> diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
> index e2c9de69b65..50b82e6bcf9 100644
> --- a/gdb/ada-lang.c
> +++ b/gdb/ada-lang.c
> @@ -3452,6 +3452,132 @@ See set/show multiple-symbol."));
>    return n_chosen;
>  }
>  
> +/* See ada-lang.h.  */
> +
> +block_symbol
> +ada_find_operator_symbol (enum exp_opcode op, int parse_completion,
> +			  int nargs, value *argvec[])
> +{
> +  if (possible_user_operator_p (op, argvec))
> +    {
> +      std::vector<struct block_symbol> candidates;
> +      int n_candidates = ada_lookup_symbol_list (ada_decoded_op_name (op),
> +						 NULL, VAR_DOMAIN,
> +						 &candidates);
> +      int i = ada_resolve_function (candidates.data (), n_candidates, argvec,
> +				    nargs, ada_decoded_op_name (op), NULL,
> +				    parse_completion);
> +      if (i >= 0)
> +	return candidates[i];
> +    }
> +  return {};
> +}
> +
> +/* See ada-lang.h.  */
> +
> +block_symbol
> +ada_resolve_funcall (struct symbol *sym, const struct block *block,
> +		     struct type *context_type,
> +		     int parse_completion,
> +		     int nargs, value *argvec[],
> +		     innermost_block_tracker *tracker)
> +{
> +  std::vector<struct block_symbol> candidates;
> +  int n_candidates = ada_lookup_symbol_list (sym->linkage_name (), block,
> +					     VAR_DOMAIN, &candidates);
> +
> +  int i;
> +  if (n_candidates == 1)
> +    i = 0;
> +  else
> +    {
> +      i = ada_resolve_function (candidates.data (), n_candidates,
> +				argvec, nargs,
> +				sym->linkage_name (),
> +				context_type, parse_completion);
> +      if (i < 0)
> +	error (_("Could not find a match for %s"), sym->print_name ());
> +    }
> +
> +  tracker->update (candidates[i]);
> +  return candidates[i];
> +}
> +
> +/* See ada-lang.h.  */
> +
> +block_symbol
> +ada_resolve_variable (struct symbol *sym, const struct block *block,
> +		      struct type *context_type,
> +		      int parse_completion,
> +		      int deprocedure_p,
> +		      innermost_block_tracker *tracker)
> +{
> +  std::vector<struct block_symbol> candidates;
> +  int n_candidates = ada_lookup_symbol_list (sym->linkage_name (),
> +					     block, VAR_DOMAIN,
> +					     &candidates);
> +
> +  if (n_candidates > 1)
> +    {
> +      /* Types tend to get re-introduced locally, so if there are any
> +	 local symbols that are not types, first filter out all
> +	 types.  */
> +      int j;
> +      for (j = 0; j < n_candidates; j += 1)
> +	switch (SYMBOL_CLASS (candidates[j].symbol))
> +	  {
> +	  case LOC_REGISTER:
> +	  case LOC_ARG:
> +	  case LOC_REF_ARG:
> +	  case LOC_REGPARM_ADDR:
> +	  case LOC_LOCAL:
> +	  case LOC_COMPUTED:
> +	    goto FoundNonType;
> +	  default:
> +	    break;
> +	  }
> +    FoundNonType:
> +      if (j < n_candidates)
> +	{
> +	  j = 0;
> +	  while (j < n_candidates)
> +	    {
> +	      if (SYMBOL_CLASS (candidates[j].symbol) == LOC_TYPEDEF)
> +		{
> +		  candidates[j] = candidates[n_candidates - 1];
> +		  n_candidates -= 1;
> +		}
> +	      else
> +		j += 1;
> +	    }
> +	}
> +    }
> +
> +  int i;
> +  if (n_candidates == 0)
> +    error (_("No definition found for %s"), sym->print_name ());
> +  else if (n_candidates == 1)
> +    i = 0;
> +  else if (deprocedure_p
> +	   && !is_nonfunction (candidates.data (), n_candidates))
> +    {
> +      i = ada_resolve_function (candidates.data (), n_candidates, NULL, 0,
> +				sym->linkage_name (),
> +				context_type, parse_completion);
> +      if (i < 0)
> +	error (_("Could not find a match for %s"), sym->print_name ());
> +    }
> +  else
> +    {
> +      printf_filtered (_("Multiple matches for %s\n"), sym->print_name ());
> +      user_select_syms (candidates.data (), n_candidates, 1);
> +      i = 0;
> +    }
> +
> +  tracker->update (candidates[i]);
> +  return candidates[i];
> +}
> +
>  /* Resolve the operator of the subexpression beginning at
>     position *POS of *EXPP.  "Resolving" consists of replacing
>     the symbols that have undefined namespaces in OP_VAR_VALUE nodes
> @@ -3640,77 +3766,13 @@ resolve_subexp (expression_up *expp, int *pos, int deprocedure_p,
>      case OP_VAR_VALUE:
>        if (SYMBOL_DOMAIN (exp->elts[pc + 2].symbol) == UNDEF_DOMAIN)
>  	{
> -	  std::vector<struct block_symbol> candidates;
> -	  int n_candidates;
> -
> -	  n_candidates =
> -	    ada_lookup_symbol_list (exp->elts[pc + 2].symbol->linkage_name (),
> -				    exp->elts[pc + 1].block, VAR_DOMAIN,
> -				    &candidates);
> -
> -	  if (n_candidates > 1)
> -	    {
> -	      /* Types tend to get re-introduced locally, so if there
> -		 are any local symbols that are not types, first filter
> -		 out all types.  */
> -	      int j;
> -	      for (j = 0; j < n_candidates; j += 1)
> -		switch (SYMBOL_CLASS (candidates[j].symbol))
> -		  {
> -		  case LOC_REGISTER:
> -		  case LOC_ARG:
> -		  case LOC_REF_ARG:
> -		  case LOC_REGPARM_ADDR:
> -		  case LOC_LOCAL:
> -		  case LOC_COMPUTED:
> -		    goto FoundNonType;
> -		  default:
> -		    break;
> -		  }
> -	    FoundNonType:
> -	      if (j < n_candidates)
> -		{
> -		  j = 0;
> -		  while (j < n_candidates)
> -		    {
> -		      if (SYMBOL_CLASS (candidates[j].symbol) == LOC_TYPEDEF)
> -			{
> -			  candidates[j] = candidates[n_candidates - 1];
> -			  n_candidates -= 1;
> -			}
> -		      else
> -			j += 1;
> -		    }
> -		}
> -	    }
> -
> -	  if (n_candidates == 0)
> -	    error (_("No definition found for %s"),
> -		   exp->elts[pc + 2].symbol->print_name ());
> -	  else if (n_candidates == 1)
> -	    i = 0;
> -	  else if (deprocedure_p
> -		   && !is_nonfunction (candidates.data (), n_candidates))
> -	    {
> -	      i = ada_resolve_function
> -		(candidates.data (), n_candidates, NULL, 0,
> -		 exp->elts[pc + 2].symbol->linkage_name (),
> -		 context_type, parse_completion);
> -	      if (i < 0)
> -		error (_("Could not find a match for %s"),
> -		       exp->elts[pc + 2].symbol->print_name ());
> -	    }
> -	  else
> -	    {
> -	      printf_filtered (_("Multiple matches for %s\n"),
> -			       exp->elts[pc + 2].symbol->print_name ());
> -	      user_select_syms (candidates.data (), n_candidates, 1);
> -	      i = 0;
> -	    }
> -
> -	  exp->elts[pc + 1].block = candidates[i].block;
> -	  exp->elts[pc + 2].symbol = candidates[i].symbol;
> -	  tracker->update (candidates[i]);
> +	  block_symbol resolved
> +	    = ada_resolve_variable (exp->elts[pc + 2].symbol,
> +				    exp->elts[pc + 1].block,
> +				    context_type, parse_completion,
> +				    deprocedure_p, tracker);
> +	  exp->elts[pc + 1].block = resolved.block;
> +	  exp->elts[pc + 2].symbol = resolved.symbol;
>  	}
>  
>        if (deprocedure_p
> @@ -3729,31 +3791,14 @@ resolve_subexp (expression_up *expp, int *pos, int deprocedure_p,
>  	if (exp->elts[pc + 3].opcode == OP_VAR_VALUE
>  	    && SYMBOL_DOMAIN (exp->elts[pc + 5].symbol) == UNDEF_DOMAIN)
>  	  {
> -	    std::vector<struct block_symbol> candidates;
> -	    int n_candidates;
> -
> -	    n_candidates =
> -	      ada_lookup_symbol_list (exp->elts[pc + 5].symbol->linkage_name (),
> -				      exp->elts[pc + 4].block, VAR_DOMAIN,
> -				      &candidates);
> -
> -	    if (n_candidates == 1)
> -	      i = 0;
> -	    else
> -	      {
> -		i = ada_resolve_function
> -		  (candidates.data (), n_candidates,
> -		   argvec, nargs,
> -		   exp->elts[pc + 5].symbol->linkage_name (),
> -		   context_type, parse_completion);
> -		if (i < 0)
> -		  error (_("Could not find a match for %s"),
> -			 exp->elts[pc + 5].symbol->print_name ());
> -	      }
> -
> -	    exp->elts[pc + 4].block = candidates[i].block;
> -	    exp->elts[pc + 5].symbol = candidates[i].symbol;
> -	    tracker->update (candidates[i]);
> +	    block_symbol resolved
> +	      = ada_resolve_funcall (exp->elts[pc + 5].symbol,
> +				     exp->elts[pc + 4].block,
> +				     context_type, parse_completion,
> +				     nargs, argvec,
> +				     tracker);
> +	    exp->elts[pc + 4].block = resolved.block;
> +	    exp->elts[pc + 5].symbol = resolved.symbol;
>  	  }
>        }
>        break;
> @@ -3778,27 +3823,16 @@ resolve_subexp (expression_up *expp, int *pos, int deprocedure_p,
>      case UNOP_PLUS:
>      case UNOP_LOGICAL_NOT:
>      case UNOP_ABS:
> -      if (possible_user_operator_p (op, argvec))
> -	{
> -	  std::vector<struct block_symbol> candidates;
> -	  int n_candidates;
> -
> -	  n_candidates =
> -	    ada_lookup_symbol_list (ada_decoded_op_name (op),
> -				    NULL, VAR_DOMAIN,
> -				    &candidates);
> -
> -	  i = ada_resolve_function (candidates.data (), n_candidates, argvec,
> -				    nargs, ada_decoded_op_name (op), NULL,
> -				    parse_completion);
> -	  if (i < 0)
> -	    break;
> +      {
> +	block_symbol found = ada_find_operator_symbol (op, parse_completion,
> +						       nargs, argvec);
> +	if (found.symbol == nullptr)
> +	  break;
>  
> -	  replace_operator_with_call (expp, pc, nargs, 1,
> -				      candidates[i].symbol,
> -				      candidates[i].block);
> -	  exp = expp->get ();
> -	}
> +	replace_operator_with_call (expp, pc, nargs, 1,
> +				    found.symbol, found.block);
> +	exp = expp->get ();
> +      }
>        break;
>  
>      case OP_TYPE:
> diff --git a/gdb/ada-lang.h b/gdb/ada-lang.h
> index dbf45a84928..8333def6280 100644
> --- a/gdb/ada-lang.h
> +++ b/gdb/ada-lang.h
> @@ -386,4 +386,22 @@ extern void print_ada_task_info (struct ui_out *uiout,
>  				 const char *taskno_str,
>  				 struct inferior *inf);
>  
> +extern block_symbol ada_find_operator_symbol (enum exp_opcode op,
> +					      int parse_completion,
> +					      int nargs, value *argvec[]);
> +
> +extern block_symbol ada_resolve_funcall (struct symbol *sym,
> +					 const struct block *block,
> +					 struct type *context_type,
> +					 int parse_completion,
> +					 int nargs, value *argvec[],
> +					 innermost_block_tracker *tracker);
> +
> +extern block_symbol ada_resolve_variable (struct symbol *sym,
> +					  const struct block *block,
> +					  struct type *context_type,
> +					  int parse_completion,
> +					  int deprocedure_p,
> +					  innermost_block_tracker *tracker);
> +
>  #endif
> -- 
> 2.26.2

-- 
Joel

^ permalink raw reply	[flat|nested] 225+ messages in thread

* Re: [PATCH 169/203] Implement Ada resolution
  2021-01-01 21:46 ` [PATCH 169/203] Implement Ada resolution Tom Tromey
@ 2021-01-03  7:57   ` Joel Brobecker
  2021-02-13 19:49     ` Tom Tromey
  0 siblings, 1 reply; 225+ messages in thread
From: Joel Brobecker @ 2021-01-03  7:57 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

Hi Tom,

Just a tiny question below...

On Fri, Jan 01, 2021 at 02:46:49PM -0700, Tom Tromey wrote:
> Ada has a parser post-pass that implements "resolution".  This process
> replaces some opcodes with function calls.  For example, a "+"
> operation might be replaced with a call to the appropriate overloaded
> function.
> 
> This differs from the approach taken for the same problem in C++.
> However, in this series I chose not to try to make changes outside of
> rewrite the expression data structure.  So, resolution remains.
> 
> The new approach to resolution is to introduce an interface class,
> that some concrete operations implement.  Then, the Ada code will use
> this to resolve the expression tree.  Because new-style expressions
> are built as ordinary objects, and don't require rewriting the data
> structure in place, in the new code this processing will be done in
> the parser.  By the end of the series, some special cases in this area
> that exist only for Ada will be removed.
> 
> gdb/ChangeLog
> 2021-01-01  Tom Tromey  <tom@tromey.com>
> 
> 	* ada-lang.c (ada_var_value_operation::resolve)
> 	(ada_funcall_operation::resolve): New methods.
> 	* ada-exp.h (struct ada_resolvable): New.
> 	(class ada_var_value_operation): Derive from ada_resolvable.
> 	<get_block, resolve>: New methods.
> 	(class ada_funcall_operation): Derive from ada_resolvable.
> 	<resolve>: New method.
> ---
>  gdb/ChangeLog  | 10 ++++++++
>  gdb/ada-exp.h  | 38 ++++++++++++++++++++++++++++--
>  gdb/ada-lang.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 109 insertions(+), 2 deletions(-)
> 
> diff --git a/gdb/ada-exp.h b/gdb/ada-exp.h
> index 287ed5cc62c..2c5696cab76 100644
> --- a/gdb/ada-exp.h
> +++ b/gdb/ada-exp.h
> @@ -304,9 +304,27 @@ class ada_unop_atr_operation
>    { return std::get<1> (m_storage); }
>  };
>  
> +/* The base class for Ada type resolution.  Ada operations that want
> +   to participate in resolution implement this interface.  */
> +struct ada_resolvable
> +{
> +  /* Resolve this object.  EXP is the expression being resolved.
> +     DEPROCEDURE_P is true if de-proceduring is desired.

What does it mean "de-proceduring is desired"?

> +     PARSE_COMPLETION and TRACKER are passed in from the parser
> +     context.  CONTEXT_TYPE is the expected type of the expression, or
> +     nullptr if none is known.  This method should return true if the
> +     operation should be replaced by a function call with this object
> +     as the callee.  */

-- 
Joel

^ permalink raw reply	[flat|nested] 225+ messages in thread

* Re: [PATCH 073/203] Introduce class operation
  2021-01-03  7:09   ` Joel Brobecker
@ 2021-01-03 13:55     ` Lancelot SIX
  2021-02-10  0:57       ` Tom Tromey
  0 siblings, 1 reply; 225+ messages in thread
From: Lancelot SIX @ 2021-01-03 13:55 UTC (permalink / raw)
  To: Joel Brobecker, Tom Tromey; +Cc: gdb-patches

Hi everyone

On 03/01/2021 07:09, Joel Brobecker wrote:
> Hi Tom,
>
>> 	* ax-gdb.c (operation::generate_ax): New method.
> Thanks for this!
>
> I don't have much comment to share on this, at least not just yet
> until I have had a chance to see this new API in action in the rest
> of the patch series. I do have one small-tiny-mini suggestion:
>
> It's about:
>
>> +typedef std::unique_ptr<operation> operation_up;
> FWIW, the connection between "up" and the rest of the declaration
> wasn't immediately obvious to me. I think this is because "up"
> is an english word, and spelled like that, all in lowercase,
> that's really what my brain keeps analyzing it as first. It takes
> an effort to adjust my thinking against this bias.
>
> It's not a problem for me if we decide to keep this like that,
> but what do you think about about renaming this to something like
> "operation_uptr"? I think it'll make the intention more immediately
> clear to the reader.
>
I am fairly new to this codebase, but as far as I can say, this sort of 
naming convention (the _up suffix for a typedefed std::unique_ptr) is 
already used here and there:

$ git grep 'typedef std::unique_ptr.*_up;'|wc -l
33

I have to admin that the first time I came across it it was not obvious 
to me either, but it would make sense to keep it this way for 
consistency (I guess).

BR
Lancelot.


^ permalink raw reply	[flat|nested] 225+ messages in thread

* Re: [PATCH 003/203] Split out eval_op_var_msym_value
  2021-01-01 21:44 ` [PATCH 003/203] Split out eval_op_var_msym_value Tom Tromey
@ 2021-01-04 11:43   ` Andrew Burgess
  2021-02-13 19:37     ` Tom Tromey
  0 siblings, 1 reply; 225+ messages in thread
From: Andrew Burgess @ 2021-01-04 11:43 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

* Tom Tromey <tom@tromey.com> [2021-01-01 14:44:03 -0700]:

> This splits OP_VAR_MSYM_VALUE into a new function for future use.
> 
> gdb/ChangeLog
> 2021-01-01  Tom Tromey  <tom@tromey.com>
> 
> 	* eval.c (eval_op_var_msym_value): New function.
> 	(evaluate_subexp_standard): Use it.
> ---
>  gdb/ChangeLog |  5 +++++
>  gdb/eval.c    | 26 +++++++++++++++++---------
>  2 files changed, 22 insertions(+), 9 deletions(-)
> 
> diff --git a/gdb/eval.c b/gdb/eval.c
> index 745333d31f9..e896baa3dec 100644
> --- a/gdb/eval.c
> +++ b/gdb/eval.c
> @@ -1215,6 +1215,20 @@ eval_op_var_entry_value (struct type *expect_type, struct expression *exp,
>    return SYMBOL_COMPUTED_OPS (sym)->read_variable_at_entry (sym, frame);
>  }
>  
> +static struct value *
> +eval_op_var_msym_value (struct type *expect_type, struct expression *exp,
> +			enum noside noside,
> +			minimal_symbol *msymbol, struct objfile *objfile)

The first couple of patches included a header comment for these new
helper functions.  Starting from this patch these header comments are
hit and miss.

Maybe these should be added?  I haven't commented on each patch where
this is an issue, that didn't feel very helpful.

Thanks,
Andrew



> +{
> +  value *val = evaluate_var_msym_value (noside, objfile, msymbol);
> +
> +  struct type *type = value_type (val);
> +  if (type->code () == TYPE_CODE_ERROR
> +      && (noside != EVAL_AVOID_SIDE_EFFECTS || pc != 0))
> +    error_unknown_type (msymbol->print_name ());
> +  return val;
> +}
> +
>  struct value *
>  evaluate_subexp_standard (struct type *expect_type,
>  			  struct expression *exp, int *pos,
> @@ -1277,15 +1291,9 @@ evaluate_subexp_standard (struct type *expect_type,
>  	(*pos) += 3;
>  
>  	minimal_symbol *msymbol = exp->elts[pc + 2].msymbol;
> -	value *val = evaluate_var_msym_value (noside,
> -					      exp->elts[pc + 1].objfile,
> -					      msymbol);
> -
> -	type = value_type (val);
> -	if (type->code () == TYPE_CODE_ERROR
> -	    && (noside != EVAL_AVOID_SIDE_EFFECTS || pc != 0))
> -	  error_unknown_type (msymbol->print_name ());
> -	return val;
> +	return eval_op_var_msym_value (expect_type, exp, noside,
> +				       msymbol,
> +				       exp->elts[pc + 1].objfile);
>        }
>  
>      case OP_VAR_ENTRY_VALUE:
> -- 
> 2.26.2
> 

^ permalink raw reply	[flat|nested] 225+ messages in thread

* Re: [PATCH 052/203] Split out eval_op_m2_high
  2021-01-01 21:44 ` [PATCH 052/203] Split out eval_op_m2_high Tom Tromey
@ 2021-01-04 12:05   ` Andrew Burgess
  2021-02-10  0:56     ` Tom Tromey
  0 siblings, 1 reply; 225+ messages in thread
From: Andrew Burgess @ 2021-01-04 12:05 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

* Tom Tromey <tom@tromey.com> [2021-01-01 14:44:52 -0700]:

> This splits UNOP_HIGH into a new function for future use.
> 
> gdb/ChangeLog
> 2021-01-01  Tom Tromey  <tom@tromey.com>
> 
> 	* m2-lang.c (eval_op_m2_high): New function.
> 	(evaluate_subexp_modula2): Use it.
> ---
>  gdb/ChangeLog |  5 +++++
>  gdb/m2-lang.c | 55 ++++++++++++++++++++++++++++++---------------------
>  2 files changed, 37 insertions(+), 23 deletions(-)
> 
> diff --git a/gdb/m2-lang.c b/gdb/m2-lang.c
> index fb49ba470d6..982bc264a3b 100644
> --- a/gdb/m2-lang.c
> +++ b/gdb/m2-lang.c
> @@ -29,6 +29,37 @@
>  #include "valprint.h"
>  #include "gdbarch.h"
>  
> +/* A helper function for UNOP_HIGH.  */
> +
> +static struct value *
> +eval_op_m2_high (struct type *expect_type, struct expression *exp,
> +		 enum noside noside,
> +		 struct value *arg1)
> +{
> +  if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS)
> +    return arg1;
> +  else
> +    {
> +      arg1 = coerce_ref (arg1);
> +      struct type *type = check_typedef (value_type (arg1));
> +
> +      if (m2_is_unbounded_array (type))
> +	{
> +	  struct value *temp = arg1;
> +
> +	  type = type->field (1).type ();
> +	  /* i18n: Do not translate the "_m2_high" part!  */
> +	  arg1 = value_struct_elt (&temp, NULL, "_m2_high", NULL,
> +				   _("unbounded structure "
> +				     "missing _m2_high field"));
> +	  

Not your mistake (copied code), but there's an unneeded tab at the end
of the previous otherwise empty line.  Maybe you could clean this up?

Thanks,
Andrew

> +	  if (value_type (arg1) != type)
> +	    arg1 = value_cast (type, arg1);
> +	}
> +    }
> +  return arg1;
> +}
> +
>  static struct value *
>  evaluate_subexp_modula2 (struct type *expect_type, struct expression *exp,
>  			 int *pos, enum noside noside)
> @@ -43,29 +74,7 @@ evaluate_subexp_modula2 (struct type *expect_type, struct expression *exp,
>      case UNOP_HIGH:
>        (*pos)++;
>        arg1 = evaluate_subexp_with_coercion (exp, pos, noside);
> -
> -      if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS)
> -	return arg1;
> -      else
> -	{
> -	  arg1 = coerce_ref (arg1);
> -	  type = check_typedef (value_type (arg1));
> -
> -	  if (m2_is_unbounded_array (type))
> -	    {
> -	      struct value *temp = arg1;
> -
> -	      type = type->field (1).type ();
> -	      /* i18n: Do not translate the "_m2_high" part!  */
> -	      arg1 = value_struct_elt (&temp, NULL, "_m2_high", NULL,
> -				       _("unbounded structure "
> -					 "missing _m2_high field"));
> -	  
> -	      if (value_type (arg1) != type)
> -		arg1 = value_cast (type, arg1);
> -	    }
> -	}
> -      return arg1;
> +      return eval_op_m2_high (expect_type, exp, noside, arg1);
>  
>      case BINOP_SUBSCRIPT:
>        (*pos)++;
> -- 
> 2.26.2
> 

^ permalink raw reply	[flat|nested] 225+ messages in thread

* Re: [PATCH 000/203] Refactor expressions
  2021-01-03  7:02 ` [PATCH 000/203] Refactor expressions Joel Brobecker
@ 2021-01-04 12:16   ` Andrew Burgess
  2021-02-13 19:54   ` Tom Tromey
  1 sibling, 0 replies; 225+ messages in thread
From: Andrew Burgess @ 2021-01-04 12:16 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: Tom Tromey, gdb-patches

* Joel Brobecker <brobecker@adacore.com> [2021-01-03 11:02:50 +0400]:

> Hi Tom,
> 
> On Fri, Jan 01, 2021 at 02:44:00PM -0700, Tom Tromey wrote:
> > I have long thought that struct expression is the worst data structure
> > in GDB.  In fact, I've sometimes told people it is the worst data
> > structure I've encountered in my career.  I've wanted to rewrite it
> > for many years, and this year I finally found a workable plan and the
> > motivation to do so.  This series is the result.
> 
> Thanks for the (mega) series!
> 
> Because of the length of the series, I think it's going to be potentially
> more difficult for you to maintain it over time. I so I think it would
> be nice if we could put a priority on its review.
> 
> I've now started with part 1:
> 
> > 1. Split functions out from the evaluators.
> > 
> >    Each evaluator function is fairly long, and mixes knowledge about
> >    the structure of the expression (how the exp_elements are laid out)
> >    with knowledge of the semantics of the operation.
> > 
> >    This part of the series, which is about 70 patches, splits out the
> >    semantics of most operations into their own functions.  These
> >    functions can be then be reused -- which is helpful for ensuring
> >    that changes don't sneak in.
> > 
> >    In this part of the series, sometimes the newly-introduced
> >    functions have extraneous arguments.  This was done partly so that
> >    some could be reused by generic code in part 2; but also partly
> >    because it was just simpler to write patches by rote.
> 
> Aside from the commit "what is this code for", I think this part
> of the series is a nice improvement on its own. independently
> of redesigning struct expression, I've always found the evaluator
> functions to be overly long and harder to navigate as a result.
> So I think it could go in ahead of the rest if we agree that
> this part is good.
> 
> For me, I've gone through the patches, more or less carefully
> based on a random sample, and they look good. I paused a bit
> about the Ada ones, were you excluded the hanlding of noside ==
> EVAL_SKIP. I'm not entirely sure why that is, perhaps because
> the block consists in a goto nosideret? Looking at what that
> nosideret does, it's just...
> 
>     | nosideret:
>     |   return eval_skip_value (exp);
> 
> ... so we could inline this in the new functions.
> 
> However, this is really a very minor detail that doesn't need to be
> addressed here.
> 
> So, to summarize, if others agree, I'm happy for this part of
> the series to go in.

I agree with this.  I looked through all the patches 001 -> 072.
There's a few missing comments that I think should be added, and I
would suggest dropping the "what is this code for" patch (if this
needs looking at it can be a separate branch), but otherwise this
first set would be a good improvement on its own and worth merging
sooner rather than later I think.

Thanks,
Andrew



> 
> > 
> > 2. Introduce 'class operation' and its subclasses.
> > 
> >    This sub-series is around 100 patches.  It introduces the new base
> >    class for an expression operation, and then proceeds to add
> >    operations for every necessary opcode.  In some cases multiple such
> >    operations are needed -- for example when multiple languages
> >    implement an opcode in different ways.
> > 
> >    Some discussion of the design & tradeoffs appear in the "Introduce
> >    class operation" patch.
> > 
> > 3. Convert existing code to use operations.
> > 
> >    This is a short sub-series of around 10 patches.  Each parser is
> >    converted separately, as are DTrace and SystemTap probes
> > 
> > 4. Delete obsolete code.
> > 
> >    The final 20 patches or so are concerned with removing all the code
> >    that is now obsolete, and with doing some minor tidying of the
> >    result.
> > 
> > The overall approach here is to replace the current data structure --
> > but only the data structure.  I didn't generally try to clean up
> > things that seemed a bit weird.
> > 
> > I also didn't try to add new features, like async evaluation.  After
> > starting the project, I felt that trying to combine this refactoring
> > with another, different one would be too difficult.
> > 
> > This is all on the branch t/expression-rewrite-incr in my github.
> > 
> > Regression tested on x86-64 Fedora 32.  I also built it on PPC Linux
> > to ensure that the ppc-linux-nat.c changes would build.
> > 
> > Tom
> > 
> 
> -- 
> Joel

^ permalink raw reply	[flat|nested] 225+ messages in thread

* Re: [PATCH 136/203] Add two simple Modula-2 operations
  2021-01-01 21:46 ` [PATCH 136/203] Add two simple Modula-2 operations Tom Tromey
@ 2021-01-07 15:16   ` Gaius Mulley
  0 siblings, 0 replies; 225+ messages in thread
From: Gaius Mulley @ 2021-01-07 15:16 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

Tom Tromey <tom@tromey.com> writes:

> This adds a couple of simple Modula-2 operations.
>
> gdb/ChangeLog
> 2021-01-01  Tom Tromey  <tom@tromey.com>
>
>         * m2-lang.c (eval_op_m2_high, eval_op_m2_subscript): No longer
>         static.
>         * m2-exp.h: New file.
> ---
>  gdb/ChangeLog |  6 ++++
>  gdb/m2-exp.h  | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  gdb/m2-lang.c |  5 +--
>  3 files changed, 93 insertions(+), 2 deletions(-)
>  create mode 100644 gdb/m2-exp.h
>
> diff --git a/gdb/m2-exp.h b/gdb/m2-exp.h
> new file mode 100644
> index 00000000000..e034963a9a6
> --- /dev/null
> +++ b/gdb/m2-exp.h
> @@ -0,0 +1,84 @@
> +/* Definitions for Modula-2 expressions
> +
> +   Copyright (C) 2020 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 M2_EXP_H
> +#define M2_EXP_H
> +
> +#include "expop.h"
> +
> +extern struct value *eval_op_m2_high (struct type *expect_type,
> +                                     struct expression *exp,
> +                                     enum noside noside,
> +                                     struct value *arg1);
> +extern struct value *eval_op_m2_subscript (struct type *expect_type,
> +                                          struct expression *exp,
> +                                          enum noside noside,
> +                                          struct value *arg1,
> +                                          struct value *arg2);
> +
> +namespace expr
> +{
> +
> +/* The Modula-2 "HIGH" operation.  */
> +class m2_unop_high_operation
> +  : public tuple_holding_operation<operation_up>
> +{
> +public:
> +
> +  using tuple_holding_operation::tuple_holding_operation;
> +
> +  value *evaluate (struct type *expect_type,
> +                  struct expression *exp,
> +                  enum noside noside) override
> +  {
> +    value *arg1 = std::get<0> (m_storage)->evaluate_with_coercion (exp,
> +                                                                  noside);
> +    return eval_op_m2_high (expect_type, exp, noside, arg1);
> +  }
> +
> +  enum exp_opcode opcode () const override
> +  { return UNOP_HIGH; }
> +};
> +
> +/* Subscripting for Modula-2.  */
> +class m2_binop_subscript_operation
> +  : public tuple_holding_operation<operation_up, operation_up>
> +{
> +public:
> +
> +  using tuple_holding_operation::tuple_holding_operation;
> +
> +  value *evaluate (struct type *expect_type,
> +                  struct expression *exp,
> +                  enum noside noside) override
> +  {
> +    value *arg1 = std::get<0> (m_storage)->evaluate_with_coercion (exp,
> +                                                                  noside);
> +    value *arg2 = std::get<1> (m_storage)->evaluate_with_coercion (exp,
> +                                                                  noside);
> +    return eval_op_m2_subscript (expect_type, exp, noside, arg1, arg2);
> +  }
> +
> +  enum exp_opcode opcode () const override
> +  { return BINOP_SUBSCRIPT; }
> +};
> +
> +} /* namespace expr */
> +
> +#endif /* M2_EXP_H */
> diff --git a/gdb/m2-lang.c b/gdb/m2-lang.c
> index f5e80eee9c6..60d373ec2b9 100644
> --- a/gdb/m2-lang.c
> +++ b/gdb/m2-lang.c
> @@ -28,10 +28,11 @@
>  #include "c-lang.h"
>  #include "valprint.h"
>  #include "gdbarch.h"
> +#include "m2-exp.h"
>
>  /* A helper function for UNOP_HIGH.  */
>
> -static struct value *
> +struct value *
>  eval_op_m2_high (struct type *expect_type, struct expression *exp,
>                  enum noside noside,
>                  struct value *arg1)
> @@ -62,7 +63,7 @@ eval_op_m2_high (struct type *expect_type, struct expression *exp,
>
>  /* A helper function for BINOP_SUBSCRIPT.  */
>
> -static struct value *
> +struct value *
>  eval_op_m2_subscript (struct type *expect_type, struct expression *exp,
>                       enum noside noside,
>                       struct value *arg1, struct value *arg2)
> --
> 2.26.2

thanks Tom for all the work keeping this up to date - all looks great!


regards,
Gaius

^ permalink raw reply	[flat|nested] 225+ messages in thread

* Re: [PATCH 009/203] what is this code for
  2021-01-03  6:00   ` Joel Brobecker
@ 2021-01-25  2:28     ` Simon Marchi
  2021-01-25  3:27       ` Tom Tromey
  2021-02-11  2:25       ` Tom Tromey
  0 siblings, 2 replies; 225+ messages in thread
From: Simon Marchi @ 2021-01-25  2:28 UTC (permalink / raw)
  To: Joel Brobecker, Tom Tromey; +Cc: gdb-patches

On 2021-01-03 1:00 a.m., Joel Brobecker wrote:
> Hi Tom,
> 
>> @@ -1224,7 +1224,7 @@ eval_op_var_msym_value (struct type *expect_type, struct expression *exp,
>>  
>>    struct type *type = value_type (val);
>>    if (type->code () == TYPE_CODE_ERROR
>> -      && (noside != EVAL_AVOID_SIDE_EFFECTS || pc != 0))
>> +      && (noside != EVAL_AVOID_SIDE_EFFECTS))
>>      error_unknown_type (msymbol->print_name ());
>>    return val;
> 
> I tracked the origin of this code down to the following commit...
> 
>     commit 46a4882b3c7d9ec981568b8b13a3c9c39c8f8e61
>     Author: Pedro Alves <palves@redhat.com>
>     Date:   Mon Sep 4 20:21:15 2017 +0100
>     Subject: Stop assuming no-debug-info variables have type int
> 
> ... which was the second stage of a similar change for functions.
> The revision log did not really give an explicit explanation for
> this code, but after a bit of thinking, I think I was able to
> figure it out.
> 
> Consider the case where you're trying to investigate a variable
> called "opaque" which is declared in the symbol table but does not
> have any debug info.
> 
>   * If noside != EVAL_AVOID_SIDE_EFFECTS (typically, we're trying
>     to print the value, then we always error out with:
> 
>         | 'opaque' has unknown type; cast it to its declared type
> 
>     ... This is what the patch is about. That's not what you are
>     asking about, because it's easy to understand. OK.
> 
>   * So, if noside == EVAL_AVOID_SIDE_EFFECTS, what does it mean
>     to only print the error message above if pc != 0?
> 
>     Well, if pc == 0, it means OP_VAR_MSYM_VALUE node is first,
>     and since that operator doesn't have any "parameters", what
>     it means to me is that it must actually be the only operand
>     of the expression. Thus, we must be facing the following
>     situation:
> 
>         | (gdb) ptype opaque
> 
>     And what do we do in that scenario? Well, we have code in gdbtype.c
>     which gives default types for the various kinds of minimal symbols.
>     For data symbols, it looks like this:
> 
>         | objfile_type->nodebug_data_symbol
>         |   = init_nodebug_var_type (objfile, "<data variable, no debug info>");
> 
>     So, when we do a ptype, we don't get an error, but instead, get
>     some information about the symbol:
> 
>         | (gdb) ptype opaque
>         | type = <data variable, no debug info>
> 
> 
>     If, on the other hand pc != 0, it means our minsym is part
>     of a larger expression, such as, for instance "opaque + 1".
>     With today's GDB, a "ptype" of the expression above generates
>     the same error message when when in EVAL_NORMAL mode:
> 
>         | (gdb) ptype opaque + 1
>         | 'opaque' has unknown type; cast it to its declared type
> 
>     If you remove the check above, then we no longer trigger
>     the "has unknown type" error. So, instead, we just evaluate
>     the minsym as is, which means we get a value whose type is
>     the type of "objfile_type->nodebug_data_symbol", in other words
>     TYPE_CODE_ERROR, which leads to:
> 
>         | (gdb) ptype opaque + 1
>         | Argument to arithmetic operation not a number or boolean.
> 
>     For minimal symbols which are text symbols, these get a default
>     type of TYPE_CODE_FUNC, so removing the above breaks the check
>     which forces the user to specify the return type.
> 
> We should probably add a test or two in gdb.base/nodebug.exp for that...
> 

In addition to this good explanation: I tried removing the `|| pc == 0`
from the code (based on current master) and got these failures:

+FAIL: gdb.base/nodebug.exp: p sizeof(dataglobal + 1)
+FAIL: gdb.base/nodebug.exp: ptype *dataglobal
+FAIL: gdb.base/nodebug.exp: ptype dataglobal + 1
+FAIL: gdb.base/nodebug.exp: ptype sizeof(dataglobal + 1)
+FAIL: gdb.base/nodebug.exp: whatis *dataglobal
+FAIL: gdb.base/nodebug.exp: whatis dataglobal + 1
+FAIL: gdb.base/nodebug.exp: whatis sizeof(dataglobal + 1)

So it's already covered.  Tom, are these cases correctly handled with
this series applied?

Simon

^ permalink raw reply	[flat|nested] 225+ messages in thread

* Re: [PATCH 009/203] what is this code for
  2021-01-25  2:28     ` Simon Marchi
@ 2021-01-25  3:27       ` Tom Tromey
  2021-02-11  2:25       ` Tom Tromey
  1 sibling, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-01-25  3:27 UTC (permalink / raw)
  To: Simon Marchi; +Cc: Joel Brobecker, Tom Tromey, gdb-patches

Simon> So it's already covered.  Tom, are these cases correctly handled with
Simon> this series applied?

I regression-tested it and compared and it passed; however I don't think
this is explicitly handled, so I suspect that the comparison was wrong.
Maybe this will need a new method on operation to be handled correctly.
I'll take a look when I rebase the series and fix up the other comments.

Tom

^ permalink raw reply	[flat|nested] 225+ messages in thread

* Re: [PATCH 052/203] Split out eval_op_m2_high
  2021-01-04 12:05   ` Andrew Burgess
@ 2021-02-10  0:56     ` Tom Tromey
  0 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-02-10  0:56 UTC (permalink / raw)
  To: Andrew Burgess; +Cc: Tom Tromey, gdb-patches

>>>>> "Andrew" == Andrew Burgess <andrew.burgess@embecosm.com> writes:

>> +	  struct value *temp = arg1;
>> +
>> +	  type = type->field (1).type ();
>> +	  /* i18n: Do not translate the "_m2_high" part!  */
>> +	  arg1 = value_struct_elt (&temp, NULL, "_m2_high", NULL,
>> +				   _("unbounded structure "
>> +				     "missing _m2_high field"));
>> +	  

Andrew> Not your mistake (copied code), but there's an unneeded tab at the end
Andrew> of the previous otherwise empty line.  Maybe you could clean this up?

I've fixed this.

Tom

^ permalink raw reply	[flat|nested] 225+ messages in thread

* Re: [PATCH 073/203] Introduce class operation
  2021-01-03 13:55     ` Lancelot SIX
@ 2021-02-10  0:57       ` Tom Tromey
  0 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-02-10  0:57 UTC (permalink / raw)
  To: Lancelot SIX via Gdb-patches; +Cc: Joel Brobecker, Tom Tromey, Lancelot SIX

>>> +typedef std::unique_ptr<operation> operation_up;

>> FWIW, the connection between "up" and the rest of the declaration
>> wasn't immediately obvious to me. I think this is because "up"
>> is an english word, and spelled like that, all in lowercase,
>> that's really what my brain keeps analyzing it as first. It takes
>> an effort to adjust my thinking against this bias.

Lancelot> I am fairly new to this codebase, but as far as I can say, this sort
Lancelot> of naming convention (the _up suffix for a typedefed std::unique_ptr)
Lancelot> is already used here and there:

Lancelot> $ git grep 'typedef std::unique_ptr.*_up;'|wc -l
Lancelot> 33

Lancelot> I have to admin that the first time I came across it it was not
Lancelot> obvious to me either, but it would make sense to keep it this way for
Lancelot> consistency (I guess).

Yeah, IIRC the "_up" suffix (for "unique pointer") was introduced a
while back by Pedro; this is just following the existing naming
convention.

Tom

^ permalink raw reply	[flat|nested] 225+ messages in thread

* Re: [PATCH 009/203] what is this code for
  2021-01-25  2:28     ` Simon Marchi
  2021-01-25  3:27       ` Tom Tromey
@ 2021-02-11  2:25       ` Tom Tromey
  2021-02-13 19:37         ` Tom Tromey
  1 sibling, 1 reply; 225+ messages in thread
From: Tom Tromey @ 2021-02-11  2:25 UTC (permalink / raw)
  To: Simon Marchi; +Cc: Joel Brobecker, Tom Tromey, gdb-patches

>>>>> "Simon" == Simon Marchi <simon.marchi@polymtl.ca> writes:

Simon> In addition to this good explanation: I tried removing the `|| pc == 0`
Simon> from the code (based on current master) and got these failures:

Simon> +FAIL: gdb.base/nodebug.exp: p sizeof(dataglobal + 1)
Simon> +FAIL: gdb.base/nodebug.exp: ptype *dataglobal
Simon> +FAIL: gdb.base/nodebug.exp: ptype dataglobal + 1
Simon> +FAIL: gdb.base/nodebug.exp: ptype sizeof(dataglobal + 1)
Simon> +FAIL: gdb.base/nodebug.exp: whatis *dataglobal
Simon> +FAIL: gdb.base/nodebug.exp: whatis dataglobal + 1
Simon> +FAIL: gdb.base/nodebug.exp: whatis sizeof(dataglobal + 1)

Simon> So it's already covered.  Tom, are these cases correctly handled with
Simon> this series applied?

It wasn't, which I don't understand, since I regression tested this.
I wonder if the comparison script I am using is buggy.

Anyway, I have reimplemented this feature in the new version of the
series, these tests work now.  There's one more failure in nodebug.exp
that I have yet to track down - in one case, the error message has
changed.

Tom

^ permalink raw reply	[flat|nested] 225+ messages in thread

* Re: [PATCH 003/203] Split out eval_op_var_msym_value
  2021-01-04 11:43   ` Andrew Burgess
@ 2021-02-13 19:37     ` Tom Tromey
  0 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-02-13 19:37 UTC (permalink / raw)
  To: Andrew Burgess; +Cc: Tom Tromey, gdb-patches

>>>>> "Andrew" == Andrew Burgess <andrew.burgess@embecosm.com> writes:

>> 
>> +static struct value *
>> +eval_op_var_msym_value (struct type *expect_type, struct expression *exp,
>> +			enum noside noside,
>> +			minimal_symbol *msymbol, struct objfile *objfile)

Andrew> The first couple of patches included a header comment for these new
Andrew> helper functions.  Starting from this patch these header comments are
Andrew> hit and miss.

Andrew> Maybe these should be added?  I haven't commented on each patch where
Andrew> this is an issue, that didn't feel very helpful.

I went through the "Split" patches and I've added comments where they
were missing.

Tom

^ permalink raw reply	[flat|nested] 225+ messages in thread

* Re: [PATCH 009/203] what is this code for
  2021-02-11  2:25       ` Tom Tromey
@ 2021-02-13 19:37         ` Tom Tromey
  0 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-02-13 19:37 UTC (permalink / raw)
  To: Tom Tromey; +Cc: Simon Marchi, gdb-patches, Joel Brobecker

>>>>> "Tom" == Tom Tromey <tom@tromey.com> writes:

Tom> There's one more failure in nodebug.exp
Tom> that I have yet to track down - in one case, the error message has
Tom> changed.

I've fixed this now as well.

Tom

^ permalink raw reply	[flat|nested] 225+ messages in thread

* Re: [PATCH 151/203] Split out some Ada type resolution code
  2021-01-03  7:46   ` Joel Brobecker
@ 2021-02-13 19:47     ` Tom Tromey
  0 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-02-13 19:47 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: Tom Tromey, gdb-patches

>>>>> "Joel" == Joel Brobecker <brobecker@adacore.com> writes:

Joel> Hi Tom,
Joel> On Fri, Jan 01, 2021 at 02:46:31PM -0700, Tom Tromey wrote:
>> This splits some Ada type resolution code out of resolve_subexp into
>> new functions that can be reused.
>> 
>> gdb/ChangeLog
>> 2021-01-01  Tom Tromey  <tom@tromey.com>
>> 
>> * ada-lang.h (ada_find_operator_symbol, ada_resolve_funcall)
>> (ada_resolve_variable): Declare.
>> * ada-lang.c (ada_find_operator_symbol, ada_resolve_funcall)
>> (ada_resolve_variable): New functions.
>> (resolve_subexp): Update.

Joel> Could this patch go in early, and independently of this patch series
Joel> (or perhaps right after the first third of the patches splitting
Joel> the various eval routines go in)?

It could but it's simpler for me to keep the series as-is.

Joel> As far as I can tell, all it needs is documentation of the new routines
Joel> in ada-lang.h. Other than that, this patch looks like a nice little
Joel> improvement of the code's organization.

I've added some comments.

Tom

^ permalink raw reply	[flat|nested] 225+ messages in thread

* Re: [PATCH 169/203] Implement Ada resolution
  2021-01-03  7:57   ` Joel Brobecker
@ 2021-02-13 19:49     ` Tom Tromey
  0 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-02-13 19:49 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: Tom Tromey, gdb-patches

>> +  /* Resolve this object.  EXP is the expression being resolved.
>> +     DEPROCEDURE_P is true if de-proceduring is desired.

Joel> What does it mean "de-proceduring is desired"?

I've updated the comment.  My understanding is that this refers to
transforming a reference to a symbol into a function call, if the symbol
names a zero-argument function.

Tom

^ permalink raw reply	[flat|nested] 225+ messages in thread

* Re: [PATCH 000/203] Refactor expressions
  2021-01-03  7:02 ` [PATCH 000/203] Refactor expressions Joel Brobecker
  2021-01-04 12:16   ` Andrew Burgess
@ 2021-02-13 19:54   ` Tom Tromey
  2021-02-16 16:17     ` Tom Tromey
  1 sibling, 1 reply; 225+ messages in thread
From: Tom Tromey @ 2021-02-13 19:54 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: Tom Tromey, gdb-patches

>>>>> "Joel" == Joel Brobecker <brobecker@adacore.com> writes:

Joel> For me, I've gone through the patches, more or less carefully
Joel> based on a random sample, and they look good. I paused a bit
Joel> about the Ada ones, were you excluded the hanlding of noside ==
Joel> EVAL_SKIP. I'm not entirely sure why that is, perhaps because
Joel> the block consists in a goto nosideret? Looking at what that
Joel> nosideret does, it's just...

Joel>     | nosideret:
Joel>     |   return eval_skip_value (exp);

Joel> ... so we could inline this in the new functions.

There's no need for EVAL_SKIP in the new code.  This was just an
artifact of how the expression objects were laid out in memory.

It's possible that this series has intermediate states that fail in some
way.  I didn't test every patch in isolation.  I suppose I should do
that, I have just been avoiding it since on my home machine, a test run
is ~15 minutes, which works out to 50 hours for this series.

I'm ready to send v2 of the series.  I think I'll save the individual
regression test and fixes for v3.

Tom

^ permalink raw reply	[flat|nested] 225+ messages in thread

* Re: [PATCH 000/203] Refactor expressions
  2021-02-13 19:54   ` Tom Tromey
@ 2021-02-16 16:17     ` Tom Tromey
  0 siblings, 0 replies; 225+ messages in thread
From: Tom Tromey @ 2021-02-16 16:17 UTC (permalink / raw)
  To: Tom Tromey; +Cc: Joel Brobecker, gdb-patches

>>>>> "Tom" == Tom Tromey <tom@tromey.com> writes:

Tom> I'm ready to send v2 of the series.  I think I'll save the individual
Tom> regression test and fixes for v3.

I wrote a script to check out each version, build it, and
regression-test it.  Then I let it run for a couple of days.

It found a few patches that did not build.  Those were all patches where
some hunk was misplaced into a later patch -- nothing serious, just
stuff like missing #includes.  I've fixed all these problems on my
branch.

It also found that there are patches that introduce regressions.  I
haven't looked into those yet.  They occur near the end of the series,
which is both (a) good and (b) expected, since the early parts of the
series are pretty innocuous.

I'll dig through these before sending v3.

Tom

^ permalink raw reply	[flat|nested] 225+ messages in thread

end of thread, other threads:[~2021-02-16 16:17 UTC | newest]

Thread overview: 225+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-01-01 21:44 [PATCH 000/203] Refactor expressions Tom Tromey
2021-01-01 21:44 ` [PATCH 001/203] Split out eval_op_scope Tom Tromey
2021-01-01 21:44 ` [PATCH 002/203] Split out eval_op_var_entry_value Tom Tromey
2021-01-01 21:44 ` [PATCH 003/203] Split out eval_op_var_msym_value Tom Tromey
2021-01-04 11:43   ` Andrew Burgess
2021-02-13 19:37     ` Tom Tromey
2021-01-01 21:44 ` [PATCH 004/203] Split out eval_op_func_static_var Tom Tromey
2021-01-01 21:44 ` [PATCH 005/203] Split out eval_op_register Tom Tromey
2021-01-01 21:44 ` [PATCH 006/203] Split out eval_op_string Tom Tromey
2021-01-01 21:44 ` [PATCH 007/203] Split out eval_op_objc_selector Tom Tromey
2021-01-01 21:44 ` [PATCH 008/203] Split out eval_op_concat Tom Tromey
2021-01-01 21:44 ` [PATCH 009/203] what is this code for Tom Tromey
2021-01-03  6:00   ` Joel Brobecker
2021-01-25  2:28     ` Simon Marchi
2021-01-25  3:27       ` Tom Tromey
2021-02-11  2:25       ` Tom Tromey
2021-02-13 19:37         ` Tom Tromey
2021-01-01 21:44 ` [PATCH 010/203] Split out eval_op_ternop Tom Tromey
2021-01-01 21:44 ` [PATCH 011/203] Split out eval_op_structop_struct Tom Tromey
2021-01-01 21:44 ` [PATCH 012/203] Split out eval_op_structop_ptr Tom Tromey
2021-01-01 21:44 ` [PATCH 013/203] Split out eval_op_member Tom Tromey
2021-01-01 21:44 ` [PATCH 014/203] Split out eval_op_add Tom Tromey
2021-01-01 21:44 ` [PATCH 015/203] Split out eval_op_sub Tom Tromey
2021-01-01 21:44 ` [PATCH 016/203] Split out eval_op_binary Tom Tromey
2021-01-01 21:44 ` [PATCH 017/203] Split out eval_op_subscript Tom Tromey
2021-01-01 21:44 ` [PATCH 018/203] Split out eval_op_equal Tom Tromey
2021-01-01 21:44 ` [PATCH 019/203] Split out eval_op_notequal Tom Tromey
2021-01-01 21:44 ` [PATCH 020/203] Split out eval_op_less Tom Tromey
2021-01-01 21:44 ` [PATCH 021/203] Split out eval_op_gtr Tom Tromey
2021-01-01 21:44 ` [PATCH 022/203] Split out eval_op_geq Tom Tromey
2021-01-01 21:44 ` [PATCH 023/203] Split out eval_op_leq Tom Tromey
2021-01-01 21:44 ` [PATCH 024/203] Split out eval_op_repeat Tom Tromey
2021-01-01 21:44 ` [PATCH 025/203] Split out eval_op_plus Tom Tromey
2021-01-01 21:44 ` [PATCH 026/203] Split out eval_op_neg Tom Tromey
2021-01-01 21:44 ` [PATCH 027/203] Split out eval_op_complement Tom Tromey
2021-01-01 21:44 ` [PATCH 028/203] Split out eval_op_lognot Tom Tromey
2021-01-01 21:44 ` [PATCH 029/203] Split out eval_op_ind Tom Tromey
2021-01-01 21:44 ` [PATCH 030/203] Split out eval_op_alignof Tom Tromey
2021-01-01 21:44 ` [PATCH 031/203] Split out eval_op_memval Tom Tromey
2021-01-01 21:44 ` [PATCH 032/203] Split out eval_op_preinc Tom Tromey
2021-01-01 21:44 ` [PATCH 033/203] Split out eval_op_predec Tom Tromey
2021-01-01 21:44 ` [PATCH 034/203] Split out eval_op_postinc Tom Tromey
2021-01-01 21:44 ` [PATCH 035/203] Split out eval_op_postdec Tom Tromey
2021-01-01 21:44 ` [PATCH 036/203] Split out eval_op_type Tom Tromey
2021-01-01 21:44 ` [PATCH 037/203] Split out eval_op_f_abs Tom Tromey
2021-01-01 21:44 ` [PATCH 038/203] Split out eval_op_f_mod Tom Tromey
2021-01-01 21:44 ` [PATCH 039/203] Split out eval_op_f_ceil Tom Tromey
2021-01-01 21:44 ` [PATCH 040/203] Split out eval_op_f_floor Tom Tromey
2021-01-01 21:44 ` [PATCH 041/203] Split out eval_op_f_modulo Tom Tromey
2021-01-01 21:44 ` [PATCH 042/203] Split out eval_op_f_cmplx Tom Tromey
2021-01-01 21:44 ` [PATCH 043/203] Split out eval_op_f_kind Tom Tromey
2021-01-01 21:44 ` [PATCH 044/203] Change parameters to rust_range Tom Tromey
2021-01-01 21:44 ` [PATCH 045/203] Change parameters to rust_subscript Tom Tromey
2021-01-01 21:44 ` [PATCH 046/203] Split out eval_op_rust_ind Tom Tromey
2021-01-01 21:44 ` [PATCH 047/203] Split out eval_op_rust_complement Tom Tromey
2021-01-01 21:44 ` [PATCH 048/203] Split out eval_op_rust_array Tom Tromey
2021-01-01 21:44 ` [PATCH 049/203] Split out eval_op_rust_struct_anon Tom Tromey
2021-01-01 21:44 ` [PATCH 050/203] Split out eval_op_rust_structop Tom Tromey
2021-01-01 21:44 ` [PATCH 051/203] Split helper functions Tom Tromey
2021-01-01 21:44 ` [PATCH 052/203] Split out eval_op_m2_high Tom Tromey
2021-01-04 12:05   ` Andrew Burgess
2021-02-10  0:56     ` Tom Tromey
2021-01-01 21:44 ` [PATCH 053/203] Split out eval_op_m2_subscript Tom Tromey
2021-01-01 21:44 ` [PATCH 054/203] Split out eval_binop_assign_modify Tom Tromey
2021-01-01 21:44 ` [PATCH 055/203] Split out eval_op_objc_msgcall Tom Tromey
2021-01-01 21:44 ` [PATCH 056/203] Split out eval_opencl_assign Tom Tromey
2021-01-01 21:44 ` [PATCH 057/203] Split out eval_ternop_in_range Tom Tromey
2021-01-01 21:44 ` [PATCH 058/203] Split out ada_unop_neg Tom Tromey
2021-01-01 21:44 ` [PATCH 059/203] Split out ada_unop_in_range Tom Tromey
2021-01-01 21:45 ` [PATCH 060/203] Split out ada_atr_tag Tom Tromey
2021-01-01 21:45 ` [PATCH 061/203] Split out ada_atr_size Tom Tromey
2021-01-01 21:45 ` [PATCH 062/203] Split out ada_abs Tom Tromey
2021-01-01 21:45 ` [PATCH 063/203] Split out ada_mult_binop Tom Tromey
2021-01-01 21:45 ` [PATCH 064/203] Split out ada_equal_binop Tom Tromey
2021-01-01 21:45 ` [PATCH 065/203] Split out ada_ternop_slice Tom Tromey
2021-01-01 21:45 ` [PATCH 066/203] Split out ada_binop_in_bounds Tom Tromey
2021-01-01 21:45 ` [PATCH 067/203] Split out ada_unop_atr Tom Tromey
2021-01-01 21:45 ` [PATCH 068/203] Split out ada_binop_minmax Tom Tromey
2021-01-01 21:45 ` [PATCH 069/203] Change value_val_atr to ada_val_atr Tom Tromey
2021-01-01 21:45 ` [PATCH 070/203] Split out ada_binop_exp Tom Tromey
2021-01-01 21:45 ` [PATCH 071/203] Split out eval_multi_subscript Tom Tromey
2021-01-01 21:45 ` [PATCH 072/203] Split gen_expr_binop_rest Tom Tromey
2021-01-01 21:45 ` [PATCH 073/203] Introduce class operation Tom Tromey
2021-01-03  7:09   ` Joel Brobecker
2021-01-03 13:55     ` Lancelot SIX
2021-02-10  0:57       ` Tom Tromey
2021-01-01 21:45 ` [PATCH 074/203] Implement dumping Tom Tromey
2021-01-01 21:45 ` [PATCH 075/203] Add two agent expression helper functions Tom Tromey
2021-01-01 21:45 ` [PATCH 076/203] Introduce float_const_operation Tom Tromey
2021-01-01 21:45 ` [PATCH 077/203] Introduce scope_operation Tom Tromey
2021-01-01 21:45 ` [PATCH 078/203] Introduce long_const_operation Tom Tromey
2021-01-01 21:45 ` [PATCH 079/203] Introduce var_msym_value_operation Tom Tromey
2021-01-01 21:45 ` [PATCH 080/203] Introduce var_entry_value_operation Tom Tromey
2021-01-01 21:45 ` [PATCH 081/203] Introduce func_static_var_operation Tom Tromey
2021-01-01 21:45 ` [PATCH 082/203] Introduce last_operation Tom Tromey
2021-01-01 21:45 ` [PATCH 083/203] Introduce register_operation Tom Tromey
2021-01-01 21:45 ` [PATCH 084/203] Introduce bool_operation Tom Tromey
2021-01-01 21:45 ` [PATCH 085/203] Introduce internalvar_operation Tom Tromey
2021-01-01 21:45 ` [PATCH 086/203] Introduce string_operation Tom Tromey
2021-01-01 21:45 ` [PATCH 087/203] Introduce ternop_slice_operation Tom Tromey
2021-01-01 21:45 ` [PATCH 088/203] Introduce ternop_cond_operation Tom Tromey
2021-01-01 21:45 ` [PATCH 089/203] Add c-exp.h and c_string_operation Tom Tromey
2021-01-01 21:45 ` [PATCH 090/203] Introduce objc_nsstring_operation Tom Tromey
2021-01-01 21:45 ` [PATCH 091/203] Introduce objc_selector_operation Tom Tromey
2021-01-01 21:45 ` [PATCH 092/203] Introduce complex_operation Tom Tromey
2021-01-01 21:45 ` [PATCH 093/203] Introduce structop_operation Tom Tromey
2021-01-01 21:45 ` [PATCH 094/203] Introduce structop_ptr_operation Tom Tromey
2021-01-01 21:45 ` [PATCH 095/203] Introduce structop_member_operation and structop_mptr_operation Tom Tromey
2021-01-01 21:45 ` [PATCH 096/203] Introduce concat_operation Tom Tromey
2021-01-01 21:45 ` [PATCH 097/203] Introduce add_operation Tom Tromey
2021-01-01 21:45 ` [PATCH 098/203] Introduce sub_operation Tom Tromey
2021-01-01 21:45 ` [PATCH 099/203] Introduce binop_operation Tom Tromey
2021-01-01 21:45 ` [PATCH 100/203] Introduce subscript_operation Tom Tromey
2021-01-01 21:45 ` [PATCH 101/203] Implement binary comparison operations Tom Tromey
2021-01-01 21:45 ` [PATCH 102/203] Introduce repeat_operation Tom Tromey
2021-01-01 21:45 ` [PATCH 103/203] Introduce comma_operation Tom Tromey
2021-01-01 21:45 ` [PATCH 104/203] Implement some unary operations Tom Tromey
2021-01-01 21:45 ` [PATCH 105/203] Implement unary increment and decrement operations Tom Tromey
2021-01-01 21:45 ` [PATCH 106/203] Introduce unop_ind_operation Tom Tromey
2021-01-01 21:45 ` [PATCH 107/203] Introduce type_operation Tom Tromey
2021-01-01 21:45 ` [PATCH 108/203] Introduce typeof_operation Tom Tromey
2021-01-01 21:45 ` [PATCH 109/203] Introduce decltype_operation Tom Tromey
2021-01-01 21:45 ` [PATCH 110/203] Introduce typeid_operation Tom Tromey
2021-01-01 21:45 ` [PATCH 111/203] Introduce unop_addr_operation Tom Tromey
2021-01-01 21:45 ` [PATCH 112/203] Introduce unop_sizeof_operation Tom Tromey
2021-01-01 21:45 ` [PATCH 113/203] Introduce unop_alignof_operation Tom Tromey
2021-01-01 21:45 ` [PATCH 114/203] Implement UNOP_MEMVAL and UNOP_MEMVAL_TYPE Tom Tromey
2021-01-01 21:45 ` [PATCH 115/203] Introduce op_this_operation Tom Tromey
2021-01-01 21:45 ` [PATCH 116/203] Introduce type_instance_operation Tom Tromey
2021-01-01 21:45 ` [PATCH 117/203] Introduce assign_operation Tom Tromey
2021-01-01 21:45 ` [PATCH 118/203] Introduce assign_modify_operation Tom Tromey
2021-01-01 21:45 ` [PATCH 119/203] Introduce unop_cast_operation Tom Tromey
2021-01-01 21:46 ` [PATCH 120/203] Introduce unop_cast_type_operation Tom Tromey
2021-01-01 21:46 ` [PATCH 121/203] Implement C++ cast operations Tom Tromey
2021-01-01 21:46 ` [PATCH 122/203] Introduce var_value_operation Tom Tromey
2021-01-01 21:46 ` [PATCH 123/203] Introduce objc_msgcall_operation Tom Tromey
2021-01-01 21:46 ` [PATCH 124/203] Introduce multi_subscript_operation Tom Tromey
2021-01-01 21:46 ` [PATCH 125/203] Introduce ada_wrapped_operation Tom Tromey
2021-01-01 21:46 ` [PATCH 126/203] Introduce ada_string_operation Tom Tromey
2021-01-01 21:46 ` [PATCH 127/203] Introduce ada_qual_operation Tom Tromey
2021-01-01 21:46 ` [PATCH 128/203] Introduce ada_ternop_range_operation Tom Tromey
2021-01-01 21:46 ` [PATCH 129/203] Implement several Fortran operations Tom Tromey
2021-01-01 21:46 ` [PATCH 130/203] Implement some Rust operations Tom Tromey
2021-01-01 21:46 ` [PATCH 131/203] Introduce rust_unop_ind_operation Tom Tromey
2021-01-01 21:46 ` [PATCH 132/203] Introduce rust_subscript_operation Tom Tromey
2021-01-01 21:46 ` [PATCH 133/203] Introduce rust_range_operation Tom Tromey
2021-01-01 21:46 ` [PATCH 134/203] Implement Rust field operations Tom Tromey
2021-01-01 21:46 ` [PATCH 135/203] Introduce rust_aggregate_operation Tom Tromey
2021-01-01 21:46 ` [PATCH 136/203] Add two simple Modula-2 operations Tom Tromey
2021-01-07 15:16   ` Gaius Mulley
2021-01-01 21:46 ` [PATCH 137/203] Implement the "&&" and "||" operators Tom Tromey
2021-01-01 21:46 ` [PATCH 138/203] Implement some Ada unary operations Tom Tromey
2021-01-01 21:46 ` [PATCH 139/203] Introduce ada_unop_range_operation Tom Tromey
2021-01-01 21:46 ` [PATCH 140/203] Introduce class adl_func_operation Tom Tromey
2021-01-01 21:46 ` [PATCH 141/203] Introduce array_operation Tom Tromey
2021-01-01 21:46 ` [PATCH 142/203] Implement function call operations Tom Tromey
2021-01-01 21:46 ` [PATCH 143/203] Implement Rust funcall operation Tom Tromey
2021-01-01 21:46 ` [PATCH 144/203] Introduce fortran_undetermined Tom Tromey
2021-01-01 21:46 ` [PATCH 145/203] Introduce opencl_cast_type_operation Tom Tromey
2021-01-01 21:46 ` [PATCH 146/203] Implement OpenCL binary operations Tom Tromey
2021-01-01 21:46 ` [PATCH 147/203] Introduce opencl_notequal_operation Tom Tromey
2021-01-01 21:46 ` [PATCH 148/203] Introduce opencl_structop_operation Tom Tromey
2021-01-01 21:46 ` [PATCH 149/203] Implement OpenCL logical binary operations Tom Tromey
2021-01-01 21:46 ` [PATCH 150/203] Implement OpenCL ternary conditional operator Tom Tromey
2021-01-01 21:46 ` [PATCH 151/203] Split out some Ada type resolution code Tom Tromey
2021-01-03  7:46   ` Joel Brobecker
2021-02-13 19:47     ` Tom Tromey
2021-01-01 21:46 ` [PATCH 152/203] Introduce ada_binop_addsub_operation Tom Tromey
2021-01-01 21:46 ` [PATCH 153/203] Implement Ada multiplicative operators Tom Tromey
2021-01-01 21:46 ` [PATCH 154/203] Implement Ada equality operators Tom Tromey
2021-01-01 21:46 ` [PATCH 155/203] Introduce ada_bitwise_operation Tom Tromey
2021-01-01 21:46 ` [PATCH 156/203] Introduce ada_ternop_slice Tom Tromey
2021-01-01 21:46 ` [PATCH 157/203] Introduce ada_binop_in_bounds Tom Tromey
2021-01-01 21:46 ` [PATCH 158/203] Implement some Ada OP_ATR_ operations Tom Tromey
2021-01-01 21:46 ` [PATCH 159/203] Introduce ada_var_value_operation Tom Tromey
2021-01-01 21:46 ` [PATCH 160/203] Introduce ada_var_msym_value_operation Tom Tromey
2021-01-01 21:46 ` [PATCH 161/203] Implement Ada min and max operations Tom Tromey
2021-01-01 21:46 ` [PATCH 162/203] Refactor value_pos_atr Tom Tromey
2021-01-01 21:46 ` [PATCH 163/203] Introduce ada_pos_operation Tom Tromey
2021-01-01 21:46 ` [PATCH 164/203] Introduce ada_atr_val_operation Tom Tromey
2021-01-01 21:46 ` [PATCH 165/203] Introduce ada_binop_exp_operation Tom Tromey
2021-01-01 21:46 ` [PATCH 166/203] Introduce ada_unop_ind_operation Tom Tromey
2021-01-01 21:46 ` [PATCH 167/203] Introduce ada_structop_operation Tom Tromey
2021-01-01 21:46 ` [PATCH 168/203] Implement function calls for Ada Tom Tromey
2021-01-01 21:46 ` [PATCH 169/203] Implement Ada resolution Tom Tromey
2021-01-03  7:57   ` Joel Brobecker
2021-02-13 19:49     ` Tom Tromey
2021-01-01 21:46 ` [PATCH 170/203] Implement Ada assignment Tom Tromey
2021-01-01 21:46 ` [PATCH 171/203] Remove use of op_string Tom Tromey
2021-01-01 21:46 ` [PATCH 172/203] Add an expr::operation_up to struct expression Tom Tromey
2021-01-01 21:46 ` [PATCH 173/203] Add completion for operations Tom Tromey
2021-01-01 21:46 ` [PATCH 174/203] Add operation-related methods to parser_state Tom Tromey
2021-01-01 21:46 ` [PATCH 175/203] Convert dtrace probes to use operations Tom Tromey
2021-01-01 21:46 ` [PATCH 176/203] Convert stap probes to create operations Tom Tromey
2021-01-01 21:46 ` [PATCH 177/203] Convert rust-exp.y to use operations Tom Tromey
2021-01-01 21:46 ` [PATCH 178/203] Convert c-exp.y " Tom Tromey
2021-01-01 21:46 ` [PATCH 179/203] Convert go-exp.y " Tom Tromey
2021-01-01 21:47 ` [PATCH 180/203] Convert d-exp.y " Tom Tromey
2021-01-01 21:47 ` [PATCH 181/203] Convert p-exp.y " Tom Tromey
2021-01-01 21:47 ` [PATCH 182/203] Convert m2-exp.y " Tom Tromey
2021-01-01 21:47 ` [PATCH 183/203] Convert f-exp.y " Tom Tromey
2021-01-01 21:47 ` [PATCH 184/203] Convert ada-exp.y " Tom Tromey
2021-01-01 21:47 ` [PATCH 185/203] Remove now-unused Rust evaluator code Tom Tromey
2021-01-01 21:47 ` [PATCH 186/203] Remove now-unused Fortran " Tom Tromey
2021-01-01 21:47 ` [PATCH 187/203] Remove now-unused Modula-2 " Tom Tromey
2021-01-01 21:47 ` [PATCH 188/203] Remove now-unused Ada " Tom Tromey
2021-01-01 21:47 ` [PATCH 189/203] Remove now-unused C " Tom Tromey
2021-01-01 21:47 ` [PATCH 190/203] Remove union exp_element Tom Tromey
2021-01-01 21:47 ` [PATCH 191/203] Remove two Ada opcodes Tom Tromey
2021-01-01 21:47 ` [PATCH 192/203] Remove unused Modula-2 opcodes Tom Tromey
2021-01-01 21:47 ` [PATCH 193/203] Remove unused Ada opcodes Tom Tromey
2021-01-01 21:47 ` [PATCH 194/203] Remove OP_EXTENDED0 Tom Tromey
2021-01-01 21:47 ` [PATCH 195/203] Remove OP_UNUSED_LAST Tom Tromey
2021-01-01 21:47 ` [PATCH 196/203] Remove BINOP_END Tom Tromey
2021-01-01 21:47 ` [PATCH 197/203] Inline expression constructor Tom Tromey
2021-01-01 21:47 ` [PATCH 198/203] Inline expr_builder methods Tom Tromey
2021-01-01 21:47 ` [PATCH 199/203] Merge namespace scopes in eval.c Tom Tromey
2021-01-01 21:47 ` [PATCH 200/203] Remove EVAL_SKIP Tom Tromey
2021-01-01 21:47 ` [PATCH 201/203] Change exp_uses_objfile to return bool Tom Tromey
2021-01-01 21:47 ` [PATCH 202/203] Use bound_minimal_symbol in var_msym_value_operation Tom Tromey
2021-01-01 21:47 ` [PATCH 203/203] Remove some null checks Tom Tromey
2021-01-03  7:02 ` [PATCH 000/203] Refactor expressions Joel Brobecker
2021-01-04 12:16   ` Andrew Burgess
2021-02-13 19:54   ` Tom Tromey
2021-02-16 16:17     ` Tom Tromey

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).