Commit | Line | Data |
---|---|---|
ed3ef339 DE |
1 | # Copyright (C) 2008-2014 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 | # This file is part of the GDB testsuite. | |
17 | # It tests the mechanism exposing values to Guile. | |
18 | ||
19 | load_lib gdb-guile.exp | |
20 | ||
21 | standard_testfile | |
22 | ||
23 | # Build inferior to language specification. | |
24 | # LANG is one of "c" or "c++". | |
25 | proc build_inferior {exefile lang} { | |
26 | global srcdir subdir srcfile testfile hex | |
27 | ||
28 | # Use different names for .o files based on the language. | |
29 | # For Fission, the debug info goes in foo.dwo and we don't want, | |
30 | # for example, a C++ compile to clobber the dwo of a C compile. | |
31 | # ref: http://gcc.gnu.org/wiki/DebugFission | |
32 | switch ${lang} { | |
33 | "c" { set filename ${testfile}.o } | |
34 | "c++" { set filename ${testfile}-cxx.o } | |
35 | } | |
36 | set objfile [standard_output_file $filename] | |
37 | ||
38 | if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${objfile}" object "debug $lang"] != "" | |
39 | || [gdb_compile "${objfile}" "${exefile}" executable "debug $lang"] != "" } { | |
40 | untested "Couldn't compile ${srcfile} in $lang mode" | |
41 | return -1 | |
42 | } | |
43 | return 0 | |
44 | } | |
45 | ||
46 | proc test_value_in_inferior {} { | |
47 | global gdb_prompt | |
48 | global testfile | |
49 | ||
50 | gdb_breakpoint [gdb_get_line_number "break to inspect struct and union"] | |
51 | ||
52 | gdb_continue_to_breakpoint "break to inspect struct and union" | |
53 | ||
54 | # Just get inferior variable s in the value history, available to guile. | |
55 | gdb_test "print s" "= {a = 3, b = 5}" "" | |
56 | ||
57 | gdb_scm_test_silent_cmd "gu (define s (history-ref 0))" "set s" | |
58 | ||
59 | gdb_test "gu (print (value-field s \"a\"))" \ | |
60 | "= 3" "access element inside struct using string name" | |
61 | ||
7a5a839f LC |
62 | # Append value in the value history. |
63 | gdb_scm_test_silent_cmd "gu (define i (history-append! (make-value 42)))" \ | |
64 | "append 42" | |
65 | ||
66 | gdb_test "gu i" "\[0-9\]+" | |
67 | gdb_test "gu (history-ref i)" "#<gdb:value 42>" | |
68 | gdb_test "p \$" "= 42" | |
69 | ||
350e1a76 DE |
70 | # Verify the recorded history value survives a gc. |
71 | gdb_test_no_output "guile (gc)" | |
72 | gdb_test "p \$\$" "= 42" | |
73 | ||
fb934770 LC |
74 | # Make sure 'history-append!' rejects non-value objects. |
75 | gdb_test "gu (history-append! 123)" \ | |
76 | "ERROR:.* Wrong type argument.*" "history-append! type error" | |
77 | ||
ed3ef339 DE |
78 | # Test dereferencing the argv pointer. |
79 | ||
80 | # Just get inferior variable argv the value history, available to guile. | |
81 | gdb_test "print argv" "= \\(char \\*\\*\\) 0x.*" "" | |
82 | ||
83 | gdb_scm_test_silent_cmd "gu (define argv (history-ref 0))" \ | |
84 | "set argv" | |
85 | gdb_scm_test_silent_cmd "gu (define arg0 (value-dereference argv))" \ | |
86 | "set arg0" | |
87 | ||
88 | # Check that the dereferenced value is sane. | |
89 | if { ! [target_info exists noargs] } { | |
90 | gdb_test "gu (print arg0)" \ | |
91 | "0x.*$testfile\"" "verify dereferenced value" | |
92 | } | |
93 | ||
94 | # Smoke-test value-optimized-out?. | |
95 | gdb_test "gu (print (value-optimized-out? arg0))" \ | |
96 | "= #f" "Test value-optimized-out?" | |
97 | ||
98 | # Test address attribute. | |
99 | gdb_test "gu (print (value-address arg0))" \ | |
100 | "= 0x\[\[:xdigit:\]\]+" "Test address attribute" | |
101 | # Test address attribute is #f in a non-addressable value. | |
102 | gdb_test "gu (print (value-address (make-value 42)))" \ | |
103 | "= #f" "Test address attribute in non-addressable value" | |
104 | ||
105 | # Test displaying a variable that is temporarily at a bad address. | |
106 | # But if we can examine what's at memory address 0, then we'll also be | |
107 | # able to display it without error. Don't run the test in that case. | |
108 | set can_read_0 0 | |
109 | gdb_test_multiple "x 0" "memory at address 0" { | |
110 | -re "0x0:\[ \t\]*Cannot access memory at address 0x0\r\n$gdb_prompt $" { } | |
111 | -re "0x0:\[ \t\]*Error accessing memory address 0x0\r\n$gdb_prompt $" { } | |
112 | -re "\r\n$gdb_prompt $" { | |
113 | set can_read_0 1 | |
114 | } | |
115 | } | |
116 | ||
117 | # Test memory error. | |
118 | set test "parse_and_eval with memory error" | |
119 | if {$can_read_0} { | |
120 | untested $test | |
121 | } else { | |
122 | gdb_test "gu (print (parse-and-eval \"*(int*)0\"))" \ | |
123 | "ERROR: Cannot access memory at address 0x0.*" $test | |
124 | } | |
125 | ||
126 | # Test Guile lazy value handling | |
127 | set test "memory error and lazy values" | |
128 | if {$can_read_0} { | |
129 | untested $test | |
130 | } else { | |
131 | gdb_test_no_output "gu (define inval (parse-and-eval \"*(int*)0\"))" | |
132 | gdb_test "gu (print (value-lazy? inval))" \ | |
133 | "#t" | |
134 | gdb_test "gu (define inval2 (value-add inval 1))" \ | |
135 | "ERROR: Cannot access memory at address 0x0.*" $test | |
136 | gdb_test "gu (value-fetch-lazy! inval))" \ | |
137 | "ERROR: Cannot access memory at address 0x0.*" $test | |
138 | } | |
139 | gdb_test_no_output "gu (define argc-lazy (parse-and-eval \"argc\"))" | |
140 | gdb_test_no_output "gu (define argc-notlazy (parse-and-eval \"argc\"))" | |
141 | gdb_test_no_output "gu (value-fetch-lazy! argc-notlazy)" | |
142 | gdb_test "gu (print (value-lazy? argc-lazy))" "= #t" | |
143 | gdb_test "gu (print (value-lazy? argc-notlazy))" "= #f" | |
144 | gdb_test "print argc" "= 1" "sanity check argc" | |
145 | gdb_test "gu (print (value-lazy? argc-lazy))" "= #t" | |
146 | gdb_test_no_output "set argc=2" | |
147 | gdb_test "gu (print argc-notlazy)" "= 1" | |
148 | gdb_test "gu (print argc-lazy)" "= 2" | |
149 | gdb_test "gu (print (value-lazy? argc-lazy))" "= #f" | |
150 | ||
151 | # Test string fetches, both partial and whole. | |
152 | gdb_test "print st" "\"divide et impera\"" | |
153 | gdb_scm_test_silent_cmd "gu (define st (history-ref 0))" \ | |
154 | "inf: get st value from history" | |
155 | gdb_test "gu (print (value->string st))" \ | |
156 | "= divide et impera" "Test string with no length" | |
157 | gdb_test "gu (print (value->string st #:length -1))" \ | |
158 | "= divide et impera" "Test string (length = -1) is all of the string" | |
159 | gdb_test "gu (print (value->string st #:length 6))" \ | |
160 | "= divide" | |
161 | gdb_test "gu (print (string-append \"---\" (value->string st #:length 0) \"---\"))" \ | |
162 | "= ------" "Test string (length = 0) is empty" | |
163 | gdb_test "gu (print (string-length (value->string st #:length 0)))" \ | |
164 | "= 0" "Test length is 0" | |
165 | ||
166 | # Fetch a string that has embedded nulls. | |
167 | gdb_test "print nullst" "\"divide\\\\000et\\\\000impera\".*" | |
168 | gdb_scm_test_silent_cmd "gu (define nullst (history-ref 0))" \ | |
169 | "inf: get nullst value from history" | |
170 | gdb_test "gu (print (value->string nullst))" \ | |
171 | "divide" "Test string to first null" | |
172 | gdb_scm_test_silent_cmd "gu (set! nullst (value->string nullst #:length 9))" \ | |
173 | "get string beyond null" | |
174 | gdb_test "gu (print nullst)" \ | |
175 | "= divide\\\\000et" | |
176 | } | |
177 | ||
178 | proc test_strings {} { | |
179 | gdb_test "gu (make-value \"test\")" "#<gdb:value \"test\">" "make string" | |
180 | ||
181 | # Test string conversion errors. | |
182 | set save_charset [get_target_charset] | |
183 | gdb_test_no_output "set target-charset UTF-8" | |
184 | ||
185 | gdb_test_no_output "gu (set-port-conversion-strategy! #f 'error)" | |
186 | gdb_test "gu (print (value->string (make-value (string #\\x1234)) #:encoding \"ASCII\"))" \ | |
187 | "ERROR.*decoding-error.*" \ | |
188 | "value->string with default #:errors = 'error" | |
189 | ||
190 | # There is no 'escape strategy for C->SCM string conversions, but it's | |
191 | # still a legitimate value for %default-port-conversion-strategy. | |
192 | # GDB handles this by, umm, substituting 'substitute. | |
193 | # Use this case to also handle "#:errors #f" which explicitly says | |
194 | # "use %default-port-conversion-strategy". | |
195 | gdb_test_no_output "gu (set-port-conversion-strategy! #f 'escape)" | |
196 | gdb_test "gu (print (value->string (make-value (string #\\x1234)) #:encoding \"ASCII\" #:errors #f))" \ | |
197 | "= \[?\]{3}" "value->string with default #:errors = 'escape" | |
198 | ||
199 | # This is last in the default conversion tests so that | |
200 | # %default-port-conversion-strategy ends up with the default value. | |
201 | gdb_test_no_output "gu (set-port-conversion-strategy! #f 'substitute)" | |
202 | gdb_test "gu (print (value->string (make-value (string #\\x1234)) #:encoding \"ASCII\"))" \ | |
203 | "= \[?\]{3}" "value->string with default #:errors = 'substitute" | |
204 | ||
205 | gdb_test "gu (print (value->string (make-value (string #\\x1234)) #:encoding \"ASCII\" #:errors 'error))" \ | |
206 | "ERROR.*decoding-error.*" "value->string #:errors 'error" | |
207 | gdb_test "gu (print (value->string (make-value (string #\\x1234)) #:encoding \"ASCII\" #:errors 'substitute))" \ | |
208 | "= \[?\]{3}" "value->string #:errors 'substitute" | |
209 | gdb_test "gu (print (value->string (make-value \"abc\") #:errors \"foo\"))" \ | |
210 | "ERROR.*invalid error kind.*" "bad value for #:errors" | |
211 | ||
212 | gdb_test_no_output "set target-charset $save_charset" \ | |
213 | "restore target-charset" | |
214 | } | |
215 | ||
216 | proc test_lazy_strings {} { | |
217 | global hex | |
218 | ||
219 | gdb_test "print sptr" "\"pointer\"" | |
220 | gdb_scm_test_silent_cmd "gu (define sptr (history-ref 0))" \ | |
221 | "lazy strings: get sptr value from history" | |
222 | ||
223 | gdb_scm_test_silent_cmd "gu (define lstr (value->lazy-string sptr))" \ | |
224 | "Aquire lazy string" | |
225 | gdb_test "gu (print (lazy-string-type lstr))" \ | |
226 | "= const char \*." "Test lazy-string type name equality" | |
227 | gdb_test "gu (print (value-type sptr))" \ | |
228 | "= const char \*." "Test string type name equality" | |
229 | gdb_test "print sn" "0x0" | |
230 | gdb_scm_test_silent_cmd "gu (define snptr (history-ref 0))" \ | |
231 | "lazy strings: get snptr value from history" | |
232 | gdb_test "gu (define snstr (value->lazy-string snptr #:length 5))" \ | |
233 | ".*cannot create a lazy string with address.*" "Test lazy string" | |
234 | gdb_scm_test_silent_cmd "gu (define snstr (value->lazy-string snptr #:length 0))" \ | |
235 | "Successfully create a lazy string" | |
236 | gdb_test "gu (print (lazy-string-length snstr))" \ | |
237 | "= 0" "Test lazy string length" | |
238 | gdb_test "gu (print (lazy-string-address snstr))" \ | |
239 | "= 0" "Test lazy string address" | |
240 | } | |
241 | ||
242 | proc test_inferior_function_call {} { | |
243 | global gdb_prompt hex decimal | |
244 | ||
245 | # Correct inferior call without arguments. | |
246 | gdb_test "p/x fp1" "= $hex.*" | |
247 | gdb_scm_test_silent_cmd "gu (define fp1 (history-ref 0))" \ | |
248 | "get fp1 value from history" | |
249 | gdb_scm_test_silent_cmd "gu (set! fp1 (value-dereference fp1))" \ | |
250 | "dereference fp1" | |
251 | gdb_test "gu (print (value-call fp1 '()))" \ | |
252 | "= void" | |
253 | ||
254 | # Correct inferior call with arguments. | |
255 | gdb_test "p/x fp2" "= $hex.*" | |
256 | gdb_scm_test_silent_cmd "gu (define fp2 (history-ref 0))" \ | |
257 | "get fp2 value from history" | |
258 | gdb_scm_test_silent_cmd "gu (set! fp2 (value-dereference fp2))" \ | |
259 | "dereference fp2" | |
260 | gdb_test "gu (print (value-call fp2 (list 10 20)))" \ | |
261 | "= 30" | |
262 | ||
263 | # Incorrect to call an int value. | |
264 | gdb_test "p i" "= $decimal.*" | |
265 | gdb_scm_test_silent_cmd "gu (define i (history-ref 0))" \ | |
266 | "inf call: get i value from history" | |
267 | gdb_test "gu (print (value-call i '()))" \ | |
268 | "ERROR: .*: Wrong type argument in position 1 \\(expecting function \\(value of TYPE_CODE_FUNC\\)\\): .*" | |
269 | ||
270 | # Incorrect number of arguments. | |
271 | gdb_test "p/x fp2" "= $hex.*" | |
272 | gdb_scm_test_silent_cmd "gu (define fp3 (history-ref 0))" \ | |
273 | "get fp3 value from history" | |
274 | gdb_scm_test_silent_cmd "gu (set! fp3 (value-dereference fp3))" \ | |
275 | "dereference fp3" | |
276 | gdb_test "gu (print (value-call fp3 (list 10)))" \ | |
277 | "ERROR: Too few arguments in function call.*" | |
278 | } | |
279 | ||
280 | proc test_value_after_death {} { | |
281 | # Construct a type while the inferior is still running. | |
282 | gdb_scm_test_silent_cmd "gu (define ptrtype (lookup-type \"PTR\"))" \ | |
283 | "create PTR type" | |
284 | ||
285 | # Kill the inferior and remove the symbols. | |
286 | gdb_test "kill" "" "kill the inferior" \ | |
287 | "Kill the program being debugged. .y or n. $" \ | |
288 | "y" | |
289 | gdb_test "file" "" "Discard the symbols" \ | |
290 | "Discard symbol table from.*y or n. $" \ | |
291 | "y" | |
292 | ||
5a1e8c7a DE |
293 | # First do a garbage collect to delete anything unused. PR 16612. |
294 | gdb_scm_test_silent_cmd "gu (gc)" "garbage collect" | |
295 | ||
ed3ef339 DE |
296 | # Now create a value using that type. Relies on arg0, created by |
297 | # test_value_in_inferior. | |
298 | gdb_scm_test_silent_cmd "gu (define castval (value-cast arg0 (type-pointer ptrtype)))" \ | |
299 | "cast arg0 to PTR" | |
300 | ||
301 | # Make sure the type is deleted. | |
302 | gdb_scm_test_silent_cmd "gu (set! ptrtype #f)" \ | |
303 | "delete PTR type" | |
304 | ||
305 | # Now see if the value's type is still valid. | |
306 | gdb_test "gu (print (value-type castval))" \ | |
307 | "= PTR ." "print value's type" | |
308 | } | |
309 | ||
310 | # Regression test for invalid subscript operations. The bug was that | |
311 | # the type of the value was not being checked before allowing a | |
312 | # subscript operation to proceed. | |
313 | ||
314 | proc test_subscript_regression {exefile lang} { | |
315 | # Start with a fresh gdb. | |
316 | clean_restart ${exefile} | |
317 | ||
318 | if ![gdb_guile_runto_main ] { | |
319 | fail "Can't run to main" | |
320 | return | |
321 | } | |
322 | ||
323 | if {$lang == "c++"} { | |
324 | gdb_breakpoint [gdb_get_line_number "break to inspect pointer by reference"] | |
325 | gdb_continue_to_breakpoint "break to inspect pointer by reference" | |
326 | ||
327 | gdb_scm_test_silent_cmd "print rptr_int" \ | |
328 | "Obtain address" | |
329 | gdb_scm_test_silent_cmd "gu (define rptr (history-ref 0))" \ | |
330 | "set rptr" | |
331 | gdb_test "gu (print (value-subscript rptr 0))" \ | |
332 | "= 2" "Check pointer passed as reference" | |
333 | ||
334 | # Just the most basic test of dynamic_cast -- it is checked in | |
335 | # the C++ tests. | |
336 | gdb_test "gu (print (value->bool (value-dynamic-cast (parse-and-eval \"base\") (type-pointer (lookup-type \"Derived\")))))" \ | |
337 | "= #t" | |
338 | ||
339 | # Likewise. | |
340 | gdb_test "gu (print (value-dynamic-type (parse-and-eval \"base\")))" \ | |
341 | "= Derived \[*\]" | |
0be03e84 DE |
342 | gdb_test "gu (print (value-dynamic-type (parse-and-eval \"base_ref\")))" \ |
343 | "= Derived \[&\]" | |
ed3ef339 DE |
344 | # A static type case. |
345 | gdb_test "gu (print (value-dynamic-type (parse-and-eval \"5\")))" \ | |
346 | "= int" | |
347 | } | |
348 | ||
349 | gdb_breakpoint [gdb_get_line_number "break to inspect struct and union"] | |
350 | gdb_continue_to_breakpoint "break to inspect struct and union" | |
351 | ||
352 | gdb_scm_test_silent_cmd "gu (define intv (make-value 1))" \ | |
353 | "Create int value for subscript test" | |
354 | gdb_scm_test_silent_cmd "gu (define stringv (make-value \"foo\"))" \ | |
355 | "Create string value for subscript test" | |
356 | ||
357 | # Try to access an int with a subscript. This should fail. | |
358 | gdb_test "gu (print intv)" \ | |
359 | "= 1" "Baseline print of an int Guile value" | |
360 | gdb_test "gu (print (value-subscript intv 0))" \ | |
361 | "ERROR: Cannot subscript requested type.*" \ | |
362 | "Attempt to access an integer with a subscript" | |
363 | ||
364 | # Try to access a string with a subscript. This should pass. | |
365 | gdb_test "gu (print stringv)" \ | |
366 | "= \"foo\"" "Baseline print of a string Guile value" | |
367 | gdb_test "gu (print (value-subscript stringv 0))" \ | |
368 | "= 102 'f'" "Attempt to access a string with a subscript" | |
369 | ||
370 | # Try to access an int array via a pointer with a subscript. | |
371 | # This should pass. | |
372 | gdb_scm_test_silent_cmd "print p" "Build pointer to array" | |
373 | gdb_scm_test_silent_cmd "gu (define pointer (history-ref 0))" "set pointer" | |
374 | gdb_test "gu (print (value-subscript pointer 0))" \ | |
375 | "= 1" "Access array via pointer with int subscript" | |
376 | gdb_test "gu (print (value-subscript pointer intv))" \ | |
377 | "= 2" "Access array via pointer with value subscript" | |
378 | ||
379 | # Try to access a single dimension array with a subscript to the | |
380 | # result. This should fail. | |
381 | gdb_test "gu (print (value-subscript (value-subscript pointer intv) 0))" \ | |
382 | "ERROR: Cannot subscript requested type.*" \ | |
383 | "Attempt to access an integer with a subscript 2" | |
384 | ||
385 | # Lastly, test subscript access to an array with multiple | |
386 | # dimensions. This should pass. | |
387 | gdb_scm_test_silent_cmd "print {\"fu \",\"foo\",\"bar\"}" "Build array" | |
388 | gdb_scm_test_silent_cmd "gu (define marray (history-ref 0))" "" | |
389 | gdb_test "gu (print (value-subscript (value-subscript marray 1) 2))" \ | |
390 | "o." "Test multiple subscript" | |
391 | } | |
392 | ||
393 | # A few tests of gdb:parse-and-eval. | |
394 | ||
395 | proc test_parse_and_eval {} { | |
396 | gdb_test "gu (print (parse-and-eval \"23\"))" \ | |
397 | "= 23" "parse-and-eval constant test" | |
398 | gdb_test "gu (print (parse-and-eval \"5 + 7\"))" \ | |
399 | "= 12" "parse-and-eval simple expression test" | |
400 | gdb_test "gu (raw-print (parse-and-eval \"5 + 7\"))" \ | |
401 | "#<gdb:value 12>" "parse-and-eval type test" | |
402 | } | |
403 | ||
404 | # Test that values are hashable. | |
405 | # N.B.: While smobs are hashable, the hash is really non-existent, | |
406 | # they all get hashed to the same value. Guile may provide a hash function | |
407 | # for smobs in a future release. In the meantime one should use a custom | |
408 | # hash table that uses gdb:hash-gsmob. | |
409 | ||
410 | proc test_value_hash {} { | |
411 | gdb_test_multiline "Simple Guile value dictionary" \ | |
412 | "guile" "" \ | |
413 | "(define one (make-value 1))" "" \ | |
414 | "(define two (make-value 2))" "" \ | |
415 | "(define three (make-value 3))" "" \ | |
416 | "(define vdict (make-hash-table 5))" "" \ | |
417 | "(hash-set! vdict one \"one str\")" "" \ | |
418 | "(hash-set! vdict two \"two str\")" "" \ | |
419 | "(hash-set! vdict three \"three str\")" "" \ | |
420 | "end" | |
421 | gdb_test "gu (print (hash-ref vdict one))" \ | |
422 | "one str" "Test dictionary hash 1" | |
423 | gdb_test "gu (print (hash-ref vdict two))" \ | |
424 | "two str" "Test dictionary hash 2" | |
425 | gdb_test "gu (print (hash-ref vdict three))" \ | |
426 | "three str" "Test dictionary hash 3" | |
427 | } | |
428 | ||
429 | # Build C version of executable. C++ is built later. | |
430 | if { [build_inferior "${binfile}" "c"] < 0 } { | |
431 | return | |
432 | } | |
433 | ||
434 | # Start with a fresh gdb. | |
435 | clean_restart ${binfile} | |
436 | ||
437 | # Skip all tests if Guile scripting is not enabled. | |
438 | if { [skip_guile_tests] } { continue } | |
439 | ||
440 | gdb_install_guile_utils | |
441 | gdb_install_guile_module | |
442 | ||
443 | test_parse_and_eval | |
444 | test_value_hash | |
445 | ||
446 | # The following tests require execution. | |
447 | ||
448 | if ![gdb_guile_runto_main] { | |
449 | fail "Can't run to main" | |
450 | return | |
451 | } | |
452 | ||
453 | test_value_in_inferior | |
454 | test_inferior_function_call | |
455 | test_strings | |
456 | test_lazy_strings | |
457 | test_value_after_death | |
458 | ||
459 | # Test either C or C++ values. | |
460 | ||
461 | test_subscript_regression "${binfile}" "c" | |
462 | ||
463 | if ![skip_cplus_tests] { | |
464 | if { [build_inferior "${binfile}-cxx" "c++"] < 0 } { | |
465 | return | |
466 | } | |
467 | with_test_prefix "c++" { | |
468 | test_subscript_regression "${binfile}-cxx" "c++" | |
469 | } | |
470 | } |