Add an expr::operation_up to struct expression
authorTom Tromey <tom@tromey.com>
Mon, 8 Mar 2021 14:27:57 +0000 (07:27 -0700)
committerTom Tromey <tom@tromey.com>
Mon, 8 Mar 2021 14:28:37 +0000 (07:28 -0700)
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-03-08  Tom Tromey  <tom@tromey.com>

* ada-exp.h (class ada_var_value_operation) <get_symbol>: Remove;
now in superclass.
* 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.

17 files changed:
gdb/ChangeLog
gdb/ada-exp.h
gdb/ax-gdb.c
gdb/breakpoint.c
gdb/dtrace-probe.c
gdb/eval.c
gdb/expop.h
gdb/expprint.c
gdb/expression.h
gdb/parse.c
gdb/parser-defs.h
gdb/ppc-linux-nat.c
gdb/printcmd.c
gdb/stap-probe.c
gdb/tracepoint.c
gdb/value.c
gdb/value.h

index fe4f560d33ebc47e72d57455f739975204db0abe..5fd0967d3d5579f024e975fb22f1d2b19d954be5 100644 (file)
@@ -1,3 +1,37 @@
+2021-03-08  Tom Tromey  <tom@tromey.com>
+
+       * ada-exp.h (class ada_var_value_operation) <get_symbol>: Remove;
+       now in superclass.
+       * 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.
+
 2021-03-08  Tom Tromey  <tom@tromey.com>
 
        * ada-lang.c (ada_value_binop): Do not use op_string.
index ab910e87fffc1cc4dd4e881addde6e69cec408ea..1ae0cbc354663767608ffda4bc3ff3ccb6d8ad80 100644 (file)
@@ -351,9 +351,6 @@ public:
                            struct expression *exp,
                            enum noside noside) override;
 
-  symbol *get_symbol () const
-  { return std::get<0> (m_storage); }
-
   const block *get_block () const
   { return std::get<1> (m_storage); }
 
index 8ec3dd7cc3d5f36d02995c4967c2cab34fe2261a..d2f50bbec7bdb05ca34bbb7cf3af3fe2adb4bd54 100644 (file)
@@ -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);
     }
 
index e9aba79e40fe00831d71908d0fcefcd23e2cf377..aa2abcef017254df1c94d6d22cfb4e7c09ae17ba 100644 (file)
@@ -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
@@ -5022,7 +5023,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);
@@ -10122,6 +10124,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)
@@ -10842,8 +10847,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)
     {
index 6c01f87de646461b48fa5e83f787ab720e9f418f..f4b6becbf61186f33be640097fecf4e8f1430e74 100644 (file)
@@ -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;
index f1302ef6f54b42523721dc23f6651ddc11bd9f39..142d4aea59cece2dee761475173f0a5fd27ce619 100644 (file)
@@ -120,8 +120,14 @@ expression::evaluate (struct type *expect_type, enum noside noside)
       && !thread_stack_temporaries_enabled_p (inferior_thread ()))
     stack_temporaries.emplace (inferior_thread ());
 
-  int pos = 0;
-  struct value *retval = evaluate_subexp (expect_type, this, &pos, noside);
+  struct value *retval;
+  if (op != nullptr)
+    retval = op->evaluate (expect_type, this, noside);
+  else
+    {
+      int pos = 0;
+      retval = evaluate_subexp (expect_type, this, &pos, noside);
+    }
 
   if (stack_temporaries.has_value ()
       && value_in_thread_stack_temporaries (retval, inferior_thread ()))
@@ -153,6 +159,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);
 }
 
@@ -179,8 +187,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)
 {
@@ -198,7 +207,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)
     {
@@ -4491,5 +4503,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;
 }
index 9a9c6bc2b199e0cf0ac2ee3ad6dd758e34c3b69b..a719b0d1edb28e3eea0bc6ec31162387e7c5be86 100644 (file)
@@ -654,6 +654,12 @@ public:
   enum exp_opcode opcode () const override
   { return OP_VAR_VALUE; }
 
+  /* 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,
@@ -823,6 +829,12 @@ public:
   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,
@@ -1329,7 +1341,24 @@ public:
   }
 };
 
-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>;
@@ -1759,6 +1788,12 @@ public:
   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,
@@ -1884,6 +1919,12 @@ public:
   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,
@@ -1942,6 +1983,12 @@ public:
   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,
index 92a3ab87ef02d831ce5537324053e65b599b359d..6c65ec0207a200bc4131172ea216f58bb1a36d0a 100644 (file)
@@ -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)
@@ -1150,9 +1153,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,
index d20857bf268b99ee9eb06a51970796e77051e386..3abaf6e6dc7db535c20ae2a30c6c38b7e9f08c88 100644 (file)
@@ -240,7 +240,9 @@ struct expression
      expression.  */
   enum exp_opcode first_opcode () const
   {
-      return elts[0].opcode;
+    if (op != nullptr)
+      return op->opcode ();
+    return elts[0].opcode;
   }
 
   /* Evaluate the expression.  EXPECT_TYPE is the context type of the
@@ -252,6 +254,7 @@ struct expression
   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;
 };
index 884a00862ece650d99cb28f8e0eb6bd81c51ec0d..68386f17bc5e026a3cc578593e4cc2113b0d8842 100644 (file)
@@ -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.  */
@@ -1073,7 +1074,6 @@ parse_exp_in_context (const char **stringptr, CORE_ADDR pc,
                      expr_completion_state *cstate)
 {
   const struct language_defn *lang = NULL;
-  int subexp;
 
   if (*stringptr == 0 || **stringptr == 0)
     error_no_arg (_("expression to compute"));
@@ -1153,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;
     }
 
@@ -1168,12 +1169,17 @@ 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 (out_subexp)
-    *out_subexp = subexp;
+  if (result->op == nullptr)
+    {
+      int subexp = prefixify_expression (result.get (),
+                                        ps.m_completion_state.expout_last_struct);
+      if (out_subexp)
+       *out_subexp = subexp;
 
-  lang->post_parser (&result, &ps);
+      lang->post_parser (&result, &ps);
+    }
+  else
+    result->op->set_outermost ();
 
   if (expressiondebug)
     dump_prefix_expression (result.get (), gdb_stdlog);
@@ -1441,6 +1447,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);
 }
 
index 466230e4ad09408a55689a672f4ff334c9644857..a9ae198fab22e4500e37f36dd16e8ff87277d534 100644 (file)
@@ -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;
index 4da15f9a66320ee5f4ed309ffbe103eda0249606..72f0283e4af231f12f15bf921eea5ca0bbcaf038 100644 (file)
@@ -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)
index 58e39c7365f98f531afd6c27503bb2a589c6f923..235f2de68fe203d3b5c166d6e0e733dabd0b98c4 100644 (file)
@@ -1375,8 +1375,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:
index bbdfbcd026737fe6cc763a3bd11851eb1837ec75..476cbecf9945b5de45cb3dd0212b85ec259bba6a 100644 (file)
@@ -1429,7 +1429,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;
index 0cbd2c68224997be66c2b215d593967846f87ec1..101c526e8b22db1a5caba756a4ff583a9a9afaee 100644 (file)
@@ -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,
index bddf9a47923a0c1e845f94668c959a11569d8464..89b612e9e876f71f3bb116a774ddd23e070354ac 100644 (file)
@@ -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
@@ -2006,7 +2007,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);
@@ -2014,15 +2015,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.  */
index 60a831c38c4e6a8ac3504299c4604d75dc0a2a25..7f72938f5b6378adee5c5f53c8d423e2b62eb54a 100644 (file)
@@ -930,7 +930,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);