Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* Re: [RFA] BINOP_DIV and ptyp command
@ 2008-01-30  4:00 Doug Evans
  2008-01-31 22:48 ` Daniel Jacobowitz
  0 siblings, 1 reply; 8+ messages in thread
From: Doug Evans @ 2008-01-30  4:00 UTC (permalink / raw)
  To: gdb-patches

I wrote:
> Daniel Jacobowitz wrote:
> > That's not a value-dependent error.  1 / 0 has a sensible type (it's
> > an int), but no sensible value; 1 >> 3.0 has no sensible type (it's a
> > syntax error).
> > 
> > I think of it this way:
> > 
> > drow@caradoc:~% cat a.c
> > int a = sizeof (1/0);
> > int b = sizeof (1 >> 3.0);
> > drow@caradoc:~% gcc -Wall -c a.c
> > a.c:2: error: invalid operands to binary >>
> 
> True.
> 
> As an exercise I wrote a patch that added hooks to language_defn
> to compute the result type.  I'll append that patch separately.
> It's a bit excessive, though there is value in using the language vector.
> There's also value in localizing the changes to valarith.c.
> Tell me what you want and I'll rework the patch as necessary.

Here is a patch that is equivalent to
http://sourceware.org/ml/gdb-patches/2008-01/msg00759.html
but adds entries to the language vector.
Knowing when to switch on current_language and when to add hooks to
language_defn is always a judgement call, right?
[Or are there rigid rules for one to follow?]

Of course, there may yet be a better way than either of these.

2008-01-29  Doug Evans  <dje@google.com>

	Fix argument promotion for binary arithmetic ops for C.
	Add entries in language vector so languages can have their own
	unop/binop promotion rules.
	* language.h (struct language_defn): New members la_unop_result_type,
	la_binop_result_type.
	(language_unop_result_type, language_binop_result_type): Declare.
	* language.c (language_unop_result_type): New fn.
	(language_binop_result_type): New fn.
	(unknown_language_defn): Update.
	(auto_language_defn, local_language_defn): Ditto.
	* ada-lang.c (ada_language_defn): Update.
	* c-lang.c (c_language_defn): Ditto.
	(cplus_language_defn, asm_language_defn, minimal_language_defn): Ditto.
	* f-lang.c (f_language_defn): Ditto.
	* jv-lang.c (java_language_defn): Ditto.
	* m2-lang.c (m2_language_defn): Ditto.
	* objc-lang.c (objc_language_defn): Ditto.
	* p-lang.c (pascal_language_defn): Ditto.
	* scm-lang.c (scm_language_defn): Ditto.
	* valarith.c (default_unop_result_type): New fn.
	(default_binop_result_type, c_binop_result_type): New fns.
	(value_binop): Move result type computation to language dependent hook.
	(value_pos, value_neg, value_complement): Ditto.
	* value.h (default_unop_result_type): Declare.
	(default_binop_result_type, c_binop_result_type): Declare.

	* eval.c (evaluate_subexp_standard): Fix type of result of mixed
	integer/float division operations when EVAL_AVOID_SIDE_EFFECTS.
	* valops.c (value_one): New function.
	* value.h (value_one): Declare.

	* gdb.base/whatis-exp.exp: Fix expected result of whatis x+y, x-y,
	x*y, x/y, x%y.

Index: ada-lang.c
===================================================================
RCS file: /cvs/src/src/gdb/ada-lang.c,v
retrieving revision 1.132
diff -u -p -r1.132 ada-lang.c
--- ada-lang.c	18 Jan 2008 17:07:39 -0000	1.132
+++ ada-lang.c	30 Jan 2008 01:06:41 -0000
@@ -10679,6 +10679,8 @@ const struct language_defn ada_language_
   ada_language_arch_info,
   ada_print_array_index,
   default_pass_by_reference,
+  default_unop_result_type,
+  default_binop_result_type,
   LANG_MAGIC
 };
 
Index: c-lang.c
===================================================================
RCS file: /cvs/src/src/gdb/c-lang.c,v
retrieving revision 1.51
diff -u -p -r1.51 c-lang.c
--- c-lang.c	1 Jan 2008 22:53:09 -0000	1.51
+++ c-lang.c	30 Jan 2008 01:06:44 -0000
@@ -426,6 +426,8 @@ const struct language_defn c_language_de
   c_language_arch_info,
   default_print_array_index,
   default_pass_by_reference,
+  default_unop_result_type,
+  c_binop_result_type,
   LANG_MAGIC
 };
 
@@ -538,6 +540,8 @@ const struct language_defn cplus_languag
   cplus_language_arch_info,
   default_print_array_index,
   cp_pass_by_reference,
+  default_unop_result_type,
+  c_binop_result_type,
   LANG_MAGIC
 };
 
@@ -572,6 +576,8 @@ const struct language_defn asm_language_
   c_language_arch_info, /* FIXME: la_language_arch_info.  */
   default_print_array_index,
   default_pass_by_reference,
+  default_unop_result_type,
+  c_binop_result_type,
   LANG_MAGIC
 };
 
@@ -611,6 +617,8 @@ const struct language_defn minimal_langu
   c_language_arch_info,
   default_print_array_index,
   default_pass_by_reference,
+  default_unop_result_type,
+  c_binop_result_type,
   LANG_MAGIC
 };
 
Index: eval.c
===================================================================
RCS file: /cvs/src/src/gdb/eval.c,v
retrieving revision 1.77
diff -u -p -r1.77 eval.c
--- eval.c	18 Jan 2008 17:07:39 -0000	1.77
+++ eval.c	30 Jan 2008 01:06:46 -0000
@@ -1509,11 +1509,20 @@ evaluate_subexp_standard (struct type *e
 	goto nosideret;
       if (binop_user_defined_p (op, arg1, arg2))
 	return value_x_binop (arg1, arg2, op, OP_NULL, noside);
-      else if (noside == EVAL_AVOID_SIDE_EFFECTS
-	       && (op == BINOP_DIV || op == BINOP_REM || op == BINOP_MOD))
-	return value_zero (value_type (arg1), not_lval);
       else
-	return value_binop (arg1, arg2, op);
+	{
+	  /* If EVAL_AVOID_SIDE_EFFECTS and we're dividing by zero,
+	     fudge arg2 to avoid division-by-zero, the caller is
+	     (theoretically) only looking for the type of the result.  */
+	  if (noside == EVAL_AVOID_SIDE_EFFECTS
+	      /* ??? Do we really want to test for BINOP_MOD here?
+		 The implementation of value_binop gives it a well-defined
+		 value.  */
+	      && (op == BINOP_DIV || op == BINOP_REM || op == BINOP_MOD)
+	      && value_logical_not (arg2))
+	    arg2 = value_one (value_type (arg2), not_lval);
+	  return value_binop (arg1, arg2, op);
+	}
 
     case BINOP_RANGE:
       arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
Index: f-lang.c
===================================================================
RCS file: /cvs/src/src/gdb/f-lang.c,v
retrieving revision 1.46
diff -u -p -r1.46 f-lang.c
--- f-lang.c	16 Jan 2008 11:21:42 -0000	1.46
+++ f-lang.c	30 Jan 2008 01:06:47 -0000
@@ -336,6 +336,8 @@ const struct language_defn f_language_de
   f_language_arch_info,
   default_print_array_index,
   default_pass_by_reference,
+  default_unop_result_type,
+  default_binop_result_type,
   LANG_MAGIC
 };
 
Index: jv-lang.c
===================================================================
RCS file: /cvs/src/src/gdb/jv-lang.c,v
retrieving revision 1.54
diff -u -p -r1.54 jv-lang.c
--- jv-lang.c	1 Jan 2008 22:53:11 -0000	1.54
+++ jv-lang.c	30 Jan 2008 01:06:48 -0000
@@ -1082,6 +1082,8 @@ const struct language_defn java_language
   c_language_arch_info,
   default_print_array_index,
   default_pass_by_reference,
+  default_unop_result_type,
+  default_binop_result_type,
   LANG_MAGIC
 };
 
Index: language.c
===================================================================
RCS file: /cvs/src/src/gdb/language.c,v
retrieving revision 1.73
diff -u -p -r1.73 language.c
--- language.c	3 Jan 2008 04:23:46 -0000	1.73
+++ language.c	30 Jan 2008 01:06:49 -0000
@@ -521,6 +521,23 @@ language_info (int quietly)
     }
 }
 \f
+/* Return type of result of arithmetic unop operation OP on ARG1.  */
+
+struct type *
+language_unop_result_type (enum exp_opcode op, struct type *type1)
+{
+  return current_language->la_unop_result_type (op, type1);
+}
+
+/* Return type of result of arithmetic binop operation OP on ARG1, ARG2.  */
+
+struct type *
+language_binop_result_type (enum exp_opcode op,
+			    struct type *type1, struct type *type2)
+{
+  return current_language->la_binop_result_type (op, type1, type2);
+}
+
 /* Return the result of a binary operation. */
 
 #if 0				/* Currently unused */
@@ -1204,6 +1221,8 @@ const struct language_defn unknown_langu
   unknown_language_arch_info,	/* la_language_arch_info.  */
   default_print_array_index,
   default_pass_by_reference,
+  default_unop_result_type,
+  default_binop_result_type,
   LANG_MAGIC
 };
 
@@ -1239,6 +1258,8 @@ const struct language_defn auto_language
   unknown_language_arch_info,	/* la_language_arch_info.  */
   default_print_array_index,
   default_pass_by_reference,
+  default_unop_result_type,
+  default_binop_result_type,
   LANG_MAGIC
 };
 
@@ -1273,6 +1294,8 @@ const struct language_defn local_languag
   unknown_language_arch_info,	/* la_language_arch_info.  */
   default_print_array_index,
   default_pass_by_reference,
+  default_unop_result_type,
+  default_binop_result_type,
   LANG_MAGIC
 };
 \f
Index: language.h
===================================================================
RCS file: /cvs/src/src/gdb/language.h,v
retrieving revision 1.47
diff -u -p -r1.47 language.h
--- language.h	1 Jan 2008 22:53:11 -0000	1.47
+++ language.h	30 Jan 2008 01:06:49 -0000
@@ -263,6 +263,15 @@ struct language_defn
        reference at the language level.  */
     int (*la_pass_by_reference) (struct type *type);
 
+    /* Return the type of the result of unary OP on TYPE1.  */
+    struct type *(*la_unop_result_type) (enum exp_opcode op,
+					 struct type *type1);
+
+    /* Return the type of the result of binary OP on TYPE1, TYPE2.  */
+    struct type *(*la_binop_result_type) (enum exp_opcode op,
+					  struct type *type1,
+					  struct type *type2);
+
     /* Add fields above this point, so the magic number is always last. */
     /* Magic number for compat checking */
 
@@ -412,6 +421,15 @@ extern void type_error (const char *, ..
 
 extern void range_error (const char *, ...) ATTR_FORMAT (printf, 1, 2);
 
+/* Arithmetic expression result types.  */
+
+extern struct type *language_unop_result_type (enum exp_opcode op,
+					       struct type *type1);
+
+extern struct type *language_binop_result_type (enum exp_opcode op,
+						struct type *type1,
+						struct type *type2);
+
 /* Data:  Does this value represent "truth" to the current language?  */
 
 extern int value_true (struct value *);
Index: m2-lang.c
===================================================================
RCS file: /cvs/src/src/gdb/m2-lang.c,v
retrieving revision 1.37
diff -u -p -r1.37 m2-lang.c
--- m2-lang.c	1 Jan 2008 22:53:11 -0000	1.37
+++ m2-lang.c	30 Jan 2008 01:06:50 -0000
@@ -387,6 +387,8 @@ const struct language_defn m2_language_d
   m2_language_arch_info,
   default_print_array_index,
   default_pass_by_reference,
+  default_unop_result_type,
+  default_binop_result_type,
   LANG_MAGIC
 };
 
Index: objc-lang.c
===================================================================
RCS file: /cvs/src/src/gdb/objc-lang.c,v
retrieving revision 1.63
diff -u -p -r1.63 objc-lang.c
--- objc-lang.c	1 Jan 2008 22:53:12 -0000	1.63
+++ objc-lang.c	30 Jan 2008 01:06:54 -0000
@@ -521,6 +521,8 @@ const struct language_defn objc_language
   c_language_arch_info,
   default_print_array_index,
   default_pass_by_reference,
+  default_unop_result_type,
+  default_binop_result_type,
   LANG_MAGIC
 };
 
Index: p-lang.c
===================================================================
RCS file: /cvs/src/src/gdb/p-lang.c,v
retrieving revision 1.37
diff -u -p -r1.37 p-lang.c
--- p-lang.c	1 Jan 2008 22:53:12 -0000	1.37
+++ p-lang.c	30 Jan 2008 01:06:55 -0000
@@ -426,6 +426,8 @@ const struct language_defn pascal_langua
   pascal_language_arch_info,
   default_print_array_index,
   default_pass_by_reference,
+  default_unop_result_type,
+  default_binop_result_type,
   LANG_MAGIC
 };
 
Index: scm-lang.c
===================================================================
RCS file: /cvs/src/src/gdb/scm-lang.c,v
retrieving revision 1.42
diff -u -p -r1.42 scm-lang.c
--- scm-lang.c	1 Jan 2008 22:53:12 -0000	1.42
+++ scm-lang.c	30 Jan 2008 01:06:55 -0000
@@ -265,6 +265,8 @@ const struct language_defn scm_language_
   c_language_arch_info,
   default_print_array_index,
   default_pass_by_reference,
+  default_unop_result_type,
+  default_binop_result_type,
   LANG_MAGIC
 };
 
Index: valarith.c
===================================================================
RCS file: /cvs/src/src/gdb/valarith.c,v
retrieving revision 1.55
diff -u -p -r1.55 valarith.c
--- valarith.c	29 Jan 2008 14:24:43 -0000	1.55
+++ valarith.c	30 Jan 2008 01:06:56 -0000
@@ -742,6 +742,451 @@ value_concat (struct value *arg1, struct
   return (outval);
 }
 \f
+/* Default implementation of la_unop_result_type.
+   Return type of OP performed on TYPE1.
+   The result type follows ANSI C rules.  If not appropropriate for any
+   particular language then it needs to supply its own la_unop_result_type
+   function.  */
+
+struct type *
+default_unop_result_type (enum exp_opcode op, struct type *type1)
+{
+  struct type *result_type;
+
+  type1 = check_typedef (type1);
+  result_type = type1;
+
+  switch (op)
+    {
+    case UNOP_PLUS:
+    case UNOP_NEG:
+      break;
+    case UNOP_COMPLEMENT:
+      /* Reject floats and decimal floats.  */
+      if (!is_integral_type (type1))
+	error (_("Argument to complement operation not an integer or boolean."));
+      break;
+    default:
+      error (_("Invalid unary operation on numbers."));
+    }
+
+  if (TYPE_CODE (type1) == TYPE_CODE_DECFLOAT
+      || TYPE_CODE (type1) == TYPE_CODE_FLT)
+    {
+      return result_type;
+    }
+  else if (is_integral_type (type1))
+    {
+      /* Perform integral promotion for ANSI C/C++.
+	 If not appropropriate for any particular language it needs to
+	 supply its own la_unop_result_type function.  */
+      if (TYPE_LENGTH (type1) < TYPE_LENGTH (builtin_type_int))
+	result_type = builtin_type_int;
+
+      return result_type;
+    }
+  else
+    {
+      error (_("Argument to unary operation not a number."));
+      return 0; /* For lint -- never reached */
+    }
+}
+
+/* Default implementation of la_binop_result_type.
+   Return type of OP performed on TYPE1, TYPE2.
+   The result isn't ANSI-C compatible for backward compatibility.
+   The result type is that used by gdb 6.7 before languages could specify it.
+   The result type is either long or long long, signed or unsigned.
+   If not appropropriate for any particular language then it needs to supply
+   its own la_binop_result_type function.  */
+
+struct type *
+default_binop_result_type (enum exp_opcode op,
+			   struct type *type1, struct type *type2)
+{
+  type1 = check_typedef (type1);
+  type2 = check_typedef (type2);
+
+  if ((TYPE_CODE (type1) != TYPE_CODE_FLT
+       && TYPE_CODE (type1) != TYPE_CODE_DECFLOAT
+       && !is_integral_type (type1))
+      ||
+      (TYPE_CODE (type2) != TYPE_CODE_FLT
+       && TYPE_CODE (type2) != TYPE_CODE_DECFLOAT
+       && !is_integral_type (type2)))
+    error (_("Argument to arithmetic operation not a number or boolean."));
+
+  if (TYPE_CODE (type1) == TYPE_CODE_DECFLOAT
+      || TYPE_CODE (type2) == TYPE_CODE_DECFLOAT)
+    {
+      struct type *result_type;
+
+      switch (op)
+	{
+	case BINOP_ADD:
+	case BINOP_SUB:
+	case BINOP_MUL:
+	case BINOP_DIV:
+	case BINOP_EXP:
+	  break;
+	default:
+	  error (_("Operation not valid for decimal floating point number."));
+	}
+
+      if (TYPE_CODE (type1) != TYPE_CODE_DECFLOAT)
+	/* If type1 is not a decimal float, the type of the result is the type
+	   of the decimal float argument, type2.  */
+	result_type = type2;
+      else if (TYPE_CODE (type2) != TYPE_CODE_DECFLOAT)
+	/* Same logic, for the case where type2 is not a decimal float.  */
+	result_type = type1;
+      else
+	/* Both are decimal floats, the type of the result is the bigger
+	   of the two.  */
+	result_type =
+	  (TYPE_LENGTH (type1) > TYPE_LENGTH (type2)) ? type1 : type2;
+
+      return result_type;
+    }
+  else if (TYPE_CODE (type1) == TYPE_CODE_FLT
+	   || TYPE_CODE (type2) == TYPE_CODE_FLT)
+    {
+      struct type *result_type;
+
+      switch (op)
+	{
+	case BINOP_ADD:
+	case BINOP_SUB:
+	case BINOP_MUL:
+	case BINOP_DIV:
+	case BINOP_EXP:
+	  break;
+	default:
+	  error (_("Integer-only operation on floating point number."));
+	}
+
+      /* If either arg was long double, make sure that value is also long
+         double.  */
+
+      if (TYPE_LENGTH (type1) * 8 > gdbarch_double_bit (current_gdbarch)
+	  || TYPE_LENGTH (type2) * 8 > gdbarch_double_bit (current_gdbarch))
+	result_type = builtin_type_long_double;
+      else
+	result_type = builtin_type_double;
+
+      return result_type;
+    }
+  else if (TYPE_CODE (type1) == TYPE_CODE_BOOL
+	   && TYPE_CODE (type2) == TYPE_CODE_BOOL)
+    {
+      switch (op)
+	{
+	case BINOP_BITWISE_AND:
+	case BINOP_BITWISE_IOR:
+	case BINOP_BITWISE_XOR:
+        case BINOP_EQUAL:
+        case BINOP_NOTEQUAL:
+	  break;
+	default:
+	  error (_("Invalid operation on booleans."));
+	}
+
+      return type1;
+    }
+  else
+    /* Integral operations here.  */
+    /* FIXME: Also mixed integral/booleans, with result an integer.  */
+    {
+      unsigned int promoted_len1 = TYPE_LENGTH (type1);
+      unsigned int promoted_len2 = TYPE_LENGTH (type2);
+      int is_unsigned1 = TYPE_UNSIGNED (type1);
+      int is_unsigned2 = TYPE_UNSIGNED (type2);
+      unsigned int result_len;
+      int unsigned_operation;
+
+      /* Determine type length and signedness after promotion for
+         both operands.  */
+      if (promoted_len1 < TYPE_LENGTH (builtin_type_int))
+	{
+	  is_unsigned1 = 0;
+	  promoted_len1 = TYPE_LENGTH (builtin_type_int);
+	}
+      if (promoted_len2 < TYPE_LENGTH (builtin_type_int))
+	{
+	  is_unsigned2 = 0;
+	  promoted_len2 = TYPE_LENGTH (builtin_type_int);
+	}
+
+      /* Determine type length of the result, and if the operation should
+         be done unsigned.
+         Use the signedness of the operand with the greater length.
+         If both operands are of equal length, use unsigned operation
+         if one of the operands is unsigned.  */
+      if (op == BINOP_RSH || op == BINOP_LSH)
+	{
+	  /* In case of the shift operators the type of the result only
+	     depends on the type of the left operand.  */
+	  unsigned_operation = is_unsigned1;
+	  result_len = promoted_len1;
+	}
+      else if (promoted_len1 > promoted_len2)
+	{
+	  unsigned_operation = is_unsigned1;
+	  result_len = promoted_len1;
+	}
+      else if (promoted_len2 > promoted_len1)
+	{
+	  unsigned_operation = is_unsigned2;
+	  result_len = promoted_len2;
+	}
+      else
+	{
+	  unsigned_operation = is_unsigned1 || is_unsigned2;
+	  result_len = promoted_len1;
+	}
+
+      switch (op)
+	{
+	case BINOP_ADD:
+	case BINOP_SUB:
+	case BINOP_MUL:
+	case BINOP_DIV:
+	case BINOP_INTDIV:
+	case BINOP_EXP:
+	case BINOP_REM:
+	case BINOP_MOD:
+	case BINOP_LSH:
+	case BINOP_RSH:
+	case BINOP_BITWISE_AND:
+	case BINOP_BITWISE_IOR:
+	case BINOP_BITWISE_XOR:
+	case BINOP_LOGICAL_AND:
+	case BINOP_LOGICAL_OR:
+	case BINOP_MIN:
+	case BINOP_MAX:
+	case BINOP_EQUAL:
+	case BINOP_NOTEQUAL:
+	case BINOP_LESS:
+	  break;
+
+	default:
+	  error (_("Invalid binary operation on numbers."));
+	}
+
+      if (unsigned_operation)
+	{
+	  if (result_len > gdbarch_long_bit (current_gdbarch) / HOST_CHAR_BIT)
+	    return builtin_type_unsigned_long_long;
+	  else
+	    return builtin_type_unsigned_long;
+	}
+      else
+	{
+	  if (result_len > gdbarch_long_bit (current_gdbarch) / HOST_CHAR_BIT)
+	    return builtin_type_long_long;
+	  else
+	    return builtin_type_long;
+	}
+    }
+}
+
+/* C/C++ implementation of la_binop_result_type.
+   Return type of OP performed on TYPE1, TYPE2.
+   The result is correct for ANSI C.  */
+
+struct type *
+c_binop_result_type (enum exp_opcode op,
+		     struct type *type1, struct type *type2)
+{
+  type1 = check_typedef (type1);
+  type2 = check_typedef (type2);
+
+  if ((TYPE_CODE (type1) != TYPE_CODE_FLT
+       && TYPE_CODE (type1) != TYPE_CODE_DECFLOAT
+       && !is_integral_type (type1))
+      ||
+      (TYPE_CODE (type2) != TYPE_CODE_FLT
+       && TYPE_CODE (type2) != TYPE_CODE_DECFLOAT
+       && !is_integral_type (type2)))
+    error (_("Argument to arithmetic operation not a number or boolean."));
+
+  if (TYPE_CODE (type1) == TYPE_CODE_DECFLOAT
+      || TYPE_CODE (type2) == TYPE_CODE_DECFLOAT)
+    {
+      struct type *result_type;
+
+      switch (op)
+	{
+	case BINOP_ADD:
+	case BINOP_SUB:
+	case BINOP_MUL:
+	case BINOP_DIV:
+	case BINOP_EXP:
+	  break;
+	default:
+	  error (_("Operation not valid for decimal floating point number."));
+	}
+
+      if (TYPE_CODE (type1) != TYPE_CODE_DECFLOAT)
+	/* If type1 is not a decimal float, the type of the result is the type
+	   of the decimal float argument, type2.  */
+	result_type = type2;
+      else if (TYPE_CODE (type2) != TYPE_CODE_DECFLOAT)
+	/* Same logic, for the case where type2 is not a decimal float.  */
+	result_type = type1;
+      else
+	/* Both are decimal floats, the type of the result is the bigger
+	   of the two.  */
+	result_type =
+	  (TYPE_LENGTH (type1) > TYPE_LENGTH (type2)) ? type1 : type2;
+
+      return result_type;
+    }
+  else if (TYPE_CODE (type1) == TYPE_CODE_FLT
+	   || TYPE_CODE (type2) == TYPE_CODE_FLT)
+    {
+      struct type *result_type;
+
+      switch (op)
+	{
+	case BINOP_ADD:
+	case BINOP_SUB:
+	case BINOP_MUL:
+	case BINOP_DIV:
+	case BINOP_EXP:
+	  break;
+	default:
+	  error (_("Integer-only operation on floating point number."));
+	}
+
+      /* If either arg was long double, make sure that value is also long
+         double.  */
+
+      if (TYPE_LENGTH (type1) * 8 > gdbarch_double_bit (current_gdbarch)
+	  || TYPE_LENGTH (type2) * 8 > gdbarch_double_bit (current_gdbarch))
+	result_type = builtin_type_long_double;
+      else
+	result_type = builtin_type_double;
+
+      return result_type;
+    }
+  else if (TYPE_CODE (type1) == TYPE_CODE_BOOL
+	   && TYPE_CODE (type2) == TYPE_CODE_BOOL)
+    {
+      switch (op)
+	{
+	case BINOP_BITWISE_AND:
+	case BINOP_BITWISE_IOR:
+	case BINOP_BITWISE_XOR:
+        case BINOP_EQUAL:
+        case BINOP_NOTEQUAL:
+	  break;
+	default:
+	  error (_("Invalid operation on booleans."));
+	}
+
+      return type1;
+    }
+  else
+    /* Integral operations here.  */
+    /* FIXME: Also mixed integral/booleans, with result an integer.  */
+    {
+      unsigned int promoted_len1 = TYPE_LENGTH (type1);
+      unsigned int promoted_len2 = TYPE_LENGTH (type2);
+      int is_unsigned1 = TYPE_UNSIGNED (type1);
+      int is_unsigned2 = TYPE_UNSIGNED (type2);
+      unsigned int result_len;
+      int unsigned_operation;
+
+      /* Determine type length and signedness after promotion for
+         both operands.  */
+      if (promoted_len1 < TYPE_LENGTH (builtin_type_int))
+	{
+	  is_unsigned1 = 0;
+	  promoted_len1 = TYPE_LENGTH (builtin_type_int);
+	}
+      if (promoted_len2 < TYPE_LENGTH (builtin_type_int))
+	{
+	  is_unsigned2 = 0;
+	  promoted_len2 = TYPE_LENGTH (builtin_type_int);
+	}
+
+      /* Determine type length of the result, and if the operation should
+         be done unsigned.
+         Use the signedness of the operand with the greater length.
+         If both operands are of equal length, use unsigned operation
+         if one of the operands is unsigned.  */
+      if (op == BINOP_RSH || op == BINOP_LSH)
+	{
+	  /* In case of the shift operators the type of the result only
+	     depends on the type of the left operand.  */
+	  unsigned_operation = is_unsigned1;
+	  result_len = promoted_len1;
+	}
+      else if (promoted_len1 > promoted_len2)
+	{
+	  unsigned_operation = is_unsigned1;
+	  result_len = promoted_len1;
+	}
+      else if (promoted_len2 > promoted_len1)
+	{
+	  unsigned_operation = is_unsigned2;
+	  result_len = promoted_len2;
+	}
+      else
+	{
+	  unsigned_operation = is_unsigned1 || is_unsigned2;
+	  result_len = promoted_len1;
+	}
+
+      switch (op)
+	{
+	case BINOP_ADD:
+	case BINOP_SUB:
+	case BINOP_MUL:
+	case BINOP_DIV:
+	case BINOP_INTDIV:
+	case BINOP_EXP:
+	case BINOP_REM:
+	case BINOP_MOD:
+	case BINOP_LSH:
+	case BINOP_RSH:
+	case BINOP_BITWISE_AND:
+	case BINOP_BITWISE_IOR:
+	case BINOP_BITWISE_XOR:
+	case BINOP_LOGICAL_AND:
+	case BINOP_LOGICAL_OR:
+	case BINOP_MIN:
+	case BINOP_MAX:
+	case BINOP_EQUAL:
+	case BINOP_NOTEQUAL:
+	case BINOP_LESS:
+	  break;
+
+	default:
+	  error (_("Invalid binary operation on numbers."));
+	}
+
+      if (result_len <= TYPE_LENGTH (builtin_type_int))
+	{
+	  return (unsigned_operation
+		  ? builtin_type_unsigned_int
+		  : builtin_type_int);
+	}
+      else if (result_len <= TYPE_LENGTH (builtin_type_long))
+	{
+	  return (unsigned_operation
+		  ? builtin_type_unsigned_long
+		  : builtin_type_long);
+	}
+      else
+	{
+	  return (unsigned_operation
+		  ? builtin_type_unsigned_long_long
+		  : builtin_type_long_long);
+	}
+    }
+}
 
 /* Obtain decimal value of arguments for binary operation, converting from
    other types if one of them is not decimal floating point.  */
@@ -810,23 +1255,15 @@ struct value *
 value_binop (struct value *arg1, struct value *arg2, enum exp_opcode op)
 {
   struct value *val;
-  struct type *type1, *type2;
+  struct type *result_type;
 
   arg1 = coerce_ref (arg1);
   arg2 = coerce_ref (arg2);
-  type1 = check_typedef (value_type (arg1));
-  type2 = check_typedef (value_type (arg2));
 
-  if ((TYPE_CODE (type1) != TYPE_CODE_FLT
-       && TYPE_CODE (type1) != TYPE_CODE_DECFLOAT && !is_integral_type (type1))
-      ||
-      (TYPE_CODE (type2) != TYPE_CODE_FLT
-       && TYPE_CODE (type2) != TYPE_CODE_DECFLOAT && !is_integral_type (type2)))
-    error (_("Argument to arithmetic operation not a number or boolean."));
+  result_type = language_binop_result_type (op, value_type (arg1),
+					    value_type (arg2));
 
-  if (TYPE_CODE (type1) == TYPE_CODE_DECFLOAT
-      ||
-      TYPE_CODE (type2) == TYPE_CODE_DECFLOAT)
+  if (TYPE_CODE (result_type) == TYPE_CODE_DECFLOAT)
     {
       struct type *v_type;
       int len_v1, len_v2, len_v;
@@ -849,23 +1286,9 @@ value_binop (struct value *arg1, struct 
 	  error (_("Operation not valid for decimal floating point number."));
 	}
 
-      if (TYPE_CODE (type1) != TYPE_CODE_DECFLOAT)
-	/* If arg1 is not a decimal float, the type of the result is the type
-	   of the decimal float argument, arg2.  */
-	v_type = type2;
-      else if (TYPE_CODE (type2) != TYPE_CODE_DECFLOAT)
-	/* Same logic, for the case where arg2 is not a decimal float.  */
-	v_type = type1;
-      else
-	/* len_v is equal either to len_v1 or to len_v2.  the type of the
-	   result is the type of the argument with the same length as v.  */
-	v_type = (len_v == len_v1)? type1 : type2;
-
-      val = value_from_decfloat (v_type, v);
+      val = value_from_decfloat (result_type, v);
     }
-  else if (TYPE_CODE (type1) == TYPE_CODE_FLT
-	   ||
-	   TYPE_CODE (type2) == TYPE_CODE_FLT)
+  else if (TYPE_CODE (result_type) == TYPE_CODE_FLT)
     {
       /* FIXME-if-picky-about-floating-accuracy: Should be doing this
          in target format.  real.c in GCC probably has the necessary
@@ -902,20 +1325,10 @@ value_binop (struct value *arg1, struct 
 	  error (_("Integer-only operation on floating point number."));
 	}
 
-      /* If either arg was long double, make sure that value is also long
-         double.  */
-
-      if (TYPE_LENGTH (type1) * 8 > gdbarch_double_bit (current_gdbarch)
-	  || TYPE_LENGTH (type2) * 8 > gdbarch_double_bit (current_gdbarch))
-	val = allocate_value (builtin_type_long_double);
-      else
-	val = allocate_value (builtin_type_double);
-
+      val = allocate_value (result_type);
       store_typed_floating (value_contents_raw (val), value_type (val), v);
     }
-  else if (TYPE_CODE (type1) == TYPE_CODE_BOOL
-	   &&
-	   TYPE_CODE (type2) == TYPE_CODE_BOOL)
+  else if (TYPE_CODE (result_type) == TYPE_CODE_BOOL)
     {
       LONGEST v1, v2, v = 0;
       v1 = value_as_long (arg1);
@@ -947,72 +1360,32 @@ value_binop (struct value *arg1, struct 
 	  error (_("Invalid operation on booleans."));
 	}
 
-      val = allocate_value (type1);
+      val = allocate_value (result_type);
       store_signed_integer (value_contents_raw (val),
-			    TYPE_LENGTH (type1),
+			    TYPE_LENGTH (result_type),
 			    v);
     }
   else
     /* Integral operations here.  */
-    /* FIXME:  Also mixed integral/booleans, with result an integer. */
-    /* FIXME: This implements ANSI C rules (also correct for C++).
-       What about FORTRAN and (the deleted) chill ?  */
     {
-      unsigned int promoted_len1 = TYPE_LENGTH (type1);
-      unsigned int promoted_len2 = TYPE_LENGTH (type2);
-      int is_unsigned1 = TYPE_UNSIGNED (type1);
-      int is_unsigned2 = TYPE_UNSIGNED (type2);
-      unsigned int result_len;
-      int unsigned_operation;
-
-      /* Determine type length and signedness after promotion for
-         both operands.  */
-      if (promoted_len1 < TYPE_LENGTH (builtin_type_int))
-	{
-	  is_unsigned1 = 0;
-	  promoted_len1 = TYPE_LENGTH (builtin_type_int);
-	}
-      if (promoted_len2 < TYPE_LENGTH (builtin_type_int))
-	{
-	  is_unsigned2 = 0;
-	  promoted_len2 = TYPE_LENGTH (builtin_type_int);
-	}
-
-      /* Determine type length of the result, and if the operation should
-         be done unsigned.
-         Use the signedness of the operand with the greater length.
-         If both operands are of equal length, use unsigned operation
-         if one of the operands is unsigned.  */
-      if (op == BINOP_RSH || op == BINOP_LSH)
-	{
-	  /* In case of the shift operators the type of the result only
-	     depends on the type of the left operand.  */
-	  unsigned_operation = is_unsigned1;
-	  result_len = promoted_len1;
-	}
-      else if (promoted_len1 > promoted_len2)
-	{
-	  unsigned_operation = is_unsigned1;
-	  result_len = promoted_len1;
-	}
-      else if (promoted_len2 > promoted_len1)
-	{
-	  unsigned_operation = is_unsigned2;
-	  result_len = promoted_len2;
-	}
-      else
-	{
-	  unsigned_operation = is_unsigned1 || is_unsigned2;
-	  result_len = promoted_len1;
-	}
+      int unsigned_operation = TYPE_UNSIGNED (result_type);
 
       if (unsigned_operation)
 	{
+	  unsigned int len1, len2, result_len;
 	  ULONGEST v1, v2, v = 0;
 	  v1 = (ULONGEST) value_as_long (arg1);
 	  v2 = (ULONGEST) value_as_long (arg2);
 
-	  /* Truncate values to the type length of the result.  */
+	  /* Truncate values to the type length of the result.
+	     Things are mildly trick because language_binop_result_type may
+	     return a long which on amd64 is 8 bytes, and that's a problem if
+	     ARG1, ARG2 are both <= 4 bytes.  We need to truncate the values
+	     at 4 bytes not 8.  So fetch the lengths of the original types
+	     and truncate at the larger of the two.  */
+	  len1 = TYPE_LENGTH (value_type (arg1));
+	  len2 = TYPE_LENGTH (value_type (arg1));
+	  result_len = len1 > len2 ? len1 : len2;
 	  if (result_len < sizeof (ULONGEST))
 	    {
 	      v1 &= ((LONGEST) 1 << HOST_CHAR_BIT * result_len) - 1;
@@ -1119,19 +1492,7 @@ value_binop (struct value *arg1, struct 
 	      error (_("Invalid binary operation on numbers."));
 	    }
 
-	  /* This is a kludge to get around the fact that we don't
-	     know how to determine the result type from the types of
-	     the operands.  (I'm not really sure how much we feel the
-	     need to duplicate the exact rules of the current
-	     language.  They can get really hairy.  But not to do so
-	     makes it hard to document just what we *do* do).  */
-
-	  /* Can't just call init_type because we wouldn't know what
-	     name to give the type.  */
-	  val = allocate_value
-	    (result_len > gdbarch_long_bit (current_gdbarch) / HOST_CHAR_BIT
-	     ? builtin_type_unsigned_long_long
-	     : builtin_type_unsigned_long);
+	  val = allocate_value (result_type);
 	  store_unsigned_integer (value_contents_raw (val),
 				  TYPE_LENGTH (value_type (val)),
 				  v);
@@ -1245,19 +1606,7 @@ value_binop (struct value *arg1, struct 
 	      error (_("Invalid binary operation on numbers."));
 	    }
 
-	  /* This is a kludge to get around the fact that we don't
-	     know how to determine the result type from the types of
-	     the operands.  (I'm not really sure how much we feel the
-	     need to duplicate the exact rules of the current
-	     language.  They can get really hairy.  But not to do so
-	     makes it hard to document just what we *do* do).  */
-
-	  /* Can't just call init_type because we wouldn't know what
-	     name to give the type.  */
-	  val = allocate_value
-	    (result_len > gdbarch_long_bit (current_gdbarch) / HOST_CHAR_BIT
-	     ? builtin_type_long_long
-	     : builtin_type_long);
+	  val = allocate_value (result_type);
 	  store_signed_integer (value_contents_raw (val),
 				TYPE_LENGTH (value_type (val)),
 				v);
@@ -1469,23 +1818,19 @@ struct value *
 value_pos (struct value *arg1)
 {
   struct type *type;
+  struct type *result_type;
 
   arg1 = coerce_ref (arg1);
-
   type = check_typedef (value_type (arg1));
+  result_type = language_unop_result_type (UNOP_PLUS, value_type (arg1));
 
   if (TYPE_CODE (type) == TYPE_CODE_FLT)
-    return value_from_double (type, value_as_double (arg1));
+    return value_from_double (result_type, value_as_double (arg1));
   else if (TYPE_CODE (type) == TYPE_CODE_DECFLOAT)
-    return value_from_decfloat (type, value_contents (arg1));
+    return value_from_decfloat (result_type, value_contents (arg1));
   else if (is_integral_type (type))
     {
-      /* Perform integral promotion for ANSI C/C++.  FIXME: What about
-         FORTRAN and (the deleted) chill ?  */
-      if (TYPE_LENGTH (type) < TYPE_LENGTH (builtin_type_int))
-	type = builtin_type_int;
-
-      return value_from_longest (type, value_as_long (arg1));
+      return value_from_longest (result_type, value_as_long (arg1));
     }
   else
     {
@@ -1498,11 +1843,11 @@ struct value *
 value_neg (struct value *arg1)
 {
   struct type *type;
-  struct type *result_type = value_type (arg1);
+  struct type *result_type;
 
   arg1 = coerce_ref (arg1);
-
   type = check_typedef (value_type (arg1));
+  result_type = language_unop_result_type (UNOP_NEG, value_type (arg1));
 
   if (TYPE_CODE (type) == TYPE_CODE_DECFLOAT)
     {
@@ -1520,16 +1865,10 @@ value_neg (struct value *arg1)
       memcpy (value_contents_raw (val), decbytes, len);
       return val;
     }
-
-  if (TYPE_CODE (type) == TYPE_CODE_FLT)
+  else if (TYPE_CODE (type) == TYPE_CODE_FLT)
     return value_from_double (result_type, -value_as_double (arg1));
   else if (is_integral_type (type))
     {
-      /* Perform integral promotion for ANSI C/C++.  FIXME: What about
-         FORTRAN and (the deleted) chill ?  */
-      if (TYPE_LENGTH (type) < TYPE_LENGTH (builtin_type_int))
-	result_type = builtin_type_int;
-
       return value_from_longest (result_type, -value_as_long (arg1));
     }
   else
@@ -1543,20 +1882,15 @@ struct value *
 value_complement (struct value *arg1)
 {
   struct type *type;
-  struct type *result_type = value_type (arg1);
+  struct type *result_type;
 
   arg1 = coerce_ref (arg1);
-
   type = check_typedef (value_type (arg1));
+  result_type = language_unop_result_type (UNOP_COMPLEMENT, value_type (arg1));
 
   if (!is_integral_type (type))
     error (_("Argument to complement operation not an integer or boolean."));
 
-  /* Perform integral promotion for ANSI C/C++.
-     FIXME: What about FORTRAN ?  */
-  if (TYPE_LENGTH (type) < TYPE_LENGTH (builtin_type_int))
-    result_type = builtin_type_int;
-
   return value_from_longest (result_type, ~value_as_long (arg1));
 }
 \f
Index: valops.c
===================================================================
RCS file: /cvs/src/src/gdb/valops.c,v
retrieving revision 1.182
diff -u -p -r1.182 valops.c
--- valops.c	18 Jan 2008 17:07:40 -0000	1.182
+++ valops.c	30 Jan 2008 01:06:58 -0000
@@ -471,6 +471,41 @@ value_zero (struct type *type, enum lval
   return val;
 }
 
+/* Create a value of numeric type TYPE that is one, and return it.  */
+
+struct value *
+value_one (struct type *type, enum lval_type lv)
+{
+  struct type *type1 = check_typedef (type);
+  struct value *val;
+
+  if (TYPE_CODE (type1) == TYPE_CODE_DECFLOAT)
+    {
+      struct value *int_one = value_from_longest (builtin_type_int, 1);
+      struct value *val;
+      gdb_byte v[16];
+
+      decimal_from_integral (int_one, v, TYPE_LENGTH (builtin_type_int));
+      val = value_from_decfloat (type, v);
+      value_free (int_one);
+    }
+  else if (TYPE_CODE (type1) == TYPE_CODE_FLT)
+    {
+      val = value_from_double (type, (DOUBLEST) 1);
+    }
+  else if (is_integral_type (type1))
+    {
+      val = value_from_longest (type, (LONGEST) 1);
+    }
+  else
+    {
+      error (_("Not a numeric type."));
+    }
+
+  VALUE_LVAL (val) = lv;
+  return val;
+}
+
 /* Return a value with type TYPE located at ADDR.
 
    Call value_at only if the data needs to be fetched immediately;
Index: value.h
===================================================================
RCS file: /cvs/src/src/gdb/value.h,v
retrieving revision 1.107
diff -u -p -r1.107 value.h
--- value.h	18 Jan 2008 17:07:40 -0000	1.107
+++ value.h	30 Jan 2008 01:06:59 -0000
@@ -325,6 +325,21 @@ extern struct value *value_array (int lo
 
 extern struct value *value_concat (struct value *arg1, struct value *arg2);
 
+/* Default implementations of la_unop_result_type,la_binop_result_type
+   return the type used by gdb 6.7 (and earlier).
+   Languages that don't have their own implementation use this until they
+   add their own.  */
+extern struct type *default_unop_result_type (enum exp_opcode op,
+					      struct type *type1);
+extern struct type *default_binop_result_type (enum exp_opcode op,
+					       struct type *type1,
+					       struct type *type2);
+/* C/C++ implementation of same.
+   default_unop_result_type is correct for ANSI C so we use that.  */
+extern struct type *c_binop_result_type (enum exp_opcode op,
+					 struct type *type1,
+					 struct type *type2);
+
 extern struct value *value_binop (struct value *arg1, struct value *arg2,
 				  enum exp_opcode op);
 
@@ -392,6 +407,8 @@ extern struct value *value_cast (struct 
 
 extern struct value *value_zero (struct type *type, enum lval_type lv);
 
+extern struct value *value_one (struct type *type, enum lval_type lv);
+
 extern struct value *value_repeat (struct value *arg1, int count);
 
 extern struct value *value_subscript (struct value *array, struct value *idx);
Index: testsuite/gdb.base/whatis-exp.exp
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/gdb.base/whatis-exp.exp,v
retrieving revision 1.7
diff -u -p -r1.7 whatis-exp.exp
--- testsuite/gdb.base/whatis-exp.exp	1 Jan 2008 22:53:19 -0000	1.7
+++ testsuite/gdb.base/whatis-exp.exp	30 Jan 2008 01:07:01 -0000
@@ -112,7 +112,7 @@ gdb_expect {
 
 send_gdb "whatis x+y\n"
 gdb_expect {
-    -re ".*type = long.*$gdb_prompt $" {
+    -re ".*type = int.*$gdb_prompt $" {
         pass "whatis value of x+y"
       }
     -re ".*$gdb_prompt $" { fail "whatis value of x+y" }
@@ -121,7 +121,7 @@ gdb_expect {
 
 send_gdb "whatis x-y\n"
 gdb_expect {
-    -re ".*type = long.*$gdb_prompt $" {
+    -re ".*type = int.*$gdb_prompt $" {
         pass "whatis value of x-y"
       }
     -re ".*$gdb_prompt $" { fail "whatis value of x-y" }
@@ -130,7 +130,7 @@ gdb_expect {
 
 send_gdb "whatis x*y\n"
 gdb_expect {
-    -re ".*type = long.*$gdb_prompt $" {
+    -re ".*type = int.*$gdb_prompt $" {
         pass "whatis value of x*y"
       }
     -re ".*$gdb_prompt $" { fail "whatis value of x*y" }


^ permalink raw reply	[flat|nested] 8+ messages in thread
* [RFA] BINOP_DIV and ptyp command
@ 2008-01-30 18:05 Doug Evans
  2008-01-30 22:58 ` Pierre Muller
  2008-01-31 23:01 ` Daniel Jacobowitz
  0 siblings, 2 replies; 8+ messages in thread
From: Doug Evans @ 2008-01-30 18:05 UTC (permalink / raw)
  To: gdb-patches

[apologies, errantly sent to the wrong list, double blech!]

Here is a revised patch to
http://sourceware.org/ml/gdb-patches/2008-01/msg00759.html.
- updates for the recent BINOP_EXP changes and fp BINOP_MIN/MAX
- fixes a small memory leak, blech
- fixes ANSI/ISO-C fp promotion

I can think of a few issues.

1) value_binop still has code in the unsigned case to handle a bit of
   the promotion computation.  This is done in order to properly clip
   the values.  Having all of the code in one place avoids this wart.
   OTOH, having all of the code in one place makes value_binop a bit
   monolithic.  The consistency of having both unop and binop result type
   functions is nice.  OTOH it's only an internal consistency, they're
   all static functions so it's not a strong argument.
   And another way to partition value_binop is along the four major if's,
   e.g. something like.

   if (DECFLOAT)
     return value_binop_decfloat (mumble);
   else if (FLT)
     return value_binop_float (mumble);
   else if (BOOL)
     return value_binop_bool (mumble);
   else /* integer */
     return value_binop_integer (mumble);

2) Another nice thing with having binop_result_type separate is that if
   different languages need to do something differently, there's a
   well-defined place to look.  OTOH, different language requirements may
   not be amenable to partitioning the problem into (1) compute result type,
   (2) compute result.

3) Another nice thing with having binop_result_type separate is that if
   someone else wants to get the result type without values, and only has
   types, {un,bin}op_result_type is there.
   OTOH, one can construct values on the fly with value_zero,value_one
   and call value_binop.

4) switching on OP in two separate fns is problematic

Tell me what you want to see and I'll update the patch to match.
[And no claim is made that there isn't some higher order issue I'm missing.]

2008-01-30  Doug Evans  <dje@google.com>

	Fix argument promotion for binary arithmetic ops for C.
	* valarith.c (unop_result_type): New fn.
	(binop_result_type): New fn.
	(value_binop): Move result type computation to binop_result_type.
	(value_pos, value_neg, value_complement): Move result type
	computation to unop_result_type.

	* eval.c (evaluate_subexp_standard): Fix type of result of mixed
	integer/float division operations when EVAL_AVOID_SIDE_EFFECTS.
	* valops.c (value_one): New function.
	* value.h (value_one): Declare.

	* gdb.base/whatis-exp.exp: Fix expected result of whatis x+y, x-y,
	x*y, x/y, x%y.

Index: eval.c
===================================================================
RCS file: /cvs/src/src/gdb/eval.c,v
retrieving revision 1.78
diff -u -p -r1.78 eval.c
--- eval.c	30 Jan 2008 07:31:07 -0000	1.78
+++ eval.c	30 Jan 2008 17:11:54 -0000
@@ -1510,12 +1510,31 @@ evaluate_subexp_standard (struct type *e
 	goto nosideret;
       if (binop_user_defined_p (op, arg1, arg2))
 	return value_x_binop (arg1, arg2, op, OP_NULL, noside);
-      else if (noside == EVAL_AVOID_SIDE_EFFECTS
-	       && (op == BINOP_DIV || op == BINOP_REM || op == BINOP_MOD
-		   || op == BINOP_INTDIV))
-	return value_zero (value_type (arg1), not_lval);
       else
-	return value_binop (arg1, arg2, op);
+	{
+	  /* If EVAL_AVOID_SIDE_EFFECTS and we're dividing by zero,
+	     fudge arg2 to avoid division-by-zero, the caller is
+	     (theoretically) only looking for the type of the result.  */
+	  if (noside == EVAL_AVOID_SIDE_EFFECTS
+	      /* ??? Do we really want to test for BINOP_MOD here?
+		 The implementation of value_binop gives it a well-defined
+		 value.  */
+	      && (op == BINOP_DIV
+		  || op == BINOP_INTDIV
+		  || op == BINOP_REM
+		  || op == BINOP_MOD)
+	      && value_logical_not (arg2))
+	    {
+	      struct value *v_one, *retval;
+
+	      v_one = value_one (value_type (arg2), not_lval);
+	      retval = value_binop (arg1, v_one, op);
+	      value_free (v_one);
+	      return retval;
+	    }
+	  else
+	    return value_binop (arg1, arg2, op);
+	}
 
     case BINOP_RANGE:
       arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
Index: valarith.c
===================================================================
RCS file: /cvs/src/src/gdb/valarith.c,v
retrieving revision 1.56
diff -u -p -r1.56 valarith.c
--- valarith.c	30 Jan 2008 07:28:16 -0000	1.56
+++ valarith.c	30 Jan 2008 17:11:56 -0000
@@ -40,6 +40,9 @@
 #endif
 
 static struct value *value_subscripted_rvalue (struct value *, struct value *, int);
+static struct type *unop_result_type (enum exp_opcode op, struct type *type1);
+static struct type *binop_result_type (enum exp_opcode op, struct type *type1,
+				       struct type *type2);
 
 void _initialize_valarith (void);
 \f
@@ -742,6 +745,287 @@ value_concat (struct value *arg1, struct
   return (outval);
 }
 \f
+/* Return result type of OP performed on TYPE1.
+   The result type follows ANSI C rules.
+   If the result is not appropropriate for any particular language then it
+   needs to patch this function to return the correct type.  */
+
+static struct type *
+unop_result_type (enum exp_opcode op, struct type *type1)
+{
+  struct type *result_type;
+
+  type1 = check_typedef (type1);
+  result_type = type1;
+
+  switch (op)
+    {
+    case UNOP_PLUS:
+    case UNOP_NEG:
+      break;
+    case UNOP_COMPLEMENT:
+      /* Reject floats and decimal floats.  */
+      if (!is_integral_type (type1))
+	error (_("Argument to complement operation not an integer or boolean."));
+      break;
+    default:
+      error (_("Invalid unary operation on numbers."));
+    }
+
+  if (TYPE_CODE (type1) == TYPE_CODE_DECFLOAT
+      || TYPE_CODE (type1) == TYPE_CODE_FLT)
+    {
+      return result_type;
+    }
+  else if (is_integral_type (type1))
+    {
+      /* Perform integral promotion for ANSI C/C++.
+	 If not appropropriate for any particular language it needs to
+	 supply its own la_unop_result_type function.  */
+      if (TYPE_LENGTH (type1) < TYPE_LENGTH (builtin_type_int))
+	result_type = builtin_type_int;
+
+      return result_type;
+    }
+  else
+    {
+      error (_("Argument to unary operation not a number."));
+      return 0; /* For lint -- never reached */
+    }
+}
+
+/* Return result type of OP performed on TYPE1, TYPE2.
+   If the result is not appropropriate for any particular language then it
+   needs to patch this function to return the correct type.  */
+
+static struct type *
+binop_result_type (enum exp_opcode op, struct type *type1, struct type *type2)
+{
+  type1 = check_typedef (type1);
+  type2 = check_typedef (type2);
+
+  if ((TYPE_CODE (type1) != TYPE_CODE_FLT
+       && TYPE_CODE (type1) != TYPE_CODE_DECFLOAT
+       && !is_integral_type (type1))
+      ||
+      (TYPE_CODE (type2) != TYPE_CODE_FLT
+       && TYPE_CODE (type2) != TYPE_CODE_DECFLOAT
+       && !is_integral_type (type2)))
+    error (_("Argument to arithmetic operation not a number or boolean."));
+
+  if (TYPE_CODE (type1) == TYPE_CODE_DECFLOAT
+      || TYPE_CODE (type2) == TYPE_CODE_DECFLOAT)
+    {
+      switch (op)
+	{
+	case BINOP_ADD:
+	case BINOP_SUB:
+	case BINOP_MUL:
+	case BINOP_DIV:
+	case BINOP_EXP:
+	  break;
+	default:
+	  error (_("Operation not valid for decimal floating point number."));
+	}
+
+      if (TYPE_CODE (type1) != TYPE_CODE_DECFLOAT)
+	/* If type1 is not a decimal float, the type of the result is the type
+	   of the decimal float argument, type2.  */
+	return type2;
+      else if (TYPE_CODE (type2) != TYPE_CODE_DECFLOAT)
+	/* Same logic, for the case where type2 is not a decimal float.  */
+	return type1;
+      else
+	/* Both are decimal floats, the type of the result is the bigger
+	   of the two.  */
+	return (TYPE_LENGTH (type1) > TYPE_LENGTH (type2)) ? type1 : type2;
+    }
+  else if (TYPE_CODE (type1) == TYPE_CODE_FLT
+	   || TYPE_CODE (type2) == TYPE_CODE_FLT)
+    {
+      switch (op)
+	{
+	case BINOP_ADD:
+	case BINOP_SUB:
+	case BINOP_MUL:
+	case BINOP_DIV:
+	case BINOP_EXP:
+	case BINOP_MIN:
+	case BINOP_MAX:
+	  break;
+	default:
+	  error (_("Integer-only operation on floating point number."));
+	}
+
+      switch (current_language->la_language)
+	{
+	case language_c:
+	case language_cplus:
+	case language_asm:
+	  /* ??? language_objc? */
+	  /* Perform ANSI/ISO-C promotions.
+	     If only one type is float, use its type.
+	     Otherwise use the bigger type.  */
+	  if (TYPE_CODE (type1) != TYPE_CODE_FLT)
+	    return type2;
+	  else if (TYPE_CODE (type2) != TYPE_CODE_FLT)
+	    return type1;
+	  else
+	    return (TYPE_LENGTH (type1) > TYPE_LENGTH (type2)) ? type1 : type2;
+
+	default:
+	  /* For other languages the result type is unchanged from 6.7 for
+	     backward compatibility.
+	     If either arg was long double, make sure that value is also long
+	     double.  */
+	  if (TYPE_LENGTH (type1) * 8 > gdbarch_double_bit (current_gdbarch)
+	      || TYPE_LENGTH (type2) * 8 > gdbarch_double_bit (current_gdbarch))
+	    return builtin_type_long_double;
+	  else
+	    return builtin_type_double;
+	}
+    }
+  else if (TYPE_CODE (type1) == TYPE_CODE_BOOL
+	   && TYPE_CODE (type2) == TYPE_CODE_BOOL)
+    {
+      switch (op)
+	{
+	case BINOP_BITWISE_AND:
+	case BINOP_BITWISE_IOR:
+	case BINOP_BITWISE_XOR:
+        case BINOP_EQUAL:
+        case BINOP_NOTEQUAL:
+	  break;
+	default:
+	  error (_("Invalid operation on booleans."));
+	}
+
+      return type1;
+    }
+  else
+    /* Integral operations here.  */
+    /* FIXME: Also mixed integral/booleans, with result an integer.  */
+    {
+      unsigned int promoted_len1 = TYPE_LENGTH (type1);
+      unsigned int promoted_len2 = TYPE_LENGTH (type2);
+      int is_unsigned1 = TYPE_UNSIGNED (type1);
+      int is_unsigned2 = TYPE_UNSIGNED (type2);
+      unsigned int result_len;
+      int unsigned_operation;
+
+      /* Determine type length and signedness after promotion for
+         both operands.  */
+      if (promoted_len1 < TYPE_LENGTH (builtin_type_int))
+	{
+	  is_unsigned1 = 0;
+	  promoted_len1 = TYPE_LENGTH (builtin_type_int);
+	}
+      if (promoted_len2 < TYPE_LENGTH (builtin_type_int))
+	{
+	  is_unsigned2 = 0;
+	  promoted_len2 = TYPE_LENGTH (builtin_type_int);
+	}
+
+      /* Determine type length of the result, and if the operation should
+	 be done unsigned.  For exponentiation and shift operators,
+	 use the length and type of the left operand.  Otherwise,
+	 use the signedness of the operand with the greater length.
+	 If both operands are of equal length, use unsigned operation
+	 if one of the operands is unsigned.  */
+      if (op == BINOP_RSH || op == BINOP_LSH || op == BINOP_EXP)
+	{
+	  /* In case of the shift operators and exponentiation the type of
+	     the result only depends on the type of the left operand.  */
+	  unsigned_operation = is_unsigned1;
+	  result_len = promoted_len1;
+	}
+      else if (promoted_len1 > promoted_len2)
+	{
+	  unsigned_operation = is_unsigned1;
+	  result_len = promoted_len1;
+	}
+      else if (promoted_len2 > promoted_len1)
+	{
+	  unsigned_operation = is_unsigned2;
+	  result_len = promoted_len2;
+	}
+      else
+	{
+	  unsigned_operation = is_unsigned1 || is_unsigned2;
+	  result_len = promoted_len1;
+	}
+
+      switch (op)
+	{
+	case BINOP_ADD:
+	case BINOP_SUB:
+	case BINOP_MUL:
+	case BINOP_DIV:
+	case BINOP_INTDIV:
+	case BINOP_EXP:
+	case BINOP_REM:
+	case BINOP_MOD:
+	case BINOP_LSH:
+	case BINOP_RSH:
+	case BINOP_BITWISE_AND:
+	case BINOP_BITWISE_IOR:
+	case BINOP_BITWISE_XOR:
+	case BINOP_LOGICAL_AND:
+	case BINOP_LOGICAL_OR:
+	case BINOP_MIN:
+	case BINOP_MAX:
+	case BINOP_EQUAL:
+	case BINOP_NOTEQUAL:
+	case BINOP_LESS:
+	  break;
+
+	default:
+	  error (_("Invalid binary operation on numbers."));
+	}
+
+      switch (current_language->la_language)
+	{
+	case language_c:
+	case language_cplus:
+	case language_asm:
+	  /* ??? language_objc? */
+	  if (result_len <= TYPE_LENGTH (builtin_type_int))
+	    {
+	      return (unsigned_operation
+		      ? builtin_type_unsigned_int
+		      : builtin_type_int);
+	    }
+	  else if (result_len <= TYPE_LENGTH (builtin_type_long))
+	    {
+	      return (unsigned_operation
+		      ? builtin_type_unsigned_long
+		      : builtin_type_long);
+	    }
+	  else
+	    {
+	      return (unsigned_operation
+		      ? builtin_type_unsigned_long_long
+		      : builtin_type_long_long);
+	    }
+
+	default:
+	  if (unsigned_operation)
+	    {
+	      if (result_len > gdbarch_long_bit (current_gdbarch) / HOST_CHAR_BIT)
+		return builtin_type_unsigned_long_long;
+	      else
+		return builtin_type_unsigned_long;
+	    }
+	  else
+	    {
+	      if (result_len > gdbarch_long_bit (current_gdbarch) / HOST_CHAR_BIT)
+		return builtin_type_long_long;
+	      else
+		return builtin_type_long;
+	    }
+	}
+    }
+}
 
 /* Integer exponentiation: V1**V2, where both arguments are
    integers.  Requires V1 != 0 if V2 < 0.  Returns 1 for 0 ** 0.  */
@@ -870,23 +1154,14 @@ struct value *
 value_binop (struct value *arg1, struct value *arg2, enum exp_opcode op)
 {
   struct value *val;
-  struct type *type1, *type2;
+  struct type *result_type;
 
   arg1 = coerce_ref (arg1);
   arg2 = coerce_ref (arg2);
-  type1 = check_typedef (value_type (arg1));
-  type2 = check_typedef (value_type (arg2));
 
-  if ((TYPE_CODE (type1) != TYPE_CODE_FLT
-       && TYPE_CODE (type1) != TYPE_CODE_DECFLOAT && !is_integral_type (type1))
-      ||
-      (TYPE_CODE (type2) != TYPE_CODE_FLT
-       && TYPE_CODE (type2) != TYPE_CODE_DECFLOAT && !is_integral_type (type2)))
-    error (_("Argument to arithmetic operation not a number or boolean."));
+  result_type = binop_result_type (op, value_type (arg1), value_type (arg2));
 
-  if (TYPE_CODE (type1) == TYPE_CODE_DECFLOAT
-      ||
-      TYPE_CODE (type2) == TYPE_CODE_DECFLOAT)
+  if (TYPE_CODE (result_type) == TYPE_CODE_DECFLOAT)
     {
       struct type *v_type;
       int len_v1, len_v2, len_v;
@@ -909,23 +1184,9 @@ value_binop (struct value *arg1, struct 
 	  error (_("Operation not valid for decimal floating point number."));
 	}
 
-      if (TYPE_CODE (type1) != TYPE_CODE_DECFLOAT)
-	/* If arg1 is not a decimal float, the type of the result is the type
-	   of the decimal float argument, arg2.  */
-	v_type = type2;
-      else if (TYPE_CODE (type2) != TYPE_CODE_DECFLOAT)
-	/* Same logic, for the case where arg2 is not a decimal float.  */
-	v_type = type1;
-      else
-	/* len_v is equal either to len_v1 or to len_v2.  the type of the
-	   result is the type of the argument with the same length as v.  */
-	v_type = (len_v == len_v1)? type1 : type2;
-
-      val = value_from_decfloat (v_type, v);
+      val = value_from_decfloat (result_type, v);
     }
-  else if (TYPE_CODE (type1) == TYPE_CODE_FLT
-	   ||
-	   TYPE_CODE (type2) == TYPE_CODE_FLT)
+  else if (TYPE_CODE (result_type) == TYPE_CODE_FLT)
     {
       /* FIXME-if-picky-about-floating-accuracy: Should be doing this
          in target format.  real.c in GCC probably has the necessary
@@ -970,20 +1231,10 @@ value_binop (struct value *arg1, struct 
 	  error (_("Integer-only operation on floating point number."));
 	}
 
-      /* If either arg was long double, make sure that value is also long
-         double.  */
-
-      if (TYPE_LENGTH (type1) * 8 > gdbarch_double_bit (current_gdbarch)
-	  || TYPE_LENGTH (type2) * 8 > gdbarch_double_bit (current_gdbarch))
-	val = allocate_value (builtin_type_long_double);
-      else
-	val = allocate_value (builtin_type_double);
-
+      val = allocate_value (result_type);
       store_typed_floating (value_contents_raw (val), value_type (val), v);
     }
-  else if (TYPE_CODE (type1) == TYPE_CODE_BOOL
-	   &&
-	   TYPE_CODE (type2) == TYPE_CODE_BOOL)
+  else if (TYPE_CODE (result_type) == TYPE_CODE_BOOL)
     {
       LONGEST v1, v2, v = 0;
       v1 = value_as_long (arg1);
@@ -1015,74 +1266,33 @@ value_binop (struct value *arg1, struct 
 	  error (_("Invalid operation on booleans."));
 	}
 
-      val = allocate_value (type1);
+      val = allocate_value (result_type);
       store_signed_integer (value_contents_raw (val),
-			    TYPE_LENGTH (type1),
+			    TYPE_LENGTH (result_type),
 			    v);
     }
   else
     /* Integral operations here.  */
-    /* FIXME:  Also mixed integral/booleans, with result an integer. */
-    /* FIXME: This implements ANSI C rules (also correct for C++).
-       What about FORTRAN and (the deleted) chill ?  */
     {
-      unsigned int promoted_len1 = TYPE_LENGTH (type1);
-      unsigned int promoted_len2 = TYPE_LENGTH (type2);
-      int is_unsigned1 = TYPE_UNSIGNED (type1);
-      int is_unsigned2 = TYPE_UNSIGNED (type2);
-      unsigned int result_len;
-      int unsigned_operation;
-
-      /* Determine type length and signedness after promotion for
-         both operands.  */
-      if (promoted_len1 < TYPE_LENGTH (builtin_type_int))
-	{
-	  is_unsigned1 = 0;
-	  promoted_len1 = TYPE_LENGTH (builtin_type_int);
-	}
-      if (promoted_len2 < TYPE_LENGTH (builtin_type_int))
-	{
-	  is_unsigned2 = 0;
-	  promoted_len2 = TYPE_LENGTH (builtin_type_int);
-	}
-
-      /* Determine type length of the result, and if the operation should
-         be done unsigned.  For exponentiation and shift operators,
-         use the length and type of the left operand.  Otherwise,
-         use the signedness of the operand with the greater length.
-         If both operands are of equal length, use unsigned operation
-         if one of the operands is unsigned.  */
-      if (op == BINOP_RSH || op == BINOP_LSH || op == BINOP_EXP)
-	{
-	  /* In case of the shift operators and exponentiation the type of
-	     the result only depends on the type of the left operand.  */
-	  unsigned_operation = is_unsigned1;
-	  result_len = promoted_len1;
-	}
-      else if (promoted_len1 > promoted_len2)
-	{
-	  unsigned_operation = is_unsigned1;
-	  result_len = promoted_len1;
-	}
-      else if (promoted_len2 > promoted_len1)
-	{
-	  unsigned_operation = is_unsigned2;
-	  result_len = promoted_len2;
-	}
-      else
-	{
-	  unsigned_operation = is_unsigned1 || is_unsigned2;
-	  result_len = promoted_len1;
-	}
+      int unsigned_operation = TYPE_UNSIGNED (result_type);
 
       if (unsigned_operation)
 	{
+	  unsigned int len1, len2, result_len;
 	  LONGEST v2_signed = value_as_long (arg2);
 	  ULONGEST v1, v2, v = 0;
 	  v1 = (ULONGEST) value_as_long (arg1);
 	  v2 = (ULONGEST) v2_signed;
 
-	  /* Truncate values to the type length of the result.  */
+	  /* Truncate values to the type length of the result.
+	     Things are mildly trick because binop_result_type may
+	     return a long which on amd64 is 8 bytes, and that's a problem if
+	     ARG1, ARG2 are both <= 4 bytes.  We need to truncate the values
+	     at 4 bytes not 8.  So fetch the lengths of the original types
+	     and truncate at the larger of the two.  */
+	  len1 = TYPE_LENGTH (value_type (arg1));
+	  len2 = TYPE_LENGTH (value_type (arg1));
+	  result_len = len1 > len2 ? len1 : len2;
 	  if (result_len < sizeof (ULONGEST))
 	    {
 	      v1 &= ((LONGEST) 1 << HOST_CHAR_BIT * result_len) - 1;
@@ -1186,19 +1396,7 @@ value_binop (struct value *arg1, struct 
 	      error (_("Invalid binary operation on numbers."));
 	    }
 
-	  /* This is a kludge to get around the fact that we don't
-	     know how to determine the result type from the types of
-	     the operands.  (I'm not really sure how much we feel the
-	     need to duplicate the exact rules of the current
-	     language.  They can get really hairy.  But not to do so
-	     makes it hard to document just what we *do* do).  */
-
-	  /* Can't just call init_type because we wouldn't know what
-	     name to give the type.  */
-	  val = allocate_value
-	    (result_len > gdbarch_long_bit (current_gdbarch) / HOST_CHAR_BIT
-	     ? builtin_type_unsigned_long_long
-	     : builtin_type_unsigned_long);
+	  val = allocate_value (result_type);
 	  store_unsigned_integer (value_contents_raw (val),
 				  TYPE_LENGTH (value_type (val)),
 				  v);
@@ -1309,19 +1507,7 @@ value_binop (struct value *arg1, struct 
 	      error (_("Invalid binary operation on numbers."));
 	    }
 
-	  /* This is a kludge to get around the fact that we don't
-	     know how to determine the result type from the types of
-	     the operands.  (I'm not really sure how much we feel the
-	     need to duplicate the exact rules of the current
-	     language.  They can get really hairy.  But not to do so
-	     makes it hard to document just what we *do* do).  */
-
-	  /* Can't just call init_type because we wouldn't know what
-	     name to give the type.  */
-	  val = allocate_value
-	    (result_len > gdbarch_long_bit (current_gdbarch) / HOST_CHAR_BIT
-	     ? builtin_type_long_long
-	     : builtin_type_long);
+	  val = allocate_value (result_type);
 	  store_signed_integer (value_contents_raw (val),
 				TYPE_LENGTH (value_type (val)),
 				v);
@@ -1533,23 +1719,19 @@ struct value *
 value_pos (struct value *arg1)
 {
   struct type *type;
+  struct type *result_type;
 
   arg1 = coerce_ref (arg1);
-
   type = check_typedef (value_type (arg1));
+  result_type = unop_result_type (UNOP_PLUS, value_type (arg1));
 
   if (TYPE_CODE (type) == TYPE_CODE_FLT)
-    return value_from_double (type, value_as_double (arg1));
+    return value_from_double (result_type, value_as_double (arg1));
   else if (TYPE_CODE (type) == TYPE_CODE_DECFLOAT)
-    return value_from_decfloat (type, value_contents (arg1));
+    return value_from_decfloat (result_type, value_contents (arg1));
   else if (is_integral_type (type))
     {
-      /* Perform integral promotion for ANSI C/C++.  FIXME: What about
-         FORTRAN and (the deleted) chill ?  */
-      if (TYPE_LENGTH (type) < TYPE_LENGTH (builtin_type_int))
-	type = builtin_type_int;
-
-      return value_from_longest (type, value_as_long (arg1));
+      return value_from_longest (result_type, value_as_long (arg1));
     }
   else
     {
@@ -1562,11 +1744,11 @@ struct value *
 value_neg (struct value *arg1)
 {
   struct type *type;
-  struct type *result_type = value_type (arg1);
+  struct type *result_type;
 
   arg1 = coerce_ref (arg1);
-
   type = check_typedef (value_type (arg1));
+  result_type = unop_result_type (UNOP_NEG, value_type (arg1));
 
   if (TYPE_CODE (type) == TYPE_CODE_DECFLOAT)
     {
@@ -1584,16 +1766,10 @@ value_neg (struct value *arg1)
       memcpy (value_contents_raw (val), decbytes, len);
       return val;
     }
-
-  if (TYPE_CODE (type) == TYPE_CODE_FLT)
+  else if (TYPE_CODE (type) == TYPE_CODE_FLT)
     return value_from_double (result_type, -value_as_double (arg1));
   else if (is_integral_type (type))
     {
-      /* Perform integral promotion for ANSI C/C++.  FIXME: What about
-         FORTRAN and (the deleted) chill ?  */
-      if (TYPE_LENGTH (type) < TYPE_LENGTH (builtin_type_int))
-	result_type = builtin_type_int;
-
       return value_from_longest (result_type, -value_as_long (arg1));
     }
   else
@@ -1607,20 +1783,15 @@ struct value *
 value_complement (struct value *arg1)
 {
   struct type *type;
-  struct type *result_type = value_type (arg1);
+  struct type *result_type;
 
   arg1 = coerce_ref (arg1);
-
   type = check_typedef (value_type (arg1));
+  result_type = unop_result_type (UNOP_COMPLEMENT, value_type (arg1));
 
   if (!is_integral_type (type))
     error (_("Argument to complement operation not an integer or boolean."));
 
-  /* Perform integral promotion for ANSI C/C++.
-     FIXME: What about FORTRAN ?  */
-  if (TYPE_LENGTH (type) < TYPE_LENGTH (builtin_type_int))
-    result_type = builtin_type_int;
-
   return value_from_longest (result_type, ~value_as_long (arg1));
 }
 \f
Index: valops.c
===================================================================
RCS file: /cvs/src/src/gdb/valops.c,v
retrieving revision 1.182
diff -u -p -r1.182 valops.c
--- valops.c	18 Jan 2008 17:07:40 -0000	1.182
+++ valops.c	30 Jan 2008 17:11:58 -0000
@@ -471,6 +471,41 @@ value_zero (struct type *type, enum lval
   return val;
 }
 
+/* Create a value of numeric type TYPE that is one, and return it.  */
+
+struct value *
+value_one (struct type *type, enum lval_type lv)
+{
+  struct type *type1 = check_typedef (type);
+  struct value *val;
+
+  if (TYPE_CODE (type1) == TYPE_CODE_DECFLOAT)
+    {
+      struct value *int_one = value_from_longest (builtin_type_int, 1);
+      struct value *val;
+      gdb_byte v[16];
+
+      decimal_from_integral (int_one, v, TYPE_LENGTH (builtin_type_int));
+      val = value_from_decfloat (type, v);
+      value_free (int_one);
+    }
+  else if (TYPE_CODE (type1) == TYPE_CODE_FLT)
+    {
+      val = value_from_double (type, (DOUBLEST) 1);
+    }
+  else if (is_integral_type (type1))
+    {
+      val = value_from_longest (type, (LONGEST) 1);
+    }
+  else
+    {
+      error (_("Not a numeric type."));
+    }
+
+  VALUE_LVAL (val) = lv;
+  return val;
+}
+
 /* Return a value with type TYPE located at ADDR.
 
    Call value_at only if the data needs to be fetched immediately;
Index: value.h
===================================================================
RCS file: /cvs/src/src/gdb/value.h,v
retrieving revision 1.107
diff -u -p -r1.107 value.h
--- value.h	18 Jan 2008 17:07:40 -0000	1.107
+++ value.h	30 Jan 2008 17:11:58 -0000
@@ -392,6 +392,8 @@ extern struct value *value_cast (struct 
 
 extern struct value *value_zero (struct type *type, enum lval_type lv);
 
+extern struct value *value_one (struct type *type, enum lval_type lv);
+
 extern struct value *value_repeat (struct value *arg1, int count);
 
 extern struct value *value_subscript (struct value *array, struct value *idx);
Index: testsuite/gdb.base/whatis-exp.exp
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/gdb.base/whatis-exp.exp,v
retrieving revision 1.7
diff -u -p -r1.7 whatis-exp.exp
--- testsuite/gdb.base/whatis-exp.exp	1 Jan 2008 22:53:19 -0000	1.7
+++ testsuite/gdb.base/whatis-exp.exp	30 Jan 2008 17:12:00 -0000
@@ -112,7 +112,7 @@ gdb_expect {
 
 send_gdb "whatis x+y\n"
 gdb_expect {
-    -re ".*type = long.*$gdb_prompt $" {
+    -re ".*type = int.*$gdb_prompt $" {
         pass "whatis value of x+y"
       }
     -re ".*$gdb_prompt $" { fail "whatis value of x+y" }
@@ -121,7 +121,7 @@ gdb_expect {
 
 send_gdb "whatis x-y\n"
 gdb_expect {
-    -re ".*type = long.*$gdb_prompt $" {
+    -re ".*type = int.*$gdb_prompt $" {
         pass "whatis value of x-y"
       }
     -re ".*$gdb_prompt $" { fail "whatis value of x-y" }
@@ -130,7 +130,7 @@ gdb_expect {
 
 send_gdb "whatis x*y\n"
 gdb_expect {
-    -re ".*type = long.*$gdb_prompt $" {
+    -re ".*type = int.*$gdb_prompt $" {
         pass "whatis value of x*y"
       }
     -re ".*$gdb_prompt $" { fail "whatis value of x*y" }


^ permalink raw reply	[flat|nested] 8+ messages in thread
* [RFA] BINOP_DIV and ptyp command
@ 2008-01-30  3:38 Doug Evans
  0 siblings, 0 replies; 8+ messages in thread
From: Doug Evans @ 2008-01-30  3:38 UTC (permalink / raw)
  To: gdb-patches

Daniel Jacobowitz wrote:
> That's not a value-dependent error.  1 / 0 has a sensible type (it's
> an int), but no sensible value; 1 >> 3.0 has no sensible type (it's a
> syntax error).
> 
> I think of it this way:
> 
> drow@caradoc:~% cat a.c
> int a = sizeof (1/0);
> int b = sizeof (1 >> 3.0);
> drow@caradoc:~% gcc -Wall -c a.c
> a.c:2: error: invalid operands to binary >>

True.

As an exercise I wrote a patch that added hooks to language_defn
to compute the result type.  I'll append that patch separately.
It's a bit excessive, though there is value in using the language vector.
There's also value in localizing the changes to valarith.c.
Tell me what you want and I'll rework the patch as necessary.

Below is the patch I'm submitting for review/approval.
It moves the result type computation to another function
and fixes the result type for c-like languages.
This patch also handles "whatis 1/0" by watching for zero and
converting it to one.  [I realize the INTDIV eval.c patch touches
this part of the code - I can wait until the INTDIV patch goes in
and update this one before checking in.]


2008-01-29  Doug Evans  <dje@google.com>

	Fix argument promotion for binary arithmetic ops for C.
	* valarith.c (unop_result_type): New fn.
	(binop_result_type): New fn.
	(value_binop): Move result type computation to binop_result_type.
	(value_pos, value_neg, value_complement): Move result type
	computation to unop_result_type.

	* eval.c (evaluate_subexp_standard): Fix type of result of mixed
	integer/float division operations when EVAL_AVOID_SIDE_EFFECTS.
	* valops.c (value_one): New function.
	* value.h (value_one): Declare.

	* gdb.base/whatis-exp.exp: Fix expected result of whatis x+y, x-y,
	x*y, x/y, x%y.

Index: eval.c
===================================================================
RCS file: /cvs/src/src/gdb/eval.c,v
retrieving revision 1.77
diff -u -p -r1.77 eval.c
--- eval.c	18 Jan 2008 17:07:39 -0000	1.77
+++ eval.c	30 Jan 2008 02:14:59 -0000
@@ -1509,11 +1509,20 @@ evaluate_subexp_standard (struct type *e
 	goto nosideret;
       if (binop_user_defined_p (op, arg1, arg2))
 	return value_x_binop (arg1, arg2, op, OP_NULL, noside);
-      else if (noside == EVAL_AVOID_SIDE_EFFECTS
-	       && (op == BINOP_DIV || op == BINOP_REM || op == BINOP_MOD))
-	return value_zero (value_type (arg1), not_lval);
       else
-	return value_binop (arg1, arg2, op);
+	{
+	  /* If EVAL_AVOID_SIDE_EFFECTS and we're dividing by zero,
+	     fudge arg2 to avoid division-by-zero, the caller is
+	     (theoretically) only looking for the type of the result.  */
+	  if (noside == EVAL_AVOID_SIDE_EFFECTS
+	      /* ??? Do we really want to test for BINOP_MOD here?
+		 The implementation of value_binop gives it a well-defined
+		 value.  */
+	      && (op == BINOP_DIV || op == BINOP_REM || op == BINOP_MOD)
+	      && value_logical_not (arg2))
+	    arg2 = value_one (value_type (arg2), not_lval);
+	  return value_binop (arg1, arg2, op);
+	}
 
     case BINOP_RANGE:
       arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
Index: valarith.c
===================================================================
RCS file: /cvs/src/src/gdb/valarith.c,v
retrieving revision 1.55
diff -u -p -r1.55 valarith.c
--- valarith.c	29 Jan 2008 14:24:43 -0000	1.55
+++ valarith.c	30 Jan 2008 02:15:00 -0000
@@ -40,6 +40,9 @@
 #endif
 
 static struct value *value_subscripted_rvalue (struct value *, struct value *, int);
+static struct type *unop_result_type (enum exp_opcode op, struct type *type1);
+static struct type *binop_result_type (enum exp_opcode op, struct type *type1,
+				       struct type *type2);
 
 void _initialize_valarith (void);
 \f
@@ -742,6 +745,277 @@ value_concat (struct value *arg1, struct
   return (outval);
 }
 \f
+/* Return type of OP performed on TYPE1.
+   The result type follows ANSI C rules.
+   If the result is not appropropriate for any particular language then it
+   needs to patch this function to return the correct type.  */
+
+static struct type *
+unop_result_type (enum exp_opcode op, struct type *type1)
+{
+  struct type *result_type;
+
+  type1 = check_typedef (type1);
+  result_type = type1;
+
+  switch (op)
+    {
+    case UNOP_PLUS:
+    case UNOP_NEG:
+      break;
+    case UNOP_COMPLEMENT:
+      /* Reject floats and decimal floats.  */
+      if (!is_integral_type (type1))
+	error (_("Argument to complement operation not an integer or boolean."));
+      break;
+    default:
+      error (_("Invalid unary operation on numbers."));
+    }
+
+  if (TYPE_CODE (type1) == TYPE_CODE_DECFLOAT
+      || TYPE_CODE (type1) == TYPE_CODE_FLT)
+    {
+      return result_type;
+    }
+  else if (is_integral_type (type1))
+    {
+      /* Perform integral promotion for ANSI C/C++.
+	 If not appropropriate for any particular language it needs to
+	 supply its own la_unop_result_type function.  */
+      if (TYPE_LENGTH (type1) < TYPE_LENGTH (builtin_type_int))
+	result_type = builtin_type_int;
+
+      return result_type;
+    }
+  else
+    {
+      error (_("Argument to unary operation not a number."));
+      return 0; /* For lint -- never reached */
+    }
+}
+
+/* Return type of OP performed on TYPE1, TYPE2.
+   For C-like languages the result follows ANSI C.
+   For other languages the result type is unchanged from 6.6 for backward
+   compatibility.
+   If the result is not appropropriate for any particular language then it
+   needs to patch this function to return the correct type.  */
+
+static struct type *
+binop_result_type (enum exp_opcode op, struct type *type1, struct type *type2)
+{
+  type1 = check_typedef (type1);
+  type2 = check_typedef (type2);
+
+  if ((TYPE_CODE (type1) != TYPE_CODE_FLT
+       && TYPE_CODE (type1) != TYPE_CODE_DECFLOAT
+       && !is_integral_type (type1))
+      ||
+      (TYPE_CODE (type2) != TYPE_CODE_FLT
+       && TYPE_CODE (type2) != TYPE_CODE_DECFLOAT
+       && !is_integral_type (type2)))
+    error (_("Argument to arithmetic operation not a number or boolean."));
+
+  if (TYPE_CODE (type1) == TYPE_CODE_DECFLOAT
+      || TYPE_CODE (type2) == TYPE_CODE_DECFLOAT)
+    {
+      struct type *result_type;
+
+      switch (op)
+	{
+	case BINOP_ADD:
+	case BINOP_SUB:
+	case BINOP_MUL:
+	case BINOP_DIV:
+	case BINOP_EXP:
+	  break;
+	default:
+	  error (_("Operation not valid for decimal floating point number."));
+	}
+
+      if (TYPE_CODE (type1) != TYPE_CODE_DECFLOAT)
+	/* If type1 is not a decimal float, the type of the result is the type
+	   of the decimal float argument, type2.  */
+	result_type = type2;
+      else if (TYPE_CODE (type2) != TYPE_CODE_DECFLOAT)
+	/* Same logic, for the case where type2 is not a decimal float.  */
+	result_type = type1;
+      else
+	/* Both are decimal floats, the type of the result is the bigger
+	   of the two.  */
+	result_type =
+	  (TYPE_LENGTH (type1) > TYPE_LENGTH (type2)) ? type1 : type2;
+
+      return result_type;
+    }
+  else if (TYPE_CODE (type1) == TYPE_CODE_FLT
+	   || TYPE_CODE (type2) == TYPE_CODE_FLT)
+    {
+      struct type *result_type;
+
+      switch (op)
+	{
+	case BINOP_ADD:
+	case BINOP_SUB:
+	case BINOP_MUL:
+	case BINOP_DIV:
+	case BINOP_EXP:
+	  break;
+	default:
+	  error (_("Integer-only operation on floating point number."));
+	}
+
+      /* If either arg was long double, make sure that value is also long
+         double.  */
+
+      if (TYPE_LENGTH (type1) * 8 > gdbarch_double_bit (current_gdbarch)
+	  || TYPE_LENGTH (type2) * 8 > gdbarch_double_bit (current_gdbarch))
+	result_type = builtin_type_long_double;
+      else
+	result_type = builtin_type_double;
+
+      return result_type;
+    }
+  else if (TYPE_CODE (type1) == TYPE_CODE_BOOL
+	   && TYPE_CODE (type2) == TYPE_CODE_BOOL)
+    {
+      switch (op)
+	{
+	case BINOP_BITWISE_AND:
+	case BINOP_BITWISE_IOR:
+	case BINOP_BITWISE_XOR:
+        case BINOP_EQUAL:
+        case BINOP_NOTEQUAL:
+	  break;
+	default:
+	  error (_("Invalid operation on booleans."));
+	}
+
+      return type1;
+    }
+  else
+    /* Integral operations here.  */
+    /* FIXME: Also mixed integral/booleans, with result an integer.  */
+    {
+      unsigned int promoted_len1 = TYPE_LENGTH (type1);
+      unsigned int promoted_len2 = TYPE_LENGTH (type2);
+      int is_unsigned1 = TYPE_UNSIGNED (type1);
+      int is_unsigned2 = TYPE_UNSIGNED (type2);
+      unsigned int result_len;
+      int unsigned_operation;
+
+      /* Determine type length and signedness after promotion for
+         both operands.  */
+      if (promoted_len1 < TYPE_LENGTH (builtin_type_int))
+	{
+	  is_unsigned1 = 0;
+	  promoted_len1 = TYPE_LENGTH (builtin_type_int);
+	}
+      if (promoted_len2 < TYPE_LENGTH (builtin_type_int))
+	{
+	  is_unsigned2 = 0;
+	  promoted_len2 = TYPE_LENGTH (builtin_type_int);
+	}
+
+      /* Determine type length of the result, and if the operation should
+         be done unsigned.
+         Use the signedness of the operand with the greater length.
+         If both operands are of equal length, use unsigned operation
+         if one of the operands is unsigned.  */
+      if (op == BINOP_RSH || op == BINOP_LSH)
+	{
+	  /* In case of the shift operators the type of the result only
+	     depends on the type of the left operand.  */
+	  unsigned_operation = is_unsigned1;
+	  result_len = promoted_len1;
+	}
+      else if (promoted_len1 > promoted_len2)
+	{
+	  unsigned_operation = is_unsigned1;
+	  result_len = promoted_len1;
+	}
+      else if (promoted_len2 > promoted_len1)
+	{
+	  unsigned_operation = is_unsigned2;
+	  result_len = promoted_len2;
+	}
+      else
+	{
+	  unsigned_operation = is_unsigned1 || is_unsigned2;
+	  result_len = promoted_len1;
+	}
+
+      switch (op)
+	{
+	case BINOP_ADD:
+	case BINOP_SUB:
+	case BINOP_MUL:
+	case BINOP_DIV:
+	case BINOP_INTDIV:
+	case BINOP_EXP:
+	case BINOP_REM:
+	case BINOP_MOD:
+	case BINOP_LSH:
+	case BINOP_RSH:
+	case BINOP_BITWISE_AND:
+	case BINOP_BITWISE_IOR:
+	case BINOP_BITWISE_XOR:
+	case BINOP_LOGICAL_AND:
+	case BINOP_LOGICAL_OR:
+	case BINOP_MIN:
+	case BINOP_MAX:
+	case BINOP_EQUAL:
+	case BINOP_NOTEQUAL:
+	case BINOP_LESS:
+	  break;
+
+	default:
+	  error (_("Invalid binary operation on numbers."));
+	}
+
+      switch (current_language->la_language)
+	{
+	case language_c:
+	case language_cplus:
+	case language_asm:
+	  /* ??? language_objc? */
+	  if (result_len <= TYPE_LENGTH (builtin_type_int))
+	    {
+	      return (unsigned_operation
+		      ? builtin_type_unsigned_int
+		      : builtin_type_int);
+	    }
+	  else if (result_len <= TYPE_LENGTH (builtin_type_long))
+	    {
+	      return (unsigned_operation
+		      ? builtin_type_unsigned_long
+		      : builtin_type_long);
+	    }
+	  else
+	    {
+	      return (unsigned_operation
+		      ? builtin_type_unsigned_long_long
+		      : builtin_type_long_long);
+	    }
+
+	default:
+	  if (unsigned_operation)
+	    {
+	      if (result_len > gdbarch_long_bit (current_gdbarch) / HOST_CHAR_BIT)
+		return builtin_type_unsigned_long_long;
+	      else
+		return builtin_type_unsigned_long;
+	    }
+	  else
+	    {
+	      if (result_len > gdbarch_long_bit (current_gdbarch) / HOST_CHAR_BIT)
+		return builtin_type_long_long;
+	      else
+		return builtin_type_long;
+	    }
+	}
+    }
+}
 
 /* Obtain decimal value of arguments for binary operation, converting from
    other types if one of them is not decimal floating point.  */
@@ -810,23 +1084,14 @@ struct value *
 value_binop (struct value *arg1, struct value *arg2, enum exp_opcode op)
 {
   struct value *val;
-  struct type *type1, *type2;
+  struct type *result_type;
 
   arg1 = coerce_ref (arg1);
   arg2 = coerce_ref (arg2);
-  type1 = check_typedef (value_type (arg1));
-  type2 = check_typedef (value_type (arg2));
 
-  if ((TYPE_CODE (type1) != TYPE_CODE_FLT
-       && TYPE_CODE (type1) != TYPE_CODE_DECFLOAT && !is_integral_type (type1))
-      ||
-      (TYPE_CODE (type2) != TYPE_CODE_FLT
-       && TYPE_CODE (type2) != TYPE_CODE_DECFLOAT && !is_integral_type (type2)))
-    error (_("Argument to arithmetic operation not a number or boolean."));
+  result_type = binop_result_type (op, value_type (arg1), value_type (arg2));
 
-  if (TYPE_CODE (type1) == TYPE_CODE_DECFLOAT
-      ||
-      TYPE_CODE (type2) == TYPE_CODE_DECFLOAT)
+  if (TYPE_CODE (result_type) == TYPE_CODE_DECFLOAT)
     {
       struct type *v_type;
       int len_v1, len_v2, len_v;
@@ -849,23 +1114,9 @@ value_binop (struct value *arg1, struct 
 	  error (_("Operation not valid for decimal floating point number."));
 	}
 
-      if (TYPE_CODE (type1) != TYPE_CODE_DECFLOAT)
-	/* If arg1 is not a decimal float, the type of the result is the type
-	   of the decimal float argument, arg2.  */
-	v_type = type2;
-      else if (TYPE_CODE (type2) != TYPE_CODE_DECFLOAT)
-	/* Same logic, for the case where arg2 is not a decimal float.  */
-	v_type = type1;
-      else
-	/* len_v is equal either to len_v1 or to len_v2.  the type of the
-	   result is the type of the argument with the same length as v.  */
-	v_type = (len_v == len_v1)? type1 : type2;
-
-      val = value_from_decfloat (v_type, v);
+      val = value_from_decfloat (result_type, v);
     }
-  else if (TYPE_CODE (type1) == TYPE_CODE_FLT
-	   ||
-	   TYPE_CODE (type2) == TYPE_CODE_FLT)
+  else if (TYPE_CODE (result_type) == TYPE_CODE_FLT)
     {
       /* FIXME-if-picky-about-floating-accuracy: Should be doing this
          in target format.  real.c in GCC probably has the necessary
@@ -902,20 +1153,10 @@ value_binop (struct value *arg1, struct 
 	  error (_("Integer-only operation on floating point number."));
 	}
 
-      /* If either arg was long double, make sure that value is also long
-         double.  */
-
-      if (TYPE_LENGTH (type1) * 8 > gdbarch_double_bit (current_gdbarch)
-	  || TYPE_LENGTH (type2) * 8 > gdbarch_double_bit (current_gdbarch))
-	val = allocate_value (builtin_type_long_double);
-      else
-	val = allocate_value (builtin_type_double);
-
+      val = allocate_value (result_type);
       store_typed_floating (value_contents_raw (val), value_type (val), v);
     }
-  else if (TYPE_CODE (type1) == TYPE_CODE_BOOL
-	   &&
-	   TYPE_CODE (type2) == TYPE_CODE_BOOL)
+  else if (TYPE_CODE (result_type) == TYPE_CODE_BOOL)
     {
       LONGEST v1, v2, v = 0;
       v1 = value_as_long (arg1);
@@ -947,72 +1188,32 @@ value_binop (struct value *arg1, struct 
 	  error (_("Invalid operation on booleans."));
 	}
 
-      val = allocate_value (type1);
+      val = allocate_value (result_type);
       store_signed_integer (value_contents_raw (val),
-			    TYPE_LENGTH (type1),
+			    TYPE_LENGTH (result_type),
 			    v);
     }
   else
     /* Integral operations here.  */
-    /* FIXME:  Also mixed integral/booleans, with result an integer. */
-    /* FIXME: This implements ANSI C rules (also correct for C++).
-       What about FORTRAN and (the deleted) chill ?  */
     {
-      unsigned int promoted_len1 = TYPE_LENGTH (type1);
-      unsigned int promoted_len2 = TYPE_LENGTH (type2);
-      int is_unsigned1 = TYPE_UNSIGNED (type1);
-      int is_unsigned2 = TYPE_UNSIGNED (type2);
-      unsigned int result_len;
-      int unsigned_operation;
-
-      /* Determine type length and signedness after promotion for
-         both operands.  */
-      if (promoted_len1 < TYPE_LENGTH (builtin_type_int))
-	{
-	  is_unsigned1 = 0;
-	  promoted_len1 = TYPE_LENGTH (builtin_type_int);
-	}
-      if (promoted_len2 < TYPE_LENGTH (builtin_type_int))
-	{
-	  is_unsigned2 = 0;
-	  promoted_len2 = TYPE_LENGTH (builtin_type_int);
-	}
-
-      /* Determine type length of the result, and if the operation should
-         be done unsigned.
-         Use the signedness of the operand with the greater length.
-         If both operands are of equal length, use unsigned operation
-         if one of the operands is unsigned.  */
-      if (op == BINOP_RSH || op == BINOP_LSH)
-	{
-	  /* In case of the shift operators the type of the result only
-	     depends on the type of the left operand.  */
-	  unsigned_operation = is_unsigned1;
-	  result_len = promoted_len1;
-	}
-      else if (promoted_len1 > promoted_len2)
-	{
-	  unsigned_operation = is_unsigned1;
-	  result_len = promoted_len1;
-	}
-      else if (promoted_len2 > promoted_len1)
-	{
-	  unsigned_operation = is_unsigned2;
-	  result_len = promoted_len2;
-	}
-      else
-	{
-	  unsigned_operation = is_unsigned1 || is_unsigned2;
-	  result_len = promoted_len1;
-	}
+      int unsigned_operation = TYPE_UNSIGNED (result_type);
 
       if (unsigned_operation)
 	{
+	  unsigned int len1, len2, result_len;
 	  ULONGEST v1, v2, v = 0;
 	  v1 = (ULONGEST) value_as_long (arg1);
 	  v2 = (ULONGEST) value_as_long (arg2);
 
-	  /* Truncate values to the type length of the result.  */
+	  /* Truncate values to the type length of the result.
+	     Things are mildly trick because binop_result_type may
+	     return a long which on amd64 is 8 bytes, and that's a problem if
+	     ARG1, ARG2 are both <= 4 bytes.  We need to truncate the values
+	     at 4 bytes not 8.  So fetch the lengths of the original types
+	     and truncate at the larger of the two.  */
+	  len1 = TYPE_LENGTH (value_type (arg1));
+	  len2 = TYPE_LENGTH (value_type (arg1));
+	  result_len = len1 > len2 ? len1 : len2;
 	  if (result_len < sizeof (ULONGEST))
 	    {
 	      v1 &= ((LONGEST) 1 << HOST_CHAR_BIT * result_len) - 1;
@@ -1119,19 +1320,7 @@ value_binop (struct value *arg1, struct 
 	      error (_("Invalid binary operation on numbers."));
 	    }
 
-	  /* This is a kludge to get around the fact that we don't
-	     know how to determine the result type from the types of
-	     the operands.  (I'm not really sure how much we feel the
-	     need to duplicate the exact rules of the current
-	     language.  They can get really hairy.  But not to do so
-	     makes it hard to document just what we *do* do).  */
-
-	  /* Can't just call init_type because we wouldn't know what
-	     name to give the type.  */
-	  val = allocate_value
-	    (result_len > gdbarch_long_bit (current_gdbarch) / HOST_CHAR_BIT
-	     ? builtin_type_unsigned_long_long
-	     : builtin_type_unsigned_long);
+	  val = allocate_value (result_type);
 	  store_unsigned_integer (value_contents_raw (val),
 				  TYPE_LENGTH (value_type (val)),
 				  v);
@@ -1245,19 +1434,7 @@ value_binop (struct value *arg1, struct 
 	      error (_("Invalid binary operation on numbers."));
 	    }
 
-	  /* This is a kludge to get around the fact that we don't
-	     know how to determine the result type from the types of
-	     the operands.  (I'm not really sure how much we feel the
-	     need to duplicate the exact rules of the current
-	     language.  They can get really hairy.  But not to do so
-	     makes it hard to document just what we *do* do).  */
-
-	  /* Can't just call init_type because we wouldn't know what
-	     name to give the type.  */
-	  val = allocate_value
-	    (result_len > gdbarch_long_bit (current_gdbarch) / HOST_CHAR_BIT
-	     ? builtin_type_long_long
-	     : builtin_type_long);
+	  val = allocate_value (result_type);
 	  store_signed_integer (value_contents_raw (val),
 				TYPE_LENGTH (value_type (val)),
 				v);
@@ -1469,23 +1646,19 @@ struct value *
 value_pos (struct value *arg1)
 {
   struct type *type;
+  struct type *result_type;
 
   arg1 = coerce_ref (arg1);
-
   type = check_typedef (value_type (arg1));
+  result_type = unop_result_type (UNOP_PLUS, value_type (arg1));
 
   if (TYPE_CODE (type) == TYPE_CODE_FLT)
-    return value_from_double (type, value_as_double (arg1));
+    return value_from_double (result_type, value_as_double (arg1));
   else if (TYPE_CODE (type) == TYPE_CODE_DECFLOAT)
-    return value_from_decfloat (type, value_contents (arg1));
+    return value_from_decfloat (result_type, value_contents (arg1));
   else if (is_integral_type (type))
     {
-      /* Perform integral promotion for ANSI C/C++.  FIXME: What about
-         FORTRAN and (the deleted) chill ?  */
-      if (TYPE_LENGTH (type) < TYPE_LENGTH (builtin_type_int))
-	type = builtin_type_int;
-
-      return value_from_longest (type, value_as_long (arg1));
+      return value_from_longest (result_type, value_as_long (arg1));
     }
   else
     {
@@ -1498,11 +1671,11 @@ struct value *
 value_neg (struct value *arg1)
 {
   struct type *type;
-  struct type *result_type = value_type (arg1);
+  struct type *result_type;
 
   arg1 = coerce_ref (arg1);
-
   type = check_typedef (value_type (arg1));
+  result_type = unop_result_type (UNOP_NEG, value_type (arg1));
 
   if (TYPE_CODE (type) == TYPE_CODE_DECFLOAT)
     {
@@ -1520,16 +1693,10 @@ value_neg (struct value *arg1)
       memcpy (value_contents_raw (val), decbytes, len);
       return val;
     }
-
-  if (TYPE_CODE (type) == TYPE_CODE_FLT)
+  else if (TYPE_CODE (type) == TYPE_CODE_FLT)
     return value_from_double (result_type, -value_as_double (arg1));
   else if (is_integral_type (type))
     {
-      /* Perform integral promotion for ANSI C/C++.  FIXME: What about
-         FORTRAN and (the deleted) chill ?  */
-      if (TYPE_LENGTH (type) < TYPE_LENGTH (builtin_type_int))
-	result_type = builtin_type_int;
-
       return value_from_longest (result_type, -value_as_long (arg1));
     }
   else
@@ -1543,20 +1710,15 @@ struct value *
 value_complement (struct value *arg1)
 {
   struct type *type;
-  struct type *result_type = value_type (arg1);
+  struct type *result_type;
 
   arg1 = coerce_ref (arg1);
-
   type = check_typedef (value_type (arg1));
+  result_type = unop_result_type (UNOP_COMPLEMENT, value_type (arg1));
 
   if (!is_integral_type (type))
     error (_("Argument to complement operation not an integer or boolean."));
 
-  /* Perform integral promotion for ANSI C/C++.
-     FIXME: What about FORTRAN ?  */
-  if (TYPE_LENGTH (type) < TYPE_LENGTH (builtin_type_int))
-    result_type = builtin_type_int;
-
   return value_from_longest (result_type, ~value_as_long (arg1));
 }
 \f
Index: valops.c
===================================================================
RCS file: /cvs/src/src/gdb/valops.c,v
retrieving revision 1.182
diff -u -p -r1.182 valops.c
--- valops.c	18 Jan 2008 17:07:40 -0000	1.182
+++ valops.c	30 Jan 2008 02:15:02 -0000
@@ -471,6 +471,41 @@ value_zero (struct type *type, enum lval
   return val;
 }
 
+/* Create a value of numeric type TYPE that is one, and return it.  */
+
+struct value *
+value_one (struct type *type, enum lval_type lv)
+{
+  struct type *type1 = check_typedef (type);
+  struct value *val;
+
+  if (TYPE_CODE (type1) == TYPE_CODE_DECFLOAT)
+    {
+      struct value *int_one = value_from_longest (builtin_type_int, 1);
+      struct value *val;
+      gdb_byte v[16];
+
+      decimal_from_integral (int_one, v, TYPE_LENGTH (builtin_type_int));
+      val = value_from_decfloat (type, v);
+      value_free (int_one);
+    }
+  else if (TYPE_CODE (type1) == TYPE_CODE_FLT)
+    {
+      val = value_from_double (type, (DOUBLEST) 1);
+    }
+  else if (is_integral_type (type1))
+    {
+      val = value_from_longest (type, (LONGEST) 1);
+    }
+  else
+    {
+      error (_("Not a numeric type."));
+    }
+
+  VALUE_LVAL (val) = lv;
+  return val;
+}
+
 /* Return a value with type TYPE located at ADDR.
 
    Call value_at only if the data needs to be fetched immediately;
Index: value.h
===================================================================
RCS file: /cvs/src/src/gdb/value.h,v
retrieving revision 1.107
diff -u -p -r1.107 value.h
--- value.h	18 Jan 2008 17:07:40 -0000	1.107
+++ value.h	30 Jan 2008 02:15:03 -0000
@@ -392,6 +392,8 @@ extern struct value *value_cast (struct 
 
 extern struct value *value_zero (struct type *type, enum lval_type lv);
 
+extern struct value *value_one (struct type *type, enum lval_type lv);
+
 extern struct value *value_repeat (struct value *arg1, int count);
 
 extern struct value *value_subscript (struct value *array, struct value *idx);
Index: testsuite/gdb.base/whatis-exp.exp
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/gdb.base/whatis-exp.exp,v
retrieving revision 1.7
diff -u -p -r1.7 whatis-exp.exp
--- testsuite/gdb.base/whatis-exp.exp	1 Jan 2008 22:53:19 -0000	1.7
+++ testsuite/gdb.base/whatis-exp.exp	30 Jan 2008 02:15:04 -0000
@@ -112,7 +112,7 @@ gdb_expect {
 
 send_gdb "whatis x+y\n"
 gdb_expect {
-    -re ".*type = long.*$gdb_prompt $" {
+    -re ".*type = int.*$gdb_prompt $" {
         pass "whatis value of x+y"
       }
     -re ".*$gdb_prompt $" { fail "whatis value of x+y" }
@@ -121,7 +121,7 @@ gdb_expect {
 
 send_gdb "whatis x-y\n"
 gdb_expect {
-    -re ".*type = long.*$gdb_prompt $" {
+    -re ".*type = int.*$gdb_prompt $" {
         pass "whatis value of x-y"
       }
     -re ".*$gdb_prompt $" { fail "whatis value of x-y" }
@@ -130,7 +130,7 @@ gdb_expect {
 
 send_gdb "whatis x*y\n"
 gdb_expect {
-    -re ".*type = long.*$gdb_prompt $" {
+    -re ".*type = int.*$gdb_prompt $" {
         pass "whatis value of x*y"
       }
     -re ".*$gdb_prompt $" { fail "whatis value of x*y" }


^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2008-02-04  0:34 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-01-30  4:00 [RFA] BINOP_DIV and ptyp command Doug Evans
2008-01-31 22:48 ` Daniel Jacobowitz
  -- strict thread matches above, loose matches on Subject: below --
2008-01-30 18:05 Doug Evans
2008-01-30 22:58 ` Pierre Muller
2008-01-31  2:57   ` Doug Evans
2008-01-31 23:01 ` Daniel Jacobowitz
2008-02-04  0:34   ` Doug Evans
2008-01-30  3:38 Doug Evans

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox