1# Copyright 2017-2020 Free Software Foundation, Inc.
2
3# This program is free software; you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by
5# the Free Software Foundation; either version 3 of the License, or
6# (at your option) any later version.
7#
8# This program is distributed in the hope that it will be useful,
9# but WITHOUT ANY WARRANTY; without even the implied warranty of
10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11# GNU General Public License for more details.
12#
13# You should have received a copy of the GNU General Public License
14# along with this program.  If not, see <http://www.gnu.org/licenses/>.
15
16# Test "whatis"/"ptype" of different typedef types, and of expressions
17# involving casts to/from different typedefs.
18#
19# Particularly, when "whatis" is given a type name directly, it should
20# strip one (and only one) typedef level.  Otherwise, it should not
21# strip any typedef at all.  GDB used to incorrectly strip typedefs of
22# expressions involving casts to typedef types.  E.g., (gdb) print
23# (int_typedef)0" shall result in a value of type "int_typedef", not
24# "int".
25
26standard_testfile
27
28# Prepare for testing in language LANG.  Lang can be "c" or "c++".
29
30proc prepare {lang} {
31    global srcfile testfile
32
33    if [target_info exists no_long_long] {
34	set options [list debug additional_flags=-DNO_LONG_LONG]
35    } else {
36	set options [list debug]
37    }
38
39    if {$lang == "c++"} {
40	lappend options c++
41	set out $testfile-cxx
42    } else {
43	set out $testfile-c
44    }
45
46    if { [prepare_for_testing "failed to prepare" \
47	      ${out} [list $srcfile] $options] } {
48	return 0
49    }
50
51    if ![runto_main] then {
52	fail "can't run to main"
53	return 0
54    }
55
56    return 1
57}
58
59# The following list is layed out as a table.  It is composed by
60# sub-lists (lines), with each line representing one whatis/ptype
61# test.  The sub-list (line) elements (columns) are (in order):
62#
63# EXP - The user expression passed to whatis/ptype.
64#
65# WHATIS - What "whatis" should print.
66#
67# If the EXP column is a type name, then this will be the same type,
68# with one (and only one) typedef level removed.  Otherwise, this is
69# the type of the expression on the first column, with all typedefs
70# preserved.
71#
72# PTYPE - What "ptype" should print.
73#
74# This is always the type of the input type/expression stripped from
75# all typedefs.
76#
77# LANGUAGE - If the line is language-specific, which language.
78#
79# This can be "c" or "c++".
80#
81# Columns in the table represent:
82     # EXP                # whatis           # ptype           # language
83set table {
84    {"void_typedef"       "void"              "void"}
85    {"void_typedef2"      "void_typedef"      "void"}
86
87    {"int_typedef"        "int"              "int"}
88    {"int_typedef2"       "int_typedef"      "int"}
89    {"v_int_typedef"      "int_typedef"      "int"}
90    {"v_int_typedef2"     "int_typedef2"     "int"}
91
92    {"float_typedef"      "float"            "float"}
93    {"float_typedef2"     "float_typedef"    "float"}
94    {"v_float_typedef"    "float_typedef"    "float"}
95    {"v_float_typedef2"   "float_typedef2"   "float"}
96
97    {"double_typedef"     "double"           "double"}
98    {"double_typedef2"    "double_typedef"   "double"}
99    {"v_double_typedef"   "double_typedef"   "double"}
100    {"v_double_typedef2"  "double_typedef2"  "double"}
101
102    {"long_double_typedef"    "long double"           "long double"}
103    {"long_double_typedef2"   "long_double_typedef"   "long double"}
104    {"v_long_double_typedef"  "long_double_typedef"   "long double"}
105    {"v_long_double_typedef2" "long_double_typedef2"  "long double"}
106
107    {"colors_typedef"     "(enum )?colors"   "enum colors( : unsigned int)? {red, green, blue}"}
108    {"colors_typedef2"    "colors_typedef"   "enum colors( : unsigned int)? {red, green, blue}"}
109    {"v_colors_typedef"   "colors_typedef"   "enum colors( : unsigned int)? {red, green, blue}"}
110    {"v_colors_typedef2"  "colors_typedef2"  "enum colors( : unsigned int)? {red, green, blue}"}
111
112    {"func_ftype"         "void \\(void\\)"  "void \\(void\\)"}
113    {"func_ftype2"        "func_ftype"       "void \\(void\\)"}
114
115    {"func_ftype *"       "func_ftype \\*"   "void \\(\\*\\)\\(void\\)"}
116    {"func_ftype2 *"      "func_ftype2 \\*"  "void \\(\\*\\)\\(void\\)"}
117    {"v_func_ftype"       "func_ftype \\*"   "void \\(\\*\\)\\(void\\)"}
118    {"v_func_ftype2"      "func_ftype2 \\*"  "void \\(\\*\\)\\(void\\)"}
119
120    {"v_t_struct_typedef"                "t_struct_typedef"                "struct t_struct {.* member;.*}"}
121    {"v_t_struct_typedef2"               "t_struct_typedef2"               "struct t_struct {.* member;.*}"}
122    {"v_t_struct_union_wrapper_typedef"  "t_struct_union_wrapper_typedef"  "union t_struct_union_wrapper {.*base;.*}"}
123    {"v_t_struct_union_wrapper_typedef2" "t_struct_union_wrapper_typedef2" "union t_struct_union_wrapper {.*base;.*}"}
124    {"v_uchar_array_t_struct_typedef"    "uchar_array_t_struct_typedef"    "unsigned char \\[.*\\]"}
125    {"v_uchar_array_t_struct_typedef2"   "uchar_array_t_struct_typedef2"   "unsigned char \\[.*\\]"}
126
127    {"v_ns_Struct_typedef"               "ns_Struct_typedef"                "struct ns::Struct {.* method.*}"   "c++"}
128
129    {"ns_method_ptr_typedef"
130	"void \\(ns::Struct::\\*\\)\\(ns::Struct \\* const\\)"
131	"void \\(ns::Struct::\\*\\)\\(ns::Struct \\* const\\)"
132	"c++"}
133
134    {"ns::method_ptr_typedef"
135	"void \\(ns::Struct::\\*\\)\\(ns::Struct \\* const\\)"
136	"void \\(ns::Struct::\\*\\)\\(ns::Struct \\* const\\)"
137	"c++"}
138
139    {"ns_method_ptr_typedef2"
140	"ns_method_ptr_typedef"
141	"void \\(ns::Struct::\\*\\)\\(ns::Struct \\* const\\)"
142	"c++"}
143
144    {"ns::method_ptr_typedef2"
145	"ns::method_ptr_typedef"
146	"void \\(ns::Struct::\\*\\)\\(ns::Struct \\* const\\)"
147	"c++"}
148
149    {"ns::Struct::method"
150	"void \\(ns::Struct \\* const\\)"
151	"void \\(ns::Struct \\* const\\)"
152	"c++"}
153}
154
155# The 4th column above is optional.  If present, it indicates that the
156# line should only be tested in the specified language.  This is a
157# helper function that checks whether LINE's language matches LANG.
158proc line_lang_match {line lang} {
159    if {[llength $line] <= 3} {
160	return true
161    }
162
163    set line_lang [lindex $line 3]
164    if {$line_lang == "" || $lang == $line_lang} {
165	return true
166    }
167
168    return false
169}
170
171# Run tests in language LANG.
172
173proc run_tests {lang} {
174    global table
175    global gdb_prompt
176
177    # Test passing all EXP in the list/table above to whatis/ptype,
178    # and check what comes out.
179    with_test_prefix "whatis/ptype" {
180	foreach line $table {
181	    set type [lindex $line 0]
182	    set whatis [lindex $line 1]
183	    set ptype [lindex $line 2]
184
185	    if {![line_lang_match $line $lang]} {
186		continue
187	    }
188
189	    # GCC doesn't record the target type of "typedef of
190	    # typedef of void" types in the DWARF.  See
191	    # <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81267>.
192	    # Handle that case manually in order to be able to xfail
193	    # it.
194	    if {$type == "void_typedef2"} {
195		set test "whatis $type"
196		gdb_test_multiple $test $test {
197		    -re "type = void\r\n$gdb_prompt $" {
198			# gcc/81267.
199			setup_xfail "*-*-*"
200			fail "$test (void)"
201		    }
202		    -re "type = void_typedef\r\n$gdb_prompt $" {
203			pass $test
204		    }
205		}
206	    } else {
207		gdb_test "whatis $type" "type = $whatis"
208	    }
209
210	    gdb_test "ptype $type" "type = $ptype"
211	}
212    }
213
214    # If floats and pointers have the same size on this architecture,
215    # then casting from array/function to float works, because
216    # arrays/functions first decay to pointers, and then GDB's cast is
217    # more general than a C cast and accepts any two types of the same
218    # length.
219    set float_ptr_same_size \
220	[get_integer_valueof "sizeof (float) == sizeof (void *)" -1]
221
222    # Ditto double.
223    set double_ptr_same_size \
224	[get_integer_valueof "sizeof (double) == sizeof (void *)" -1]
225
226    # Ditto long double.
227    set long_double_ptr_same_size \
228	[get_integer_valueof "sizeof (long double) == sizeof (void *)" -1]
229
230    # Test converting/casting all variables in the first column of the
231    # table to all types (found in the first column of the table).
232    # The aggregates are all defined to be the same size so that
233    # casting actually works.  (GDB's casting operator is more general
234    # than a C cast.)
235    #
236    # The main idea here is testing all the different paths in the
237    # value casting code in GDB (value_cast), making sure typedefs are
238    # preserved.
239    with_test_prefix "cast" {
240	foreach line1 $table {
241	    set from [lindex $line1 0]
242
243	    if {![line_lang_match $line1 $lang]} {
244		continue
245	    }
246
247	    foreach line2 $table {
248		set to [lindex $line2 0]
249		set whatis [lindex $line2 1]
250		set ptype [lindex $line2 2]
251
252		if {![line_lang_match $line2 $lang]} {
253		    continue
254		}
255
256		# We try all combinations, even those that don't
257		# parse, or are invalid, to catch the case of a
258		# regression making them inadvertently valid.  For
259		# example, these convertions are invalid:
260		#
261		#  float <-> array   [iff sizeof pointer != sizeof float]
262		#  array -> function (not function pointer)
263		#  array -> member_ptr
264		#
265		# while these are invalid syntax:
266		#
267		#  (anything) type
268		#  (var) anything
269		#  (method) anything   [not method pointer]
270		#  (float) method
271		#
272		if {([string match "v_*" $to]
273		     || (![string match "v_*" $from] && ![string match "*method" $from])
274		     || [string match "*method" $to])} {
275		    gdb_test "whatis ($to) $from" "syntax error.*" "whatis ($to) $from (syntax)"
276		    gdb_test "ptype ($to) $from" "syntax error.*" "ptype ($to) $from (syntax)"
277		} elseif {([string match "*float*" $from] && [string match "*array*" $to])
278			  || (!$float_ptr_same_size
279			      && ([string match "float*" $to] && [string match "*array*" $from]
280				  || [string match "float*" $to] && [string match "*method" $from]))
281			  || (!$double_ptr_same_size
282			      && ([string match "double*" $to] && [string match "*array*" $from]
283				  || [string match "double*" $to] && [string match "*method" $from]))
284			  || (!$long_double_ptr_same_size
285			      && ([string match "long_double*" $to] && [string match "*array*" $from]
286				  || [string match "long_double*" $to] && [string match "*method" $from]))
287			  || ([string match "*ftype" $to] && [string match "*array*" $from])
288			  || ([string match "*ftype2" $to] && [string match "*array*" $from])
289			  || ([string match "*ftype" $to] && [string match "*method" $from])
290			  || ([string match "*ftype2" $to] && [string match "*method" $from])
291			  || ([string match "*method_ptr*" $to] && [string match "*method" $from])
292			  || ([string match "*method_ptr*" $to] && [string match "*array*" $from])} {
293		    gdb_test "whatis ($to) $from" "Invalid cast." "whatis ($to) $from (invalid)"
294		    gdb_test "ptype ($to) $from" "Invalid cast." "ptype ($to) $from (invalid)"
295		} else {
296		    gdb_test "whatis ($to) $from" "type = [string_to_regexp $to]"
297		    gdb_test "ptype ($to) $from" "type = $ptype"
298		}
299	    }
300	}
301    }
302}
303
304foreach_with_prefix lang {"c" "c++"} {
305    if { [prepare $lang] } then {
306	run_tests $lang
307    }
308}
309