aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/ChangeLog10
-rw-r--r--gdb/eval.c13
-rw-r--r--gdb/testsuite/ChangeLog19
-rw-r--r--gdb/testsuite/gdb.base/dfp-test.c17
-rw-r--r--gdb/testsuite/gdb.base/dfp-test.exp59
-rw-r--r--gdb/testsuite/gdb.base/gnu_vector.exp27
-rw-r--r--gdb/testsuite/gdb.base/whatis-ptype-typedefs.c143
-rw-r--r--gdb/testsuite/gdb.base/whatis-ptype-typedefs.exp272
-rw-r--r--gdb/testsuite/gdb.python/py-prettyprint.c9
-rw-r--r--gdb/testsuite/gdb.python/py-prettyprint.exp13
-rw-r--r--gdb/testsuite/gdb.python/py-prettyprint.py34
-rw-r--r--gdb/typeprint.c36
-rw-r--r--gdb/valops.c33
13 files changed, 654 insertions, 31 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 7ad3f4c..fae7150 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,13 @@
+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>
diff --git a/gdb/eval.c b/gdb/eval.c
index 2a39774..80dfb2e 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -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"));
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index d188f83..03e825e 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,22 @@
+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.
diff --git a/gdb/testsuite/gdb.base/dfp-test.c b/gdb/testsuite/gdb.base/dfp-test.c
index 3af2b4d..a184acb 100644
--- a/gdb/testsuite/gdb.base/dfp-test.c
+++ b/gdb/testsuite/gdb.base/dfp-test.c
@@ -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;
diff --git a/gdb/testsuite/gdb.base/dfp-test.exp b/gdb/testsuite/gdb.base/dfp-test.exp
index 5f7b13d..c3a51a4 100644
--- a/gdb/testsuite/gdb.base/dfp-test.exp
+++ b/gdb/testsuite/gdb.base/dfp-test.exp
@@ -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"
+}
diff --git a/gdb/testsuite/gdb.base/gnu_vector.exp b/gdb/testsuite/gdb.base/gnu_vector.exp
index 44b1405..dac1714 100644
--- a/gdb/testsuite/gdb.base/gnu_vector.exp
+++ b/gdb/testsuite/gdb.base/gnu_vector.exp
@@ -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.
diff --git a/gdb/testsuite/gdb.base/whatis-ptype-typedefs.c b/gdb/testsuite/gdb.base/whatis-ptype-typedefs.c
new file mode 100644
index 0000000..5711a96
--- /dev/null
+++ b/gdb/testsuite/gdb.base/whatis-ptype-typedefs.c
@@ -0,0 +1,143 @@
+/* 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;
+}
diff --git a/gdb/testsuite/gdb.base/whatis-ptype-typedefs.exp b/gdb/testsuite/gdb.base/whatis-ptype-typedefs.exp
new file mode 100644
index 0000000..d333d81
--- /dev/null
+++ b/gdb/testsuite/gdb.base/whatis-ptype-typedefs.exp
@@ -0,0 +1,272 @@
+# 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
+}
diff --git a/gdb/testsuite/gdb.python/py-prettyprint.c b/gdb/testsuite/gdb.python/py-prettyprint.c
index fd58358..82f9fe7 100644
--- a/gdb/testsuite/gdb.python/py-prettyprint.c
+++ b/gdb/testsuite/gdb.python/py-prettyprint.c
@@ -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;
+
int
main ()
{
diff --git a/gdb/testsuite/gdb.python/py-prettyprint.exp b/gdb/testsuite/gdb.python/py-prettyprint.exp
index b0a9e32..02300e9 100644
--- a/gdb/testsuite/gdb.python/py-prettyprint.exp
+++ b/gdb/testsuite/gdb.python/py-prettyprint.exp
@@ -110,6 +110,19 @@ proc run_lang_tests {exefile lang} {
gdb_test "print nstype" " = {.0. = 7, .1. = 42}" \
"print nstype on one line"
+ # Check that GDB doesn't lose typedefs when looking for a printer.
+ gdb_test "print an_int" " = -1"
+ gdb_test "print (int) an_int" " = -1"
+ gdb_test "print (int_type) an_int" " = type=int_type, val=-1"
+
+ gdb_test "print an_int_type" " = type=int_type, val=1"
+ gdb_test "print (int_type) an_int_type" " = type=int_type, val=1"
+
+ gdb_test "print an_int_type2" " = type=int_type2, val=2"
+ gdb_test "print (int) an_int_type2" " = 2"
+ gdb_test "print (int_type) an_int_type2" " = type=int_type, val=2"
+ gdb_test "print (int_type2) an_int_type2" " = type=int_type2, val=2"
+
gdb_continue_to_end
}
diff --git a/gdb/testsuite/gdb.python/py-prettyprint.py b/gdb/testsuite/gdb.python/py-prettyprint.py
index c56f564..ec845e4 100644
--- a/gdb/testsuite/gdb.python/py-prettyprint.py
+++ b/gdb/testsuite/gdb.python/py-prettyprint.py
@@ -227,6 +227,13 @@ class pp_eval_type (object):
gdb.execute("bt", to_string=True)
return "eval=<" + str(gdb.parse_and_eval("eval_func (123456789, 2, 3, 4, 5, 6, 7, 8)")) + ">"
+class pp_int_typedef (object):
+ def __init__(self, val):
+ self.val = val
+
+ def to_string(self):
+ return "type=%s, val=%s" % (self.val.type, int(self.val))
+
def lookup_function (val):
"Look-up and return a pretty-printer that can print val."
@@ -263,6 +270,26 @@ def disable_lookup_function ():
def enable_lookup_function ():
lookup_function.enabled = True
+# Lookup a printer for VAL in the typedefs dict.
+def lookup_typedefs_function (val):
+ "Look-up and return a pretty-printer that can print val (typedefs)."
+
+ # Get the type.
+ type = val.type
+
+ if type == None or type.name == None or type.code != gdb.TYPE_CODE_TYPEDEF:
+ return None
+
+ # Iterate over local dictionary of typedef types to determine if a
+ # printer is registered for that type. Return an instantiation of
+ # the printer if found.
+ for function in typedefs_pretty_printers_dict:
+ if function.match (type.name):
+ return typedefs_pretty_printers_dict[function] (val)
+
+ # Cannot find a pretty printer.
+ return None
+
def register_pretty_printers ():
pretty_printers_dict[re.compile ('^struct s$')] = pp_s
pretty_printers_dict[re.compile ('^s$')] = pp_s
@@ -309,7 +336,14 @@ def register_pretty_printers ():
pretty_printers_dict[re.compile ('^eval_type_s$')] = pp_eval_type
+ typedefs_pretty_printers_dict[re.compile ('^int_type$')] = pp_int_typedef
+ typedefs_pretty_printers_dict[re.compile ('^int_type2$')] = pp_int_typedef
+
+# Dict for struct types with typedefs fully stripped.
pretty_printers_dict = {}
+# Dict for typedef types.
+typedefs_pretty_printers_dict = {}
register_pretty_printers ()
gdb.pretty_printers.append (lookup_function)
+gdb.pretty_printers.append (lookup_typedefs_function)
diff --git a/gdb/typeprint.c b/gdb/typeprint.c
index fc687d3..045271a 100644
--- a/gdb/typeprint.c
+++ b/gdb/typeprint.c
@@ -443,12 +443,40 @@ whatis_exp (char *exp, int show)
}
expression_up expr = parse_expression (exp);
- val = evaluate_type (expr.get ());
+
+ /* The behavior of "whatis" depends on whether the user
+ expression names a type directly, or a language expression
+ (including variable names). If the former, then "whatis"
+ strips one level of typedefs, only. If an expression,
+ "whatis" prints the type of the expression without stripping
+ any typedef level. "ptype" always strips all levels of
+ typedefs. */
+ if (show == -1 && expr->elts[0].opcode == OP_TYPE)
+ {
+ /* The user expression names a type directly. */
+ type = expr->elts[1].type;
+
+ /* If this is a typedef, then find its immediate target.
+ Use check_typedef to resolve stubs, but 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);
+ }
+ else
+ {
+ /* The user expression names a type indirectly by naming an
+ object or expression of that type. Find that
+ indirectly-named type. */
+ val = evaluate_type (expr.get ());
+ type = value_type (val);
+ }
}
else
- val = access_value_history (0);
-
- type = value_type (val);
+ {
+ val = access_value_history (0);
+ type = value_type (val);
+ }
get_user_print_options (&opts);
if (opts.objectprint)
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."));