ODR warning for "enum string_repr_result"
[binutils-gdb.git] / gdb / expop.h
index b808c0f63bc770ed049908fc46fa2db3c38bb1e2..cfe96cbe589d8172fa1a972c05d911e3d2ec5978 100644 (file)
@@ -1,6 +1,6 @@
 /* Definitions for expressions in GDB
 
-   Copyright (C) 2020 Free Software Foundation, Inc.
+   Copyright (C) 2020-2022 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -53,8 +53,7 @@ extern struct value *eval_op_var_msym_value (struct type *expect_type,
                                             struct expression *exp,
                                             enum noside noside,
                                             bool outermost_p,
-                                            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);
@@ -65,10 +64,6 @@ 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);
 extern struct value *eval_op_ternop (struct type *expect_type,
                                     struct expression *exp,
                                     enum noside noside,
@@ -88,10 +83,6 @@ 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);
 extern struct value *eval_op_add (struct type *expect_type,
                                  struct expression *exp,
                                  enum noside noside,
@@ -197,10 +188,18 @@ 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
 {
 
+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.  */
@@ -214,7 +213,7 @@ check_objfile (struct objfile *exp_objfile, struct objfile *objfile)
   return exp_objfile == objfile;
 }
 
-static inline bool 
+static inline bool
 check_objfile (struct type *type, struct objfile *objfile)
 {
   struct objfile *ty_objfile = type->objfile_owner ();
@@ -223,24 +222,29 @@ check_objfile (struct type *type, struct objfile *objfile)
   return false;
 }
 
-static inline bool 
+static inline bool
 check_objfile (struct symbol *sym, struct objfile *objfile)
 {
-  return check_objfile (symbol_objfile (sym), objfile);
+  return check_objfile (sym->objfile (), objfile);
 }
 
-static inline bool 
+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)
+check_objfile (const block_symbol &sym, struct objfile *objfile)
 {
-  /* This may seem strange but minsyms are only used with an objfile
-     as well.  */
-  return false;
+  return (check_objfile (sym.symbol, objfile)
+         || check_objfile (sym.block, objfile));
+}
+
+static inline bool
+check_objfile (bound_minimal_symbol minsym, struct objfile *objfile)
+{
+  return check_objfile (minsym.objfile, objfile);
 }
 
 static inline bool
@@ -255,7 +259,7 @@ check_objfile (const std::string &str, struct objfile *objfile)
   return false;
 }
 
-static inline bool 
+static inline bool
 check_objfile (const operation_up &op, struct objfile *objfile)
 {
   return op->uses_objfile (objfile);
@@ -281,7 +285,7 @@ check_objfile (enum_flags<T> val, struct objfile *objfile)
 }
 
 template<typename T>
-static inline bool 
+static inline bool
 check_objfile (const std::vector<T> &collection, struct objfile *objfile)
 {
   for (const auto &item : collection)
@@ -293,13 +297,16 @@ check_objfile (const std::vector<T> &collection, struct objfile *objfile)
 }
 
 template<typename S, typename T>
-static inline bool 
+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));
 }
 
+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)
@@ -320,7 +327,9 @@ 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);
+                                const block_symbol &sym);
+extern void dump_for_expression (struct ui_file *stream, int depth,
+                                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,
@@ -330,14 +339,14 @@ extern void dump_for_expression (struct ui_file *stream, int depth,
 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);
+                                const std::unique_ptr<ada_component> &comp);
 
 template<typename T>
 void
 dump_for_expression (struct ui_file *stream, int depth,
                     const std::vector<T> &vals)
 {
-  fprintf_filtered (stream, _("%*sVector:\n"), depth, "");
+  gdb_printf (stream, _("%*sVector:\n"), depth, "");
   for (auto &item : vals)
     dump_for_expression (stream, depth + 1, item);
 }
@@ -433,7 +442,7 @@ check_constant (const operation_up &item)
 }
 
 static inline bool
-check_constant (struct minimal_symbol *msym)
+check_constant (bound_minimal_symbol msym)
 {
   return false;
 }
@@ -456,12 +465,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)
 {
@@ -471,13 +474,21 @@ check_constant (ULONGEST cst)
 static inline bool
 check_constant (struct symbol *sym)
 {
-  enum address_class sc = SYMBOL_CLASS (sym);
+  enum address_class sc = sym->aclass ();
   return (sc == LOC_BLOCK
          || sc == LOC_CONST
          || sc == LOC_CONST_BYTES
          || sc == LOC_LABEL);
 }
 
+static inline bool
+check_constant (const block_symbol &sym)
+{
+  /* We know the block is constant, so we only need to check the
+     symbol.  */
+  return check_constant (sym.symbol);
+}
+
 template<typename T>
 static inline bool
 check_constant (const std::vector<T> &collection)
@@ -591,6 +602,11 @@ public:
   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; }
 
