#include "objfiles.h"
#include "typeprint.h"
#include <ctype.h>
+#include "expop.h"
/* Prototypes for local functions. */
}
}
+namespace expr
+{
+
+value *
+operation::evaluate_for_cast (struct type *expect_type,
+ struct expression *exp,
+ enum noside noside)
+{
+ value *val = evaluate (expect_type, exp, noside);
+ if (noside == EVAL_SKIP)
+ return eval_skip_value (exp);
+ return value_cast (expect_type, val);
+}
+
+value *
+operation::evaluate_for_address (struct expression *exp, enum noside noside)
+{
+ value *val = evaluate (nullptr, exp, noside);
+ return evaluate_subexp_for_address_base (exp, noside, val);
+}
+
+}
+
/* Evaluate like `evaluate_subexp' except coercing arrays to pointers.
When used in contexts where arrays will be coerced anyway, this is
equivalent to `evaluate_subexp' but much faster because it avoids
return evaluate_subexp_for_sizeof_base (exp, type);
}
+namespace expr
+{
+
+value *
+operation::evaluate_for_sizeof (struct expression *exp, enum noside noside)
+{
+ value *val = evaluate (nullptr, exp, EVAL_AVOID_SIDE_EFFECTS);
+ return evaluate_subexp_for_sizeof_base (exp, value_type (val));
+}
+
+}
+
/* Evaluate a subexpression of EXP, at index *POS, and return a value
for that subexpression cast to TO_TYPE. Advance *POS over the
subexpression. */
--- /dev/null
+/* Definitions for expressions in GDB
+
+ Copyright (C) 2020 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef EXPOP_H
+#define EXPOP_H
+
+#include "block.h"
+#include "c-lang.h"
+#include "cp-abi.h"
+#include "expression.h"
+#include "objfiles.h"
+#include "gdbsupport/traits.h"
+#include "gdbsupport/enum-flags.h"
+
+struct agent_expr;
+struct axs_value;
+
+namespace expr
+{
+
+/* The check_objfile overloads are used to check whether a particular
+ component of some operation references an objfile. The passed-in
+ objfile will never be a debug objfile. */
+
+/* See if EXP_OBJFILE matches OBJFILE. */
+static inline bool
+check_objfile (struct objfile *exp_objfile, struct objfile *objfile)
+{
+ if (exp_objfile->separate_debug_objfile_backlink)
+ exp_objfile = exp_objfile->separate_debug_objfile_backlink;
+ return exp_objfile == objfile;
+}
+
+static inline bool
+check_objfile (struct type *type, struct objfile *objfile)
+{
+ struct objfile *ty_objfile = type->objfile_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<typename T>
+static inline bool
+check_objfile (enum_flags<T> val, struct objfile *objfile)
+{
+ return false;
+}
+
+template<typename T>
+static inline bool
+check_objfile (const std::vector<T> &collection, struct objfile *objfile)
+{
+ for (const auto &item : collection)
+ {
+ if (check_objfile (item, objfile))
+ return true;
+ }
+ return false;
+}
+
+template<typename S, typename T>
+static inline bool
+check_objfile (const std::pair<S, T> &item, struct objfile *objfile)
+{
+ return (check_objfile (item.first, objfile)
+ || check_objfile (item.second, objfile));
+}
+
+/* Base class for most concrete operations. This class holds data,
+ specified via template parameters, and supplies generic
+ implementations of the 'dump' and 'uses_objfile' methods. */
+template<typename... Arg>
+class tuple_holding_operation : public operation
+{
+public:
+
+ explicit tuple_holding_operation (Arg... args)
+ : m_storage (std::forward<Arg> (args)...)
+ {
+ }
+
+ DISABLE_COPY_AND_ASSIGN (tuple_holding_operation);
+
+ bool uses_objfile (struct objfile *objfile) const override
+ {
+ return do_check_objfile<0, Arg...> (objfile, m_storage);
+ }
+
+ void dump (struct ui_file *stream, int depth) const override
+ {
+ do_dump<0, Arg...> (stream, depth, m_storage);
+ }
+
+protected:
+
+ /* Storage for the data. */
+ std::tuple<Arg...> m_storage;
+
+private:
+
+ /* do_dump does the work of dumping the data. */
+ template<int I, typename... T>
+ typename std::enable_if<I == sizeof... (T), void>::type
+ do_dump (struct ui_file *stream, int depth, const std::tuple<T...> &value)
+ const
+ {
+ }
+
+ template<int I, typename... T>
+ typename std::enable_if<I < sizeof... (T), void>::type
+ do_dump (struct ui_file *stream, int depth, const std::tuple<T...> &value)
+ const
+ {
+ do_dump<I + 1, T...> (stream, depth, value);
+ }
+
+ /* do_check_objfile does the work of checking whether this object
+ refers to OBJFILE. */
+ template<int I, typename... T>
+ typename std::enable_if<I == sizeof... (T), bool>::type
+ do_check_objfile (struct objfile *objfile, const std::tuple<T...> &value)
+ const
+ {
+ return false;
+ }
+
+ template<int I, typename... T>
+ typename std::enable_if<I < sizeof... (T), bool>::type
+ do_check_objfile (struct objfile *objfile, const std::tuple<T...> &value)
+ const
+ {
+ if (check_objfile (std::get<I> (value), objfile))
+ return true;
+ return do_check_objfile<I + 1, T...> (objfile, value);
+ }
+};
+
+/* The check_constant overloads are used to decide whether a given
+ concrete operation is a constant. This is done by checking the
+ operands. */
+
+static inline bool
+check_constant (const operation_up &item)
+{
+ return item->constant_p ();
+}
+
+static inline bool
+check_constant (struct minimal_symbol *msym)
+{
+ return false;
+}
+
+static inline bool
+check_constant (struct type *type)
+{
+ return true;
+}
+
+static inline bool
+check_constant (const struct block *block)
+{
+ return true;
+}
+
+static inline bool
+check_constant (const std::string &str)
+{
+ return true;
+}
+
+static inline bool
+check_constant (struct objfile *objfile)
+{
+ return true;
+}
+
+static inline bool
+check_constant (ULONGEST cst)
+{
+ return true;
+}
+
+static inline bool
+check_constant (struct symbol *sym)
+{
+ enum address_class sc = SYMBOL_CLASS (sym);
+ return (sc == LOC_BLOCK
+ || sc == LOC_CONST
+ || sc == LOC_CONST_BYTES
+ || sc == LOC_LABEL);
+}
+
+template<typename T>
+static inline bool
+check_constant (const std::vector<T> &collection)
+{
+ for (const auto &item : collection)
+ if (!check_constant (item))
+ return false;
+ return true;
+}
+
+template<typename S, typename T>
+static inline bool
+check_constant (const std::pair<S, T> &item)
+{
+ return check_constant (item.first) && check_constant (item.second);
+}
+
+/* Base class for concrete operations. This class supplies an
+ implementation of 'constant_p' that works by checking the
+ operands. */
+template<typename... Arg>
+class maybe_constant_operation
+ : public tuple_holding_operation<Arg...>
+{
+public:
+
+ using tuple_holding_operation<Arg...>::tuple_holding_operation;
+
+ bool constant_p () const override
+ {
+ return do_check_constant<0, Arg...> (this->m_storage);
+ }
+
+private:
+
+ template<int I, typename... T>
+ typename std::enable_if<I == sizeof... (T), bool>::type
+ do_check_constant (const std::tuple<T...> &value) const
+ {
+ return true;
+ }
+
+ template<int I, typename... T>
+ typename std::enable_if<I < sizeof... (T), bool>::type
+ do_check_constant (const std::tuple<T...> &value) const
+ {
+ if (!check_constant (std::get<I> (value)))
+ return false;
+ return do_check_constant<I + 1, T...> (value);
+ }
+};
+
+} /* namespace expr */
+
+#endif /* EXPOP_H */
does in many situations. */
};
+struct expression;
+struct agent_expr;
+struct axs_value;
+struct type;
+struct ui_file;
+
+namespace expr
+{
+
+class operation;
+typedef std::unique_ptr<operation> operation_up;
+
+/* Base class for an operation. An operation is a single component of
+ an expression. */
+
+class operation
+{
+protected:
+
+ operation () = default;
+ DISABLE_COPY_AND_ASSIGN (operation);
+
+public:
+
+ virtual ~operation () = default;
+
+ /* Evaluate this operation. */
+ virtual value *evaluate (struct type *expect_type,
+ struct expression *exp,
+ enum noside noside) = 0;
+
+ /* Evaluate this operation in a context where C-like coercion is
+ needed. */
+ virtual value *evaluate_with_coercion (struct expression *exp,
+ enum noside noside)
+ {
+ return evaluate (nullptr, exp, noside);
+ }
+
+ /* Evaluate this expression in the context of a cast to
+ EXPECT_TYPE. */
+ virtual value *evaluate_for_cast (struct type *expect_type,
+ struct expression *exp,
+ enum noside noside);
+
+ /* Evaluate this expression in the context of a sizeof
+ operation. */
+ virtual value *evaluate_for_sizeof (struct expression *exp,
+ enum noside noside);
+
+ /* Evaluate this expression in the context of an address-of
+ operation. Must return the address. */
+ virtual value *evaluate_for_address (struct expression *exp,
+ enum noside noside);
+
+ /* True if this is a constant expression. */
+ virtual bool constant_p () const
+ { return false; }
+
+ /* Return true if this operation uses OBJFILE (and will become
+ dangling when OBJFILE is unloaded), otherwise return false.
+ OBJFILE must not be a separate debug info file. */
+ virtual bool uses_objfile (struct objfile *objfile) const
+ { return false; }
+
+ /* Generate agent expression bytecodes for this operation. */
+ void generate_ax (struct expression *exp, struct agent_expr *ax,
+ struct axs_value *value,
+ struct type *cast_type = nullptr);
+
+ /* Return the opcode that is implemented by this operation. */
+ virtual enum exp_opcode opcode () const = 0;
+
+ /* Print this operation to STREAM. */
+ virtual void dump (struct ui_file *stream, int depth) const = 0;
+
+protected:
+
+ /* Called by generate_ax to do the work for this particular
+ operation. */
+ virtual void do_generate_ax (struct expression *exp,
+ struct agent_expr *ax,
+ struct axs_value *value,
+ struct type *cast_type)
+ {
+ error (_("Cannot translate to agent expression"));
+ }
+};
+
+/* A helper function for creating an operation_up, given a type. */
+template<typename T, typename... Arg>
+operation_up
+make_operation (Arg... args)
+{
+ return operation_up (new T (std::forward<Arg> (args)...));
+}
+
+}
+
union exp_element
{
enum exp_opcode opcode;