Commit c973d0aa authored by Pedro Alves's avatar Pedro Alves
Browse files

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.
parent 284d826d
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.
2017-08-18 Tom Tromey <tom@tromey.com>
Pedro Alves <palves@redhat.com>
......
......@@ -2727,18 +2727,7 @@ evaluate_subexp_standard (struct type *expect_type,
if (noside == EVAL_SKIP)
goto nosideret;
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);
}
return allocate_value (exp->elts[pc + 1].type);
else
error (_("Attempt to use a type name as an expression"));
......
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-18 Yao Qi <yao.qi@linaro.org>
* gdb.server/unittest.exp: New.
......
......@@ -91,6 +91,23 @@ volatile _Decimal32 d32;
volatile _Decimal64 d64;
volatile _Decimal128 d128;
/* Typedefs and typedefs of typedefs, for ptype/whatis testing. */
typedef _Decimal32 d32_t;
typedef _Decimal64 d64_t;
typedef _Decimal128 d128_t;
typedef d32_t d32_t2;
typedef d64_t d64_t2;
typedef d128_t d128_t2;
d32_t v_d32_t;
d64_t v_d64_t;
d128_t v_d128_t;
d32_t2 v_d32_t2;
d64_t2 v_d64_t2;
d128_t2 v_d128_t2;
struct decstruct
{
int int4;
......
......@@ -274,6 +274,10 @@ gdb_test "ptype d64 + ds.dec32" " = volatile _Decimal64"
gdb_test "ptype d128 + ds.dec32" " = volatile _Decimal128"
gdb_test "ptype d128 + ds.dec64" " = volatile _Decimal128"
gdb_test "whatis d64 + ds.dec32" " = volatile _Decimal64"
gdb_test "whatis d128 + ds.dec32" " = volatile _Decimal128"
gdb_test "whatis d128 + ds.dec64" " = volatile _Decimal128"
# Mixture of Decimal and integral operands
gdb_test "p d32 + 1" " = 1.1"
gdb_test "p 2 + d64" " = 2.1"
......@@ -331,3 +335,58 @@ gdb_test "print ds.dec128 = -ds.double8" " = 0.(0999.*|1000.*)"
gdb_test "print ds.dec128 = ds.dec32" " = -0.1"
gdb_test "print ds.dec32 = ds.int4" " = 1"
gdb_test "print ds.int4 = 7.3dl" " = 7"
# Test "whatis"/"ptype" of expressions involving casts to/from dfp
# typedefs.
# This list is composed by sub-lists, and their elements are (in
# order):
#
# - Type to cast to. This is also what "whatis" should print.
# - What "ptype" should print.
# Columns in the sublists represent:
# to/whatis # ptype
foreach elem {
{"_Decimal32" "_Decimal32"}
{"_Decimal64" "_Decimal64"}
{"_Decimal128" "_Decimal128"}
{"d32_t" "_Decimal32"}
{"d64_t" "_Decimal64"}
{"d128_t" "_Decimal128"}
{"d32_t2" "_Decimal32"}
{"d64_t2" "_Decimal64"}
{"d128_t2" "_Decimal128"}
} {
set type [lindex $elem 0]
set ptype [lindex $elem 1]
gdb_test "whatis ($type) 0" " = $type"
gdb_test "ptype ($type) 0" " = $ptype"
}
# Test:
# - whatis/ptype of variables of typedef type.
# - whatis/ptype of typedef type names.
# - whatis/ptype of typedef-of-typedef type names.
# Columns in the sublists represent:
# Type name # whatis # ptype
foreach elem {
{"v_d32_t" "d32_t" "_Decimal32"}
{"v_d64_t" "d64_t" "_Decimal64"}
{"v_d128_t" "d128_t" "_Decimal128"}
{"d32_t" "_Decimal32" "_Decimal32"}
{"d64_t" "_Decimal64" "_Decimal64"}
{"d128_t" "_Decimal128" "_Decimal128"}
{"d32_t2" "d32_t" "_Decimal32"}
{"d64_t2" "d64_t" "_Decimal64"}
{"d128_t2" "d128_t" "_Decimal128"}
} {
set type [lindex $elem 0]
set whatis [lindex $elem 1]
set ptype [lindex $elem 2]
gdb_test "whatis $type" " = $whatis"
gdb_test "ptype $type" " = $ptype"
}
......@@ -95,6 +95,17 @@ gdb_test "print -f4a" "\\\$$decimal = \\{-2, -4, -8, -16\\}"
gdb_test "print (char4) 0x01010101" "\\\$$decimal = \\{1, 1, 1, 1\\}"
gdb_test "print (int2) lla" "\\\$$decimal = \\{1, 1\\}"
# Check that "whatis" doesn't peel off the destination type's typedef
# by mistake, in expressions that involve a cast to typedef type.
gdb_test "whatis (char4) 0x01010101" "type = char4"
gdb_test "whatis (int2) lla" "type = int2"
# Check that OTOH "ptype" does peel off the destination type's
# typedef.
gdb_test "ptype (char4) 0x01010101" \
"type = char __attribute__ \\(\\(vector_size\\(4\\)\\)\\)"
gdb_test "ptype (int2) lla" \
"type = int __attribute__ \\(\\(vector_size\\(2\\)\\)\\)"
if { ![string compare $endian big] } then {
gdb_test "print (char4) ia" "\\\$$decimal = \\{0, 0, 0, 2\\}"
} else {
......@@ -167,16 +178,30 @@ gdb_test "print (double2) f2" "Cannot convert between vector values of different
gdb_test "print (int4) c4" "Cannot convert between vector values of different sizes"
gdb_test "print (char4) i4a" "Cannot convert between vector values of different sizes"
# Test ptype on vector types.
# Test ptype/whatis on vector types/vars.
gdb_test "ptype c4" "type = char __attribute__ \\(\\(vector_size\\(4\\)\\)\\)"
gdb_test "whatis c4" "type = char4"
gdb_test "ptype char4" "type = char __attribute__ \\(\\(vector_size\\(4\\)\\)\\)"
gdb_test "whatis char4" "type = char __attribute__ \\(\\(vector_size\\(4\\)\\)\\)"
gdb_test "ptype i4a" "type = int __attribute__ \\(\\(vector_size\\(4\\)\\)\\)"
gdb_test "whatis i4a" "type = int4"
gdb_test "ptype int4" "type = int __attribute__ \\(\\(vector_size\\(4\\)\\)\\)"
gdb_test "whatis int4" "type = int __attribute__ \\(\\(vector_size\\(4\\)\\)\\)"
gdb_test "ptype f4b" "type = float __attribute__ \\(\\(vector_size\\(4\\)\\)\\)"
gdb_test "whatis f4b" "type = float4"
gdb_test "ptype float4" "type = float __attribute__ \\(\\(vector_size\\(4\\)\\)\\)"
gdb_test "whatis float4" "type = float __attribute__ \\(\\(vector_size\\(4\\)\\)\\)"
gdb_test "ptype union_with_vector_1" "type = union {\r\n\[\t \]+int i;\r\n\[\t \]+char cv __attribute__ \\(\\(vector_size\\(4\\)\\)\\);\r\n}"
gdb_test "whatis union_with_vector_1" {type = union {...}}
gdb_test "ptype struct_with_vector_1" "type = struct {\r\n\[\t \]+int i;\r\n\[\t \]+char cv __attribute__ \\(\\(vector_size\\(4\\)\\)\\);\r\n\[\t \]+float4 f4;\r\n}"
gdb_test "whatis struct_with_vector_1" {type = struct {...}}
# Test inferior function calls with vector arguments and/or vector
# return values.
......
/* 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;
}
# 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/>.
# Test "whatis"/"ptype" of different typedef types, and of expressions
# involving casts to/from different typedefs.
#
# Particularly, when "whatis" is given a type name directly, it should
# strip one (and only one) typedef level. Otherwise, it should not
# strip any typedef at all. GDB used to incorrectly strip typedefs of
# expressions involving casts to typedef types. E.g., (gdb) print
# (int_typedef)0" shall result in a value of type "int_typedef", not
# "int".
standard_testfile
# Prepare for testing in language LANG. Lang can be "c" or "c++".
proc prepare {lang} {
global srcfile testfile
if [target_info exists no_long_long] {
set options [list debug additional_flags=-DNO_LONG_LONG]
} else {
set options [list debug]
}
if {$lang == "c++"} {
lappend options c++
set out $testfile-cxx
} else {
set out $testfile-c
}
if { [prepare_for_testing "failed to prepare" \
${out} [list $srcfile] $options] } {
return -1
}
if ![runto_main] then {
fail "can't run to main"
return 0
}
}
# The following list is layed out as a table. It is composed by
# sub-lists (lines), with each line representing one whatis/ptype
# test. The sub-list (line) elements (columns) are (in order):
#
# EXP - The user expression passed to whatis/ptype.
#
# WHATIS - What "whatis" should print.
#
# If the EXP column is a type name, then this will be the same type,
# with one (and only one) typedef level removed. Otherwise, this is
# the type of the expression on the first column, with all typedefs
# preserved.
#
# PTYPE - What "ptype" should print.
#
# This is always the type of the input type/expression stripped from
# all typedefs.
#
# LANGUAGE - If the line is language-specific, which language.
#
# This can be "c" or "c++".
#
# Columns in the table represent:
# EXP # whatis # ptype # language
set table {
{"void_typedef" "void" "void"}
{"void_typedef2" "void_typedef" "void"}
{"int_typedef" "int" "int"}
{"int_typedef2" "int_typedef" "int"}
{"v_int_typedef" "int_typedef" "int"}
{"v_int_typedef2" "int_typedef2" "int"}
{"float_typedef" "float" "float"}
{"float_typedef2" "float_typedef" "float"}
{"v_float_typedef" "float_typedef" "float"}
{"v_float_typedef2" "float_typedef2" "float"}
{"colors_typedef" "(enum )?colors" "enum colors( : unsigned int)? {red, green, blue}"}
{"colors_typedef2" "colors_typedef" "enum colors( : unsigned int)? {red, green, blue}"}
{"v_colors_typedef" "colors_typedef" "enum colors( : unsigned int)? {red, green, blue}"}
{"v_colors_typedef2" "colors_typedef2" "enum colors( : unsigned int)? {red, green, blue}"}
{"func_ftype" "void \\(void\\)" "void \\(void\\)"}
{"func_ftype2" "func_ftype" "void \\(void\\)"}
{"func_ftype *" "func_ftype \\*" "void \\(\\*\\)\\(void\\)"}
{"func_ftype2 *" "func_ftype2 \\*" "void \\(\\*\\)\\(void\\)"}
{"v_func_ftype" "func_ftype \\*" "void \\(\\*\\)\\(void\\)"}
{"v_func_ftype2" "func_ftype2 \\*" "void \\(\\*\\)\\(void\\)"}
{"v_t_struct_typedef" "t_struct_typedef" "struct t_struct {.* member;.*}"}
{"v_t_struct_typedef2" "t_struct_typedef2" "struct t_struct {.* member;.*}"}
{"v_t_struct_union_wrapper_typedef" "t_struct_union_wrapper_typedef" "union t_struct_union_wrapper {.*base;.*}"}
{"v_t_struct_union_wrapper_typedef2" "t_struct_union_wrapper_typedef2" "union t_struct_union_wrapper {.*base;.*}"}
{"v_uchar_array_t_struct_typedef" "uchar_array_t_struct_typedef" "unsigned char \\[.*\\]"}
{"v_uchar_array_t_struct_typedef2" "uchar_array_t_struct_typedef2" "unsigned char \\[.*\\]"}
{"v_ns_Struct_typedef" "ns_Struct_typedef" "struct ns::Struct {.* method.*}" "c++"}
{"ns_method_ptr_typedef"
"void \\(ns::Struct::\\*\\)\\(ns::Struct \\* const\\)"
"void \\(ns::Struct::\\*\\)\\(ns::Struct \\* const\\)"
"c++"}
{"ns::method_ptr_typedef"
"void \\(ns::Struct::\\*\\)\\(ns::Struct \\* const\\)"
"void \\(ns::Struct::\\*\\)\\(ns::Struct \\* const\\)"
"c++"}
{"ns_method_ptr_typedef2"
"ns_method_ptr_typedef"
"void \\(ns::Struct::\\*\\)\\(ns::Struct \\* const\\)"
"c++"}
{"ns::method_ptr_typedef2"
"ns::method_ptr_typedef"
"void \\(ns::Struct::\\*\\)\\(ns::Struct \\* const\\)"
"c++"}
{"ns::Struct::method"
"void \\(ns::Struct \\* const\\)"
"void \\(ns::Struct \\* const\\)"
"c++"}
}
# The 4th column above is optional. If present, it indicates that the
# line should only be tested in the specified language. This is a
# helper function that checks whether LINE's language matches LANG.
proc line_lang_match {line lang} {
if {[llength $line] <= 3} {
return true
}
set line_lang [lindex $line 3]
if {$line_lang == "" || $lang == $line_lang} {
return true
}
return false
}
# Run tests in language LANG.
proc run_tests {lang} {
global table
global gdb_prompt
# Test passing all EXP in the list/table above to whatis/ptype,
# and check what comes out.
with_test_prefix "whatis/ptype" {
foreach line $table {
set type [lindex $line 0]
set whatis [lindex $line 1]
set ptype [lindex $line 2]
if {![line_lang_match $line $lang]} {
continue
}
# GCC doesn't record the target type of "typedef of
# typedef of void" types in the DWARF. See
# <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81267>.
# Handle that case manually in order to be able to xfail
# it.
if {$type == "void_typedef2"} {
set test "whatis $type"
gdb_test_multiple $test $test {
-re "type = void\r\n$gdb_prompt $" {
# gcc/81267.
setup_xfail "*-*-*"
fail "$test (void)"
}
-re "type = void_typedef\r\n$gdb_prompt $" {
pass $test
}
}
} else {
gdb_test "whatis $type" "type = $whatis"
}
gdb_test "ptype $type" "type = $ptype"
}
}
# Test converting/casting all variables in the first column of the
# table to all types (found in the first column of the table).
# The aggregates are all defined to be the same size so that
# casting actually works. (GDB's casting operator is more general
# than a C cast.)
#
# The main idea here is testing all the different paths in the
# value casting code in GDB (value_cast), making sure typedefs are
# preserved.
with_test_prefix "cast" {
foreach line1 $table {
set from [lindex $line1 0]
if {![line_lang_match $line1 $lang]} {
continue
}
foreach line2 $table {
set to [lindex $line2 0]
set whatis [lindex $line2 1]
set ptype [lindex $line2 2]
if {![line_lang_match $line2 $lang]} {
continue
}
# We try all combinations, even those that don't
# parse, or are invalid, to catch the case of a
# regression making them inadvertently valid. For
# example, these convertions are invalid:
#
# float <-> array
# array -> function (not function pointer)
# array -> member_ptr
#
# while these are invalid syntax:
#
# (anything) type
# (var) anything
# (method) anything [not method pointer]
# (float) method
#
if {([string match "v_*" $to]
|| (![string match "v_*" $from] && ![string match "*method" $from])
|| [string match "*method" $to])} {
gdb_test "whatis ($to) $from" "syntax error.*" "whatis ($to) $from (syntax)"
gdb_test "ptype ($to) $from" "syntax error.*" "ptype ($to) $from (syntax)"
} elseif {([string match "*float*" $from] && [string match "*array*" $to])
|| ([string match "float*" $to] && [string match "*array*" $from])
|| ([string match "float*" $to] && [string match "*method" $from])
|| ([string match "*ftype" $to] && [string match "*array*" $from])
|| ([string match "*ftype2" $to] && [string match "*array*" $from])
|| ([string match "*ftype" $to] && [string match "*method" $from])
|| ([string match "*ftype2" $to] && [string match "*method" $from])
|| ([string match "*method_ptr*" $to] && [string match "*method" $from])
|| ([string match "*method_ptr*" $to] && [string match "*array*" $from])} {
gdb_test "whatis ($to) $from" "Invalid cast." "whatis ($to) $from (invalid)"
gdb_test "ptype ($to) $from" "Invalid cast." "ptype ($to) $from (invalid)"
} else {
gdb_test "whatis ($to) $from" "type = [string_to_regexp $to]"
gdb_test "ptype ($to) $from" "type = $ptype"
}
}
}
}
}
foreach_with_prefix lang {"c" "c++"} {
prepare $lang
run_tests $lang
}
......@@ -257,6 +257,15 @@ bug_14741()
set_item(&c, 0, 5);
}
/* Some typedefs/variables for checking that GDB doesn't lose typedefs
when looking for a printer. */
typedef int int_type;
typedef int_type int_type2;
int an_int = -1;
int_type an_int_type = 1;
int_type2 an_int_type2 = 2;
<