}
else
{
+ type *type = language_bool_type (exp->language_defn,
+ exp->gdbarch);
+ if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ return value::zero (type, not_lval);
+
bool tem = value_logical_not (arg1);
if (!tem)
{
arg2 = std::get<1> (m_storage)->evaluate (nullptr, exp, noside);
tem = value_logical_not (arg2);
}
- struct type *type = language_bool_type (exp->language_defn,
- exp->gdbarch);
+
return value_from_longest (type, !tem);
}
}
}
else
{
+ type *type = language_bool_type (exp->language_defn,
+ exp->gdbarch);
+ if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ return value::zero (type, not_lval);
+
bool tem = value_logical_not (arg1);
if (tem)
{
tem = value_logical_not (arg2);
}
- struct type *type = language_bool_type (exp->language_defn,
- exp->gdbarch);
return value_from_longest (type, !tem);
}
}
op->dump (stream, depth);
}
+/* If evaluating with noside == EVAL_AVOID_SIDE_EFFECTS, we are essentially
+ interested in the type of ARG. However, if ARG is of reference type,
+ this would give us a memory value that would cause a failure if GDB
+ attempts to access the contents. Convert to the target type to avoid
+ such problems. */
+
+static value *
+convert_reference_to_target_type (value *arg, enum noside noside)
+{
+ struct type *type = check_typedef (arg->type ());
+ if (noside == EVAL_AVOID_SIDE_EFFECTS && TYPE_IS_REFERENCE (type))
+ {
+ struct type *target_type = check_typedef (type->target_type ());
+ return value::zero (target_type, not_lval);
+ }
+
+ return arg;
+}
+
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,
struct value *val
= std::get<0> (m_storage)->evaluate (nullptr, exp, noside);
- if (value_logical_not (val))
+ if (noside != EVAL_AVOID_SIDE_EFFECTS && value_logical_not (val))
return std::get<2> (m_storage)->evaluate (nullptr, exp, noside);
return std::get<1> (m_storage)->evaluate (nullptr, exp, noside);
}
= std::get<0> (m_storage)->evaluate_with_coercion (exp, noside);
value *rhs
= std::get<1> (m_storage)->evaluate_with_coercion (exp, noside);
+
+ lhs = convert_reference_to_target_type (lhs, noside);
+ rhs = convert_reference_to_target_type (rhs, noside);
+
return eval_op_add (expect_type, exp, noside, lhs, rhs);
}
= std::get<0> (m_storage)->evaluate_with_coercion (exp, noside);
value *rhs
= std::get<1> (m_storage)->evaluate_with_coercion (exp, noside);
+
+ lhs = convert_reference_to_target_type (lhs, noside);
+ rhs = convert_reference_to_target_type (rhs, noside);
+
return eval_op_sub (expect_type, exp, noside, lhs, rhs);
}
= std::get<0> (m_storage)->evaluate (nullptr, exp, noside);
value *rhs
= std::get<1> (m_storage)->evaluate (nullptr, exp, noside);
+
+ lhs = convert_reference_to_target_type (lhs, noside);
+ rhs = convert_reference_to_target_type (rhs, noside);
+
return FUNC (expect_type, exp, noside, OP, lhs, rhs);
}
value *rhs
= std::get<1> (this->m_storage)->evaluate (lhs->type (), exp,
noside);
+
+ lhs = convert_reference_to_target_type (lhs, noside);
+ rhs = convert_reference_to_target_type (rhs, noside);
+
return FUNC (expect_type, exp, noside, OP, lhs, rhs);
}
};
enum noside noside) override
{
value *val = std::get<0> (m_storage)->evaluate (nullptr, exp, noside);
+ val = convert_reference_to_target_type (val, noside);
return FUNC (expect_type, exp, noside, OP, val);
}
--- /dev/null
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2025 Free Software Foundation, Inc.
+
+ 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/>. */
+
+/* Tests that expression evaluation does not return an error if one of
+ the operands is of reference type. */
+
+struct
+{
+ int &get ()
+ {
+ return x;
+ };
+
+ int x = 1;
+} v_struct;
+
+int
+main (void)
+{
+ v_struct.get () = 2;
+ return 0;
+}
--- /dev/null
+# Copyright 2025 Free Software Foundation, Inc.
+
+# 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/>.
+
+standard_testfile .cc
+
+if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}] } {
+ return
+}
+
+runto_main
+
+# Test for reference type.
+gdb_test "print v_struct.get () == 1 && v_struct.get () == 2" \
+ " = false"
+gdb_test "print v_struct.get () == 1 || v_struct.get () == 2" \
+ " = true"
+
+# Test for correct type resolution using 'ptype'.
+gdb_test "ptype v_struct.get ()" \
+ "type = int &"
+gdb_test "ptype v_struct.get () == 1" \
+ "type = bool"
+gdb_test "ptype v_struct.get () + 1" \
+ "type = int"
+gdb_test "ptype v_struct.get () && 1" \
+ "type = bool"
+gdb_test "ptype v_struct.get () || 1" \
+ "type = bool"
+gdb_test "ptype !v_struct.get ()" \
+ "type = bool"
+gdb_test "ptype v_struct.get () ? 2 : 3" \
+ "type = int"
+gdb_test "ptype v_struct.get () | 1" \
+ "type = int"