1# Copyright 2017-2023 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# Tests for function local static variables, both C and C++.
17
18# This file is part of the gdb testsuite.
19
20standard_testfile .c
21
22# A few expected errors.
23set syntax_re "A syntax error in expression, near.*"
24set cannot_resolve_re "Cannot resolve method S::method to any overloaded instance"
25
26# Build an "Cannot resolve method ..." expected error string for
27# method METH.
28#
29proc cannot_resolve {meth} {
30    return "Cannot resolve method $meth to any overloaded instance"
31}
32
33# A list of scopes that have the static variables that we want to
34# print.  Each entry has, in order, the scope/function name, and the
35# prefix used by the static variables.  The prefix exists both to make
36# it easier to debug the test if something goes wrong, and, to make
37# sure that printing the static local of one method overload doesn't
38# find the variables of the wrong overload.
39#
40# While at it, we also try printing each scope without the static
41# local, to check that the parse copes with cv overloads without
42# quoting.  That's what the third and forth columns are for.  Note
43# that printing "func()" is different from "func(void)".  The former
44# is an inferior function call, while the latter is a reference to the
45# function.
46
47     #SCOPE				#PREFIX         #PRINT-SCOPE-QUOTED
48							#PRINT-SCOPE-UNQUOTED (opt)
49set cxx_scopes_list {
50    {"S::method()"			"S_M"		{= \\{void \\(S \\* const\\)\\} $hex <S::method\\(\\)>}
51							{[cannot_resolve "S::method"]}}
52
53    {"S::method() const"		"S_M_C"		{= \\{void \\(const S \\* const\\)\\} $hex <S::method\\(\\) const>}
54							$syntax_re}
55
56    {"S::method() volatile"		"S_M_V"		{= \\{void \\(volatile S \\* const\\)\\} $hex <S::method\\(\\) volatile>}
57							$syntax_re}
58
59    {"S::method() const volatile"	"S_M_CV"	{= \\{void \\(const volatile S \\* const\\)\\} $hex <S::method\\(\\) const volatile>}
60							$syntax_re}
61
62    {"S::method() volatile const"	"S_M_CV"	{= \\{void \\(const volatile S \\* const\\)\\} $hex <S::method\\(\\) const volatile>}
63							$syntax_re}
64
65    {"S::method(void)"			"S_M"		{= \\{void \\(S \\* const\\)\\} $hex <S::method\\(\\)>}}
66    {"S::method(void) const"		"S_M_C"		{= \\{void \\(const S \\* const\\)\\} $hex <S::method\\(\\) const>}}
67    {"S::method(void) volatile"		"S_M_V"		{= \\{void \\(volatile S \\* const\\)\\} $hex <S::method\\(\\) volatile>}}
68    {"S::method(void) const volatile"	"S_M_CV"	{= \\{void \\(const volatile S \\* const\\)\\} $hex <S::method\\(\\) const volatile>}}
69    {"S::method(void) volatile const"	"S_M_CV"	{= \\{void \\(const volatile S \\* const\\)\\} $hex <S::method\\(\\) const volatile>}}
70
71    {"S::static_method()"		"S_SM"		{= \\{void \\(void\\)\\} $hex <S::static_method\\(\\)>}
72							"void"}
73
74    {"S::static_method(void)"		"S_SM"		{= \\{void \\(void\\)\\} $hex <S::static_method\\(\\)>}}
75
76    {"S::inline_method()"		"S_IM"		{= \\{void \\(S \\* const\\)\\} $hex <S::inline_method\\(\\)>}
77							{[cannot_resolve "S::inline_method"]}}
78
79    {"S::inline_method(void)"		"S_IM"		{= \\{void \\(S \\* const\\)\\} $hex <S::inline_method\\(\\)>}}
80
81    {"S::static_inline_method()"	"S_SIM"		{= \\{void \\(void\\)\\} $hex <S::static_inline_method\\(\\)>}
82							"void"}
83
84    {"S::static_inline_method(void)"	"S_SIM"		{= \\{void \\(void\\)\\} $hex <S::static_inline_method\\(\\)>}}
85
86    {"S2<int>::method()"		"S2_M"		{= \\{void \\(S2<int> \\* const\\)\\} $hex <S2<int>::method\\(\\)>}
87							{[cannot_resolve "S2<int>::method"]}}
88
89    {"S2<int>::static_method()"		"S2_SM"		{= \\{void \\(void\\)\\} $hex <S2<int>::static_method\\(\\)>}
90							"void"}
91
92    {"S2<int>::inline_method()"		"S2_IM"		{= \\{void \\(S2<int> \\* const\\)\\} $hex <S2<int>::inline_method\\(\\)>}
93							{[cannot_resolve "S2<int>::inline_method"]}}
94
95    {"S2<int>::static_inline_method()"	"S2_SIM"	{= \\{void \\(void\\)\\} $hex <S2<int>::static_inline_method\\(\\)>}
96							"void"}
97
98    {"free_func"			"FF"		{= \\{void \\(void\\)\\} $hex <free_func\\(\\)>}}
99
100    {"free_func()"			"FF"		{= \\{void \\(void\\)\\} $hex <free_func\\(\\)>}
101							"void"}
102
103    {"free_func(void)"			"FF"		{= \\{void \\(void\\)\\} $hex <free_func\\(\\)>}}
104
105    {"free_inline_func()"		"FIF"		{= \\{void \\(void\\)\\} $hex <free_inline_func\\(\\)>}
106							"void"}
107
108    {"free_inline_func(void)"		"FIF"		{= \\{void \\(void\\)\\} $hex <free_inline_func\\(\\)>}}
109}
110
111set c_scopes_list {
112    {"free_func"			"FF"		{= \\{void \\(void\\)\\} $hex <free_func>}}
113    {"free_inline_func"			"FIF"		{= \\{void \\(void\\)\\} $hex <free_inline_func>}}
114}
115
116# A list of all the static varibles defined in each scope.  The first
117# column is the name of the variable, without the prefix, and the
118# second column is a regex matching what printing the variable should
119# output.
120
121     #VAR		#PRINT
122set vars_list {
123    {"s_var_int"	" = 4"}
124    {"s_var_float"	" = 3.14.*"}
125    {"s_var_aggregate"	" = \\{i1 = 1, i2 = 2, i3 = 3\\}"}
126}
127
128proc do_test {lang} {
129    global c_scopes_list
130    global cxx_scopes_list
131    global vars_list
132    global srcfile testfile
133    global gdb_prompt
134
135    set options {debug}
136
137    if {$lang == "c++"} {
138	if { [skip_cplus_tests] } {
139	    return
140	}
141	lappend options $lang
142	set src ${srcfile}c
143    } else {
144	set src ${srcfile}
145    }
146
147    if {[prepare_for_testing "failed to prepare" $testfile-$lang \
148	     [list $src] $options]} {
149	return -1
150    }
151
152    if {![runto_main]} {
153	return
154    }
155
156    gdb_test "show language" " currently [string_to_regexp $lang]\"\\."
157
158    if {$lang == "c"} {
159	set scopes_list $c_scopes_list
160    } else {
161	set scopes_list $cxx_scopes_list
162    }
163
164    # Print each scope/function using these syntaxes:
165    #
166    #  "(gdb) p 'S::method() const'"    # quoted
167    #  "(gdb) p S::method() const"      # unquoted
168    #
169    foreach scope_line $scopes_list  {
170	set scope [lindex $scope_line 0]
171
172	set print_quoted_re [lindex $scope_line 2]
173	set print_quoted_re [uplevel 1 "subst -nobackslashes -nocommands \"$print_quoted_re\""]
174
175	set print_unquoted_re [lindex $scope_line 3]
176	set print_unquoted_re [uplevel 1 "subst -nobackslashes -nocommands \"$print_unquoted_re\""]
177
178	gdb_test "print '${scope}'" $print_quoted_re
179
180	if {$print_unquoted_re != ""} {
181	    gdb_test "print ${scope}" $print_unquoted_re
182	} else {
183	    gdb_test "print ${scope}" $print_quoted_re
184	}
185    }
186
187    # Print each variable using these syntaxes:
188    #
189    #  'func()'::var
190    #  func()::var
191    #  'func()::var'
192    #
193    # In C++, the latter case makes sure that symbol lookup finds the
194    # debug symbol instead of the minimal symbol with that exact same
195    # name.
196
197    foreach scope_line $scopes_list  {
198	set scope [lindex $scope_line 0]
199	set var_prefix [lindex $scope_line 1]
200	foreach var_line $vars_list {
201	    set var [lindex $var_line 0]
202	    set print_re [lindex $var_line 1]
203
204	    # The gcc PR debug/55541 has the effect that local statics are
205	    # wrapped in a DW_TAG_lexical_block, making them unaddressable from
206	    # outside the function.  XFAIL the relevant tests.
207	    set test "print '${scope}'::${var_prefix}_${var}"
208	    set xfail_pattern "No symbol \".*\" in specified context."
209	    gdb_test_multiple $test $test {
210		-re "\[\r\n\]*(?:$print_re)\[\r\n\]+$gdb_prompt $" {
211		    pass $test
212		}
213		-re "\[\r\n\]*(?:$xfail_pattern)\[\r\n\]+$gdb_prompt $" {
214		    xfail $test
215		}
216	    }
217	    set test "print ${scope}::${var_prefix}_${var}"
218	    gdb_test_multiple $test $test {
219		-re "\[\r\n\]*(?:$print_re)\[\r\n\]+$gdb_prompt $" {
220		    pass $test
221		}
222		-re "\[\r\n\]*(?:$xfail_pattern)\[\r\n\]+$gdb_prompt $" {
223		    xfail $test
224		}
225	    }
226
227	    set sym "${scope}::${var_prefix}_${var}"
228	    if {$lang == "c++"} {
229		set test "print '${sym}'"
230		set xfail_pattern "No symbol .* in current context."
231		set xfail_pattern2 "has unknown type; cast it to its declared type"
232		gdb_test_multiple $test $test {
233		    -re "\[\r\n\]*(?:$print_re)\[\r\n\]+$gdb_prompt $" {
234			pass $test
235		    }
236		    -re "\[\r\n\]*(?:$xfail_pattern)\[\r\n\]+$gdb_prompt $" {
237			xfail $test
238		    }
239		    -re "\[\r\n\]*(?:$xfail_pattern2)\[\r\n\]+$gdb_prompt $" {
240			xfail $test
241		    }
242		}
243	    } else {
244		gdb_test "print '${sym}'" "No symbol \"$sym\" in current context\\."
245	    }
246	}
247    }
248
249    # Now run to each function, and print its variables using the
250    # localy-visible name.
251    foreach scope_line $scopes_list {
252	set scope [lindex $scope_line 0]
253	set var_prefix [lindex $scope_line 1]
254
255	with_test_prefix "$scope" {
256	    delete_breakpoints
257	    gdb_breakpoint "$scope"
258	    gdb_continue_to_breakpoint "$scope"
259
260	    foreach var_line $vars_list {
261		set var [lindex $var_line 0]
262		set print_re [lindex $var_line 1]
263
264		gdb_test "print ${var_prefix}_${var}" $print_re
265	    }
266	}
267    }
268}
269
270foreach lang {"c" "c++"} {
271    with_test_prefix $lang {
272	do_test $lang
273    }
274}
275