aboutsummaryrefslogtreecommitdiff
path: root/gdb/ada-lang.c
diff options
context:
space:
mode:
authorTom Tromey <tromey@adacore.com>2021-01-06 13:47:48 -0700
committerTom Tromey <tromey@adacore.com>2021-01-06 13:47:48 -0700
commitb49180acf205d8e52050cc05ca63f8f8630e7a9c (patch)
tree97f6648672f7c041a7648101da8ff96eaa119db7 /gdb/ada-lang.c
parent3c55062cc1d8fdb6788164a55c1e4b773c781985 (diff)
downloadfsf-binutils-gdb-b49180acf205d8e52050cc05ca63f8f8630e7a9c.zip
fsf-binutils-gdb-b49180acf205d8e52050cc05ca63f8f8630e7a9c.tar.gz
fsf-binutils-gdb-b49180acf205d8e52050cc05ca63f8f8630e7a9c.tar.bz2
Fix fixed-point binary operation type handling
Testing showed that gdb was not correctly handling some fixed-point binary operations correctly. Addition and subtraction worked by casting the result to the type of left hand operand. So, "fixed+int" had a different type -- and different value -- from "int+fixed". Furthermore, for multiplication and division, it does not make sense to first cast both sides to the fixed-point type. For example, this can prevent "f * 1" from yielding "f", if 1 is not in the domain of "f". Instead, this patch changes gdb to use the value. (This is somewhat different from Ada semantics, as those can yield a "universal fixed point".) This includes a new test case. It is only run in "minimal" mode, as the old-style fixed point works differently, and is obsolete, so I have no plans to change it. gdb/ChangeLog 2021-01-06 Tom Tromey <tromey@adacore.com> * ada-lang.c (ada_evaluate_subexp) <BINOP_ADD, BINOP_SUB>: Do not cast result. * valarith.c (fixed_point_binop): Handle multiplication and division specially. * valops.c (value_to_gdb_mpq): New function. (value_cast_to_fixed_point): Use it. gdb/testsuite/ChangeLog 2021-01-06 Tom Tromey <tromey@adacore.com> * gdb.ada/fixed_points/pck.ads (Delta4): New constant. (FP4_Type): New type. (FP4_Var): New variable. * gdb.ada/fixed_points/fixed_points.adb: Update. * gdb.ada/fixed_points.exp: Add tests for binary operators.
Diffstat (limited to 'gdb/ada-lang.c')
-rw-r--r--gdb/ada-lang.c58
1 files changed, 39 insertions, 19 deletions
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 8b20861..3bc7bdd 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -10195,18 +10195,28 @@ ada_evaluate_subexp (struct type *expect_type, struct expression *exp,
return (value_from_longest
(value_type (arg2),
value_as_long (arg1) + value_as_long (arg2)));
- if ((ada_is_gnat_encoded_fixed_point_type (value_type (arg1))
- || ada_is_gnat_encoded_fixed_point_type (value_type (arg2)))
- && value_type (arg1) != value_type (arg2))
- error (_("Operands of fixed-point addition must have the same type"));
- /* Do the addition, and cast the result to the type of the first
- argument. We cannot cast the result to a reference type, so if
- ARG1 is a reference type, find its underlying type. */
+ /* Preserve the original type for use by the range case below.
+ We cannot cast the result to a reference type, so if ARG1 is
+ a reference type, find its underlying type. */
type = value_type (arg1);
while (type->code () == TYPE_CODE_REF)
type = TYPE_TARGET_TYPE (type);
- binop_promote (exp->language_defn, exp->gdbarch, &arg1, &arg2);
- return value_cast (type, value_binop (arg1, arg2, BINOP_ADD));
+ if (ada_is_gnat_encoded_fixed_point_type (value_type (arg1))
+ || ada_is_gnat_encoded_fixed_point_type (value_type (arg2)))
+ {
+ if (value_type (arg1) != value_type (arg2))
+ error (_("Operands of fixed-point addition must have the same type"));
+ }
+ else
+ binop_promote (exp->language_defn, exp->gdbarch, &arg1, &arg2);
+ arg1 = value_binop (arg1, arg2, BINOP_ADD);
+ /* We need to special-case the result of adding to a range.
+ This is done for the benefit of "ptype". gdb's Ada support
+ historically used the LHS to set the result type here, so
+ preserve this behavior. */
+ if (type->code () == TYPE_CODE_RANGE)
+ arg1 = value_cast (type, arg1);
+ return arg1;
case BINOP_SUB:
arg1 = evaluate_subexp_with_coercion (exp, pos, noside);
@@ -10221,19 +10231,29 @@ ada_evaluate_subexp (struct type *expect_type, struct expression *exp,
return (value_from_longest
(value_type (arg2),
value_as_long (arg1) - value_as_long (arg2)));
- if ((ada_is_gnat_encoded_fixed_point_type (value_type (arg1))
- || ada_is_gnat_encoded_fixed_point_type (value_type (arg2)))
- && value_type (arg1) != value_type (arg2))
- error (_("Operands of fixed-point subtraction "
- "must have the same type"));
- /* Do the substraction, and cast the result to the type of the first
- argument. We cannot cast the result to a reference type, so if
- ARG1 is a reference type, find its underlying type. */
+ /* Preserve the original type for use by the range case below.
+ We cannot cast the result to a reference type, so if ARG1 is
+ a reference type, find its underlying type. */
type = value_type (arg1);
while (type->code () == TYPE_CODE_REF)
type = TYPE_TARGET_TYPE (type);
- binop_promote (exp->language_defn, exp->gdbarch, &arg1, &arg2);
- return value_cast (type, value_binop (arg1, arg2, BINOP_SUB));
+ if (ada_is_gnat_encoded_fixed_point_type (value_type (arg1))
+ || ada_is_gnat_encoded_fixed_point_type (value_type (arg2)))
+ {
+ if (value_type (arg1) != value_type (arg2))
+ error (_("Operands of fixed-point subtraction "
+ "must have the same type"));
+ }
+ else
+ binop_promote (exp->language_defn, exp->gdbarch, &arg1, &arg2);
+ arg1 = value_binop (arg1, arg2, BINOP_SUB);
+ /* We need to special-case the result of adding to a range.
+ This is done for the benefit of "ptype". gdb's Ada support
+ historically used the LHS to set the result type here, so
+ preserve this behavior. */
+ if (type->code () == TYPE_CODE_RANGE)
+ arg1 = value_cast (type, arg1);
+ return arg1;
case BINOP_MUL:
case BINOP_DIV: