From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 18664 invoked by alias); 30 Jan 2008 03:38:52 -0000 Received: (qmail 18626 invoked by uid 22791); 30 Jan 2008 03:38:47 -0000 X-Spam-Check-By: sourceware.org Received: from sebabeach.org (HELO sebabeach.org) (64.165.110.50) by sourceware.org (qpsmtpd/0.31) with ESMTP; Wed, 30 Jan 2008 03:38:17 +0000 Received: by sebabeach.org (Postfix, from userid 500) id 372AE13EC2; Tue, 29 Jan 2008 19:35:51 -0800 (PST) From: Doug Evans To: gdb-patches@sourceware.org Subject: Re: [RFA] BINOP_DIV and ptyp command Message-Id: <20080130033551.372AE13EC2@sebabeach.org> Date: Wed, 30 Jan 2008 04:00:00 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2008-01/txt/msg00761.txt.bz2 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 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) } } +/* 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 }; 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); } +/* 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)); } 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" }