binutils-gdb/gdb/testsuite/gdb.base/whatis-ptype-typedefs.c

144 lines
3.4 KiB
C
Raw Normal View History

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 <palves@redhat.com> * eval.c (evaluate_subexp_standard) <OP_TYPE>: 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 <palves@redhat.com> * 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.
2017-08-21 12:34:32 +02:00
/* This test program is part of GDB, the GNU debugger.
Copyright 2017 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* Define typedefs of different types, for testing the "whatis" and
"ptype" commands. */
/* Helper macro used to consistently define variables/typedefs using
the same name scheme. BASE is the shared part of the name of all
typedefs/variables generated. Defines a variable of the given
typedef type, and then a typedef of that typedef and a variable of
that new typedef type. The "double typedef" is useful to checking
that whatis only strips one typedef level. For example, if BASE is
"int", we get:
int_typedef v_int_typedef; // "v_" stands for variable of typedef type
typedef int_typedef int_typedef2; // typedef-of-typedef
int_typedef2 v_int_typedef2; // var of typedef-of-typedef
*/
#define DEF(base) \
base ## _typedef v_ ## base ## _typedef; \
\
typedef base ## _typedef base ## _typedef2; \
base ## _typedef2 v_ ## base ## _typedef2
/* Void. */
/* (Can't have variables of void type.) */
typedef void void_typedef;
typedef void_typedef void_typedef2;
void_typedef *v_void_typedef_ptr;
void_typedef2 *v_void_typedef_ptr2;
/* Integers. */
typedef int int_typedef;
DEF (int);
/* Floats. */
typedef float float_typedef;
DEF (float);
/* Enums. */
typedef enum colors {red, green, blue} colors_typedef;
DEF (colors);
/* Structures. */
typedef struct t_struct
{
int member;
} t_struct_typedef;
DEF (t_struct);
/* Unions. */
typedef union t_union
{
int member;
} t_union_typedef;
DEF (t_union);
/* Arrays. */
typedef int int_array_typedef[3];
DEF (int_array);
/* An array the same size of t_struct_typedef, so we can test casting. */
typedef unsigned char uchar_array_t_struct_typedef[sizeof (t_struct_typedef)];
DEF (uchar_array_t_struct);
/* A struct and a eunion the same size as t_struct, so we can test
casting. */
typedef struct t_struct_wrapper
{
struct t_struct base;
} t_struct_wrapper_typedef;
DEF (t_struct_wrapper);
typedef union t_struct_union_wrapper
{
struct t_struct base;
} t_struct_union_wrapper_typedef;
DEF (t_struct_union_wrapper);
/* Functions / function pointers. */
typedef void func_ftype (void);
func_ftype *v_func_ftype;
typedef func_ftype func_ftype2;
func_ftype2 *v_func_ftype2;
/* C++ methods / method pointers. */
#ifdef __cplusplus
namespace ns {
struct Struct { void method (); };
void Struct::method () {}
typedef Struct Struct_typedef;
DEF (Struct);
/* Typedefs/vars in a namespace. */
typedef void (Struct::*method_ptr_typedef) ();
DEF (method_ptr);
}
/* Similar, but in the global namespace. */
typedef ns::Struct ns_Struct_typedef;
DEF (ns_Struct);
typedef void (ns::Struct::*ns_method_ptr_typedef) ();
DEF (ns_method_ptr);
#endif
int
main (void)
{
return 0;
}