/* 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 . */ #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; 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); 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, 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, bool outermost_p, 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); 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); 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); extern struct value *eval_op_structop_struct (struct type *expect_type, struct expression *exp, 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); 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, 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); 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); 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); 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); 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); 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); 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 { /* 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_owner (); 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 static inline bool check_objfile (enum_flags val, struct objfile *objfile) { return false; } template static inline bool check_objfile (const std::vector &collection, struct objfile *objfile) { for (const auto &item : collection) { if (check_objfile (item, objfile)) return true; } return false; } template static inline bool check_objfile (const std::pair &item, struct objfile *objfile) { return (check_objfile (item.first, 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 void dump_for_expression (struct ui_file *stream, int depth, const std::vector &vals) { fprintf_filtered (stream, _("%*sVector:\n"), depth, ""); for (auto &item : vals) dump_for_expression (stream, depth + 1, item); } template void dump_for_expression (struct ui_file *stream, int depth, const std::pair &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. */ template class tuple_holding_operation : public operation { public: explicit tuple_holding_operation (Arg... args) : m_storage (std::forward (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 { dump_for_expression (stream, depth, opcode ()); do_dump<0, Arg...> (stream, depth + 1, m_storage); } protected: /* Storage for the data. */ std::tuple m_storage; private: /* do_dump does the work of dumping the data. */ template typename std::enable_if::type do_dump (struct ui_file *stream, int depth, const std::tuple &value) const { } template typename std::enable_if::type do_dump (struct ui_file *stream, int depth, const std::tuple &value) const { dump_for_expression (stream, depth, std::get (value)); do_dump (stream, depth, value); } /* do_check_objfile does the work of checking whether this object refers to OBJFILE. */ template typename std::enable_if::type do_check_objfile (struct objfile *objfile, const std::tuple &value) const { return false; } template typename std::enable_if::type do_check_objfile (struct objfile *objfile, const std::tuple &value) const { if (check_objfile (std::get (value), objfile)) return true; return do_check_objfile (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) { enum address_class sc = SYMBOL_CLASS (sym); return (sc == LOC_BLOCK || sc == LOC_CONST || sc == LOC_CONST_BYTES || sc == LOC_LABEL); } template static inline bool check_constant (const std::vector &collection) { for (const auto &item : collection) if (!check_constant (item)) return false; return true; } template static inline bool check_constant (const std::pair &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 class maybe_constant_operation : public tuple_holding_operation { public: using tuple_holding_operation::tuple_holding_operation; bool constant_p () const override { return do_check_constant<0, Arg...> (this->m_storage); } private: template typename std::enable_if::type do_check_constant (const std::tuple &value) const { return true; } template typename std::enable_if::type do_check_constant (const std::tuple &value) const { if (!check_constant (std::get (value))) return false; return do_check_constant (value); } }; /* A floating-point constant. The constant is encoded in the target format. */ typedef std::array 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; }; class scope_operation : public maybe_constant_operation { 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; }; class long_const_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_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; }; class var_msym_value_operation : public maybe_constant_operation { 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, m_outermost, 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; } void set_outermost () override { m_outermost = true; } protected: /* True if this is the outermost operation in the expression. */ bool m_outermost = false; void do_generate_ax (struct expression *exp, struct agent_expr *ax, struct axs_value *value, struct type *cast_type) override; }; class var_entry_value_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 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; } }; class func_static_var_operation : public maybe_constant_operation { 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; } }; class last_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 access_value_history (std::get<0> (m_storage)); } enum exp_opcode opcode () const override { return OP_LAST; } }; class register_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 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; }; class bool_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 { 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; } }; class internalvar_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_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; }; class string_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 { 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; } }; class ternop_slice_operation : public maybe_constant_operation { 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; } }; class ternop_cond_operation : public maybe_constant_operation { 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; }; class complex_operation : public maybe_constant_operation { 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; } }; class structop_base_operation : public tuple_holding_operation { 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); } }; 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); } }; class structop_member_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 { 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 { 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; } }; class concat_operation : public maybe_constant_operation { 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; } }; class add_operation : public maybe_constant_operation { 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); } }; class sub_operation : public maybe_constant_operation { 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); } }; 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 class binop_operation : public maybe_constant_operation { 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 class usual_ax_binop_operation : public binop_operation { public: using binop_operation::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; using intdiv_operation = binop_operation; using mod_operation = binop_operation; using mul_operation = usual_ax_binop_operation; using div_operation = usual_ax_binop_operation; using rem_operation = usual_ax_binop_operation; using lsh_operation = usual_ax_binop_operation; using rsh_operation = usual_ax_binop_operation; using bitwise_and_operation = usual_ax_binop_operation; using bitwise_ior_operation = usual_ax_binop_operation; using bitwise_xor_operation = usual_ax_binop_operation; class subscript_operation : public usual_ax_binop_operation { public: using usual_ax_binop_operation::usual_ax_binop_operation; value *evaluate_for_sizeof (struct expression *exp, enum noside noside) override; }; /* Implementation of comparison operations. */ template class comparison_operation : public usual_ax_binop_operation { public: using usual_ax_binop_operation::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; using notequal_operation = comparison_operation; using less_operation = comparison_operation; using gtr_operation = comparison_operation; using geq_operation = comparison_operation; using leq_operation = comparison_operation; /* Implement the GDB '@' repeat operator. */ class repeat_operation : public binop_operation { using binop_operation::binop_operation; protected: void do_generate_ax (struct expression *exp, struct agent_expr *ax, struct axs_value *value, struct type *cast_type) override; }; /* C-style comma operator. */ class comma_operation : public maybe_constant_operation { 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; }; 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 class unop_operation : public maybe_constant_operation { 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 class usual_ax_unop_operation : public unop_operation { using unop_operation::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; using unary_neg_operation = usual_ax_unop_operation; using unary_complement_operation = usual_ax_unop_operation; using unary_logical_not_operation = usual_ax_unop_operation; /* Handle pre- and post- increment and -decrement. */ template class unop_incr_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 { 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; using predec_operation = unop_incr_operation; using postinc_operation = unop_incr_operation; using postdec_operation = unop_incr_operation; /* Base class for implementations of UNOP_IND. */ class unop_ind_base_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 { 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); } }; /* Implement OP_TYPE. */ class type_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 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; } }; /* Implement the "typeof" operation. */ class typeof_operation : public maybe_constant_operation { 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; } }; /* Implement 'decltype'. */ class decltype_operation : public maybe_constant_operation { 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; } }; /* Implement 'typeid'. */ class typeid_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 { 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 */