@@ -603,6 +619,54 @@ protected:
     override;
 };
 
+/* Compute the value of a variable.  */
+class var_value_operation
+  : public maybe_constant_operation<block_symbol>
+{
+public:
+
+  using maybe_constant_operation::maybe_constant_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;
+
+  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; }
+
+  /* Return the symbol referenced by this object.  */
+  symbol *get_symbol () const
+  {
+    return std::get<0> (m_storage).symbol;
+  }
+
+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>
 {
@@ -634,7 +698,7 @@ protected:
 };
 
 class var_msym_value_operation
-  : public maybe_constant_operation<minimal_symbol *, struct objfile *>
+  : public maybe_constant_operation<bound_minimal_symbol>
 {
 public:
 
@@ -645,8 +709,7 @@ public:
                   enum noside noside) override
   {
     return eval_op_var_msym_value (expect_type, exp, noside, m_outermost,
-                                  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)
@@ -659,6 +722,15 @@ public:
                            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
+  {
+    const char *name = std::get<0> (m_storage).minsym->print_name ();
+    return operation::evaluate_funcall (expect_type, exp, noside, name, args);
+  }
+
   enum exp_opcode opcode () const override
   { return OP_VAR_MSYM_VALUE; }
 
@@ -754,6 +826,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,
@@ -826,12 +904,7 @@ public:
 
   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 noside noside) override;
 
   enum exp_opcode opcode () const override
   { return OP_STRING; }
@@ -924,15 +997,26 @@ public:
     return std::get<1> (m_storage);
   }
 
-  /* Used for completion.  Evaluate the LHS for type.  */
-  value *evaluate_lhs (struct expression *exp)
+  value *evaluate_funcall (struct type *expect_type,
+                          struct expression *exp,
+                          enum noside noside,
+                          const std::vector<operation_up> &args) override;
+
+  /* Try to complete this operation in the context of EXP.  TRACKER is
+     the completion tracker to update.  Return true if completion was
+     possible, false otherwise.  */
+  virtual bool complete (struct expression *exp, completion_tracker &tracker)
   {
-    return std::get<0> (m_storage)->evaluate (nullptr, exp,
-                                             EVAL_AVOID_SIDE_EFFECTS);
+    return complete (exp, tracker, "");
   }
 
 protected:
 
+  /* Do the work of the public 'complete' method.  PREFIX is prepended
+     to each result.  */
+  bool complete (struct expression *exp, completion_tracker &tracker,
+                const char *prefix);
+
   using tuple_holding_operation::tuple_holding_operation;
 };
 
@@ -1004,13 +1088,26 @@ protected:
   }
 };
 
-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
@@ -1027,11 +1124,11 @@ public:
 };
 
 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,
@@ -1063,7 +1160,7 @@ public:
       = 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);
+    return value_concat (lhs, rhs);
   }
 
   enum exp_opcode opcode () const override
@@ -1242,7 +1339,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>;
@@ -1465,9 +1579,7 @@ public:
                   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
@@ -1490,9 +1602,7 @@ public:
                   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,
@@ -1567,15 +1677,18 @@ public:
                   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
   { return UNOP_ADDR; }
 
+  /* Return the subexpression.  */
+  const operation_up &get_expression () const
+  {
+    return std::get<0> (m_storage);
+  }
+
 protected:
 
   void do_generate_ax (struct expression *exp,
@@ -1602,8 +1715,6 @@ public:
                   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);
   }
 
@@ -1666,6 +1777,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,
@@ -1713,6 +1830,383 @@ protected:
     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;
+};
+
+/* 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; }
+};
+
+/* 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_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; }
+
+  /* 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,
+                      struct agent_expr *ax,
+                      struct axs_value *value,
+                      struct type *cast_type)
+    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;
+};
+
+/* Not a cast!  Extract a value of a given type from the contents of a
+   value.  The new value is extracted from the least significant bytes
+   of the old value.  The new value's type must be no bigger than the
+   old values type.  */
+class unop_extract_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;
+
+  enum exp_opcode opcode () const override
+  { return UNOP_EXTRACT; }
+
+  /* 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,
+                      struct agent_expr *ax,
+                      struct axs_value *value,
+                      struct type *cast_type) 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; }
+
+  /* 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,
+                      struct agent_expr *ax,
+                      struct axs_value *value,
+                      struct type *cast_type)
+    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;
+};
+
+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);
+    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>;
+
+/* 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; }
+};
+
+/* 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;
+};
+
+/* 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; }
+};
+
+/* 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);
+};
+
+/* 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 */