1# Copyright 2013-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# Test namespace aliases.
17# PRs c++/7935, c++/10541
18
19load_lib dwarf.exp
20
21if {![dwarf2_support]} {
22    return 0
23}
24
25if {[skip_cplus_tests]} {
26    return
27}
28
29standard_testfile .cc nsalias-dw.S
30
31# Make the DWARF used for the test.  This is necessary to work
32# around compiler issues.  Not all versions of gcc output the
33# correct debuginfo we need.
34#
35# This should create the equivalent DWARF to:
36#
37# namespace outer
38# {
39#   namespace inner
40#   {
41#     namespace innermost
42#     {
43#       const int x = 2;
44#       int foo (void) { return x; }
45#     }
46#
47#     namespace Innermost = innermost;
48#
49#     const int x = 1;
50#     int foo (void) { return x + Innermost::foo (); }
51#   }
52#
53#   namespace Inner = inner;
54#
55#   const int x = 0;
56#   int foo (void) { return x + Inner::foo (); }
57# }
58#
59# namespace Outer = outer;
60# namespace oi = Outer::Inner;
61
62set asm_file [standard_output_file $srcfile2]
63Dwarf::assemble $asm_file {
64    cu {} {
65	compile_unit {{language @DW_LANG_C_plus_plus}} {
66	    declare_labels int_label outer_label inner_label innermost_label
67	    declare_labels im_foo_label i_foo_label o_foo_label
68	    declare_labels OuterInner_label oi1_label oi2_label
69
70	    int_label: base_type {
71		{name int}
72		{encoding @DW_ATE_signed}
73		{byte_size 4 DW_FORM_sdata}
74	    }
75
76	    outer_label: DW_TAG_namespace {
77		{name outer}
78	    } {
79		inner_label: DW_TAG_namespace {
80		    {name inner}
81		} {
82		    innermost_label: DW_TAG_namespace {
83			{name innermost}
84		    } {
85			DW_TAG_variable {
86			    {name x}
87			    {type :$int_label}
88			    {const_value 2 DW_FORM_data1}
89			}
90
91			im_foo_label: DW_TAG_subprogram {
92			    {name foo}
93			    {external 1 flag_present}
94			    {declaration 1 flag_present}
95			}
96		    }
97
98		    imported_declaration {
99			{name Innermost}
100			{import :$innermost_label}
101		    }
102
103		    DW_TAG_variable {
104			{name x}
105			{type :$int_label}
106			{const_value 1 DW_FORM_data1}
107		    }
108
109		    i_foo_label: subprogram {
110			{name foo}
111			{external 1 flag_present}
112			{declaration 1 flag_present}
113		    }
114		}
115
116		OuterInner_label: imported_declaration {
117		    {name Inner}
118		    {import :$inner_label}
119		}
120
121		DW_TAG_variable {
122		    {name x}
123		    {type :$int_label}
124		    {const_value 0 DW_FORM_data1}
125		}
126
127		o_foo_label: subprogram {
128		    {name foo}
129		    {external 1 flag_present}
130		    {declaration 1 flag_present}
131		}
132	    }
133
134	    imported_declaration {
135		{name Outer}
136		{import :$outer_label}
137	    }
138
139	    oi1_label: imported_declaration {
140		{name oi1}
141		{import :$OuterInner_label}
142	    }
143
144	    oi2_label: imported_declaration {
145		{name oi2}
146		{import :$oi1_label}
147	    }
148
149	    imported_declaration {
150		{name oi3}
151		{import :$oi2_label}
152	    }
153
154	    subprogram {
155		{specification :$im_foo_label}
156		{low_pc 0x4 DW_FORM_addr}
157		{high_pc 0x7 DW_FORM_addr}
158	    }
159
160	    subprogram {
161		{specification :$i_foo_label}
162		{low_pc 0x8 DW_FORM_addr}
163		{high_pc 0xb DW_FORM_addr}
164	    }
165
166	    subprogram {
167		{specification :$o_foo_label}
168		{low_pc 0xc DW_FORM_addr}
169		{high_pc 0xf DW_FORM_addr}
170	    }
171	}
172    }
173}
174
175if {[gdb_compile $srcdir/$subdir/$srcfile ${binfile}1.o \
176	 object {c++ debug}] != ""} {
177    return -1
178}
179
180if {[gdb_compile $asm_file ${binfile}2.o object {nodebug}] != ""} {
181    return -1
182}
183
184if {[gdb_compile [list ${binfile}1.o ${binfile}2.o] \
185	 $binfile executable {c++}] != ""} {
186    return -1
187}
188
189clean_restart $testfile
190
191# A procedure to run various tests on aliased namespaces.
192proc do_alias_tests {ns {real ""} {x ""}} {
193
194    # The "real" namespace is simply NS in all lowercase.
195    if {$real == ""} {
196	set real [string tolower $ns]
197    }
198
199    # The value of `x' is the number of '::' in NS.
200    if {$x == ""} {
201	set x [expr {[llength [split $ns ":"]] / 2}]
202    }
203
204    # Test "whatis"
205    gdb_test "whatis $ns" "type = $real"
206
207    # Test "ptype"
208    gdb_test "ptype $ns" "type = namespace $real"
209
210    # Print 'x'
211    send_log "expecting x = $x\n"
212    gdb_test "print ${ns}::x" " = $x"
213
214    # Attempt to list the function.
215    gdb_test_no_output "list ${ns}::foo"
216
217    # Attempt to break on the start of the function.
218    gdb_breakpoint "*${ns}::foo"
219
220    # And then erase it
221    with_test_prefix "($ns)" {
222	gdb_test_no_output "delete \$bpnum"
223    }
224}
225
226# This is a list of all the permutations to be tested.  For troubleshooting
227# purposes, this list is explicitly enumerated.
228
229set permutations {}
230lappend permutations "outer"
231lappend permutations "Outer"
232lappend permutations "outer::inner"
233lappend permutations "Outer::inner"
234lappend permutations "outer::Inner"
235lappend permutations "Outer::Inner"
236lappend permutations "outer::inner::innermost"
237lappend permutations "outer::inner::Innermost"
238lappend permutations "outer::Inner::innermost"
239lappend permutations "outer::Inner::Innermost"
240lappend permutations "Outer::inner::innermost"
241lappend permutations "Outer::inner::Innermost"
242lappend permutations "Outer::Inner::innermost"
243lappend permutations "Outer::Inner::Innermost"
244
245foreach p $permutations {
246    do_alias_tests $p
247}
248
249# Test recursively imported aliases.
250foreach ns {"oi1" "oi2" "oi3"} {
251    do_alias_tests $ns "outer::inner" 1
252    do_alias_tests "${ns}::innermost" "outer::inner::innermost" 2
253    do_alias_tests "${ns}::Innermost" "outer::inner::innermost" 2
254}
255
256# Generate another objfile with nested imported declarations.
257
258set imports {
259    declare_labels n0_label
260
261    n0_label: DW_TAG_namespace {
262	{name n0}
263    } {
264	DW_TAG_variable {
265	    {name x}
266	    {type :$int_label}
267	    {const_value 3 DW_FORM_data1}
268	}
269    }
270
271    declare_labels n0_import
272    n0_import: imported_declaration {
273	{name N0}
274	{import :$n0_label}
275    }
276}
277
278for {set i 1} {$i <= 100} {incr i} {
279    append imports [format "
280	declare_labels n%d_import
281	n%d_import: imported_declaration {
282	    {name N%d}
283	    {import :\$n%d_import}
284	}" $i $i $i [expr {$i - 1}]]
285}
286
287standard_testfile .cc nsalias-r-dw.S
288
289set asm_file [standard_output_file $srcfile2]
290set the_dwarf [format {
291    cu {} {
292	compile_unit {{language @DW_LANG_C_plus_plus}} {
293	    declare_labels int_label n0_label
294
295	    int_label: base_type {
296		{name int}
297		{encoding @DW_ATE_signed}
298		{byte_size 4 DW_FORM_sdata}
299	    }
300
301%s
302	}
303    }
304} $imports]
305
306Dwarf::assemble $asm_file $the_dwarf
307
308if {[gdb_compile $asm_file ${binfile}3.o object {nodebug}] != ""} {
309    return -1
310}
311
312if {[gdb_compile [list ${binfile}1.o ${binfile}3.o] \
313	 ${binfile}-r executable {c++}] != ""} {
314    return -1
315}
316
317clean_restart
318
319# Set complaints before loading the file.  Otherwise the complaint won't
320# trigger for -readnow.
321gdb_test_no_output "set complaints 1"
322
323gdb_load [standard_output_file ${testfile}-r]
324
325set readnow_p [readnow]
326
327set test "complaint for too many recursively imported declarations"
328set re ".* has too many recursively imported declarations.*"
329if { $readnow_p } {
330    global gdb_file_cmd_msg
331    gdb_assert {[regexp $re $gdb_file_cmd_msg]} $test
332} else {
333    gdb_test "print N100::x" $re $test
334}
335