From c973d0aa4a2c737ab527ae44a617f1c357e07364 Mon Sep 17 00:00:00 2001 From: Pedro Alves Date: Mon, 21 Aug 2017 11:34:32 +0100 Subject: Fix type casts losing typedefs and reimplement "whatis" typedef stripping (Ref: https://sourceware.org/ml/gdb/2017-06/msg00020.html) Assuming int_t is a typedef to int: typedef int int_t; gdb currently loses this expression's typedef: (gdb) p (int_t) 0 $1 = 0 (gdb) whatis $1 type = int or: (gdb) whatis (int_t) 0 type = int or, to get "whatis" out of the way: (gdb) maint print type (int_t) 0 ... name 'int' code 0x8 (TYPE_CODE_INT) ... This prevents a type printer for "int_t" kicking in, with e.g.: (gdb) p (int_t) 0 From the manual, we can see that that "whatis (int_t) 0" command invocation should have printed "type = int_t": If @var{arg} is a variable or an expression, @code{whatis} prints its literal type as it is used in the source code. If the type was defined using a @code{typedef}, @code{whatis} will @emph{not} print the data type underlying the @code{typedef}. (...) If @var{arg} is a type name that was defined using @code{typedef}, @code{whatis} @dfn{unrolls} only one level of that @code{typedef}. That one-level stripping is currently done here, in gdb/eval.c:evaluate_subexp_standard, handling OP_TYPE: ... else if (noside == EVAL_AVOID_SIDE_EFFECTS) { struct type *type = exp->elts[pc + 1].type; /* If this is a typedef, then find its immediate target. We use check_typedef to resolve stubs, but we ignore its result because we do not want to dig past all typedefs. */ check_typedef (type); if (TYPE_CODE (type) == TYPE_CODE_TYPEDEF) type = TYPE_TARGET_TYPE (type); return allocate_value (type); } However, this stripping is reachable in both: #1 - (gdb) whatis (int_t)0 # ARG is an expression with a cast to # typedef type. #2 - (gdb) whatis int_t # ARG is a type name. while only case #2 should strip the typedef. Removing that code from evaluate_subexp_standard is part of the fix. Instead, we make the "whatis" command implementation itself strip one level of typedefs when the command argument is a type name. We then run into another problem, also fixed by this commit: value_cast always drops any typedefs of the destination type. With all that fixed, "whatis (int_t) 0" now works as expected: (gdb) whatis int_t type = int (gdb) whatis (int_t)0 type = int_t value_cast has many different exit/convertion paths, for handling many different kinds of casts/conversions, and most of them had to be tweaked to construct the value of the right "to" type. The new tests try to exercise most of it, by trying castin of many different combinations of types. With: $ make check TESTS="*/whatis-ptype*.exp */gnu_vector.exp */dfp-test.exp" ... due to combinatorial explosion, the testsuite results for the tests above alone grow like: - # of expected passes 246 + # of expected passes 3811 You'll note that the tests exposed one GCC buglet, filed here: Missing DW_AT_type in DW_TAG_typedef of "typedef of typedef of void" https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81267 gdb/ChangeLog: 2017-08-21 Pedro Alves * eval.c (evaluate_subexp_standard) : Don't dig past typedefs. * typeprint.c (whatis_exp): If handling "whatis", and expression is OP_TYPE, strip one typedef level. Otherwise don't strip typedefs here. * valops.c (value_cast): Save "to" type before resolving stubs/typedefs. Use that type as resulting value's type. gdb/testsuite/ChangeLog: 2017-08-21 Pedro Alves * gdb.base/dfp-test.c (d32_t, d64_t, d128_t, d32_t2, d64_t2, d128_t2, v_d32_t, v_d64_t) (v_d128_t, v_d32_t2, v_d64_t2, v_d128_t2): New. * gdb.base/dfp-test.exp: Add whatis/ptype/cast tests. * gdb.base/gnu_vector.exp: Add whatis/ptype/cast tests. * gdb.base/whatis-ptype-typedefs.c: New. * gdb.base/whatis-ptype-typedefs.exp: New. * gdb.python/py-prettyprint.c (int_type, int_type2): New typedefs. (an_int, an_int_type, an_int_type2): New globals. * gdb.python/py-prettyprint.exp (run_lang_tests): Add tests involving typedefs and cast expressions. * gdb.python/py-prettyprint.py (class pp_int_typedef): New. (lookup_typedefs_function): New. (typedefs_pretty_printers_dict): New. (top level): Register lookup_typedefs_function in gdb.pretty_printers. --- gdb/valops.c | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) (limited to 'gdb/valops.c') diff --git a/gdb/valops.c b/gdb/valops.c index 3668f0b..c1bb937 100644 --- a/gdb/valops.c +++ b/gdb/valops.c @@ -379,6 +379,11 @@ value_cast (struct type *type, struct value *arg2) /* We deref the value and then do the cast. */ return value_cast (type, coerce_ref (arg2)); + /* Strip typedefs / resolve stubs in order to get at the type's + code/length, but remember the original type, to use as the + resulting type of the cast, in case it was a typedef. */ + struct type *to_type = type; + type = check_typedef (type); code1 = TYPE_CODE (type); arg2 = coerce_ref (arg2); @@ -434,7 +439,7 @@ value_cast (struct type *type, struct value *arg2) code2 = TYPE_CODE (type2); if (code1 == TYPE_CODE_COMPLEX) - return cast_into_complex (type, arg2); + return cast_into_complex (to_type, arg2); if (code1 == TYPE_CODE_BOOL) { code1 = TYPE_CODE_INT; @@ -453,14 +458,14 @@ value_cast (struct type *type, struct value *arg2) && (code2 == TYPE_CODE_STRUCT || code2 == TYPE_CODE_UNION) && TYPE_NAME (type) != 0) { - struct value *v = value_cast_structs (type, arg2); + struct value *v = value_cast_structs (to_type, arg2); if (v) return v; } if (code1 == TYPE_CODE_FLT && scalar) - return value_from_double (type, value_as_double (arg2)); + return value_from_double (to_type, value_as_double (arg2)); else if (code1 == TYPE_CODE_DECFLOAT && scalar) { enum bfd_endian byte_order = gdbarch_byte_order (get_type_arch (type)); @@ -476,7 +481,7 @@ value_cast (struct type *type, struct value *arg2) /* The only option left is an integral type. */ decimal_from_integral (arg2, dec, dec_len, byte_order); - return value_from_decfloat (type, dec); + return value_from_decfloat (to_type, dec); } else if ((code1 == TYPE_CODE_INT || code1 == TYPE_CODE_ENUM || code1 == TYPE_CODE_RANGE) @@ -497,7 +502,7 @@ value_cast (struct type *type, struct value *arg2) gdbarch_byte_order (get_type_arch (type2))); else longest = value_as_long (arg2); - return value_from_longest (type, convert_to_boolean ? + return value_from_longest (to_type, convert_to_boolean ? (LONGEST) (longest ? 1 : 0) : longest); } else if (code1 == TYPE_CODE_PTR && (code2 == TYPE_CODE_INT @@ -523,14 +528,14 @@ value_cast (struct type *type, struct value *arg2) || longest <= -((LONGEST) 1 << addr_bit)) warning (_("value truncated")); } - return value_from_longest (type, longest); + return value_from_longest (to_type, longest); } else if (code1 == TYPE_CODE_METHODPTR && code2 == TYPE_CODE_INT && value_as_long (arg2) == 0) { - struct value *result = allocate_value (type); + struct value *result = allocate_value (to_type); - cplus_make_method_ptr (type, value_contents_writeable (result), 0, 0); + cplus_make_method_ptr (to_type, value_contents_writeable (result), 0, 0); return result; } else if (code1 == TYPE_CODE_MEMBERPTR && code2 == TYPE_CODE_INT @@ -538,7 +543,7 @@ value_cast (struct type *type, struct value *arg2) { /* The Itanium C++ ABI represents NULL pointers to members as minus one, instead of biasing the normal case. */ - return value_from_longest (type, -1); + return value_from_longest (to_type, -1); } else if (code1 == TYPE_CODE_ARRAY && TYPE_VECTOR (type) && code2 == TYPE_CODE_ARRAY && TYPE_VECTOR (type2) @@ -549,21 +554,21 @@ value_cast (struct type *type, struct value *arg2) error (_("can only cast scalar to vector of same size")); else if (code1 == TYPE_CODE_VOID) { - return value_zero (type, not_lval); + return value_zero (to_type, not_lval); } else if (TYPE_LENGTH (type) == TYPE_LENGTH (type2)) { if (code1 == TYPE_CODE_PTR && code2 == TYPE_CODE_PTR) - return value_cast_pointers (type, arg2, 0); + return value_cast_pointers (to_type, arg2, 0); arg2 = value_copy (arg2); - deprecated_set_value_type (arg2, type); - set_value_enclosing_type (arg2, type); + deprecated_set_value_type (arg2, to_type); + set_value_enclosing_type (arg2, to_type); set_value_pointed_to_offset (arg2, 0); /* pai: chk_val */ return arg2; } else if (VALUE_LVAL (arg2) == lval_memory) - return value_at_lazy (type, value_address (arg2)); + return value_at_lazy (to_type, value_address (arg2)); else { error (_("Invalid cast.")); -- cgit v1.1