blob: 59be1863fc3917a7e29d811839a0296ebc73ee26 [file] [log] [blame]
Cherry Zhanga9c244a2021-04-17 00:46:53 -04001// errorcheckwithauto -0 -l -live -wb=0 -d=ssa/insert_resched_checks/off
Matthew Dempskyf7513192022-06-29 17:15:08 -07002//go:build (amd64 && goexperiment.regabiargs) || (arm64 && goexperiment.regabiargs)
Cuong Manh Lef67e31d2021-08-19 21:02:49 +07003// +build amd64,goexperiment.regabiargs arm64,goexperiment.regabiargs
Cherry Zhanga9c244a2021-04-17 00:46:53 -04004
5// Copyright 2014 The Go Authors. All rights reserved.
6// Use of this source code is governed by a BSD-style
7// license that can be found in the LICENSE file.
8
9// liveness tests with inlining disabled.
10// see also live2.go.
11
12package main
13
14func printnl()
15
16//go:noescape
17func printpointer(**int)
18
19//go:noescape
20func printintpointer(*int)
21
22//go:noescape
23func printstringpointer(*string)
24
25//go:noescape
26func printstring(string)
27
28//go:noescape
29func printbytepointer(*byte)
30
31func printint(int)
32
33func f1() {
34 var x *int // ERROR "stack object x \*int$"
35 printpointer(&x) // ERROR "live at call to printpointer: x$"
36 printpointer(&x)
37}
38
39func f2(b bool) {
40 if b {
41 printint(0) // nothing live here
42 return
43 }
44 var x *int // ERROR "stack object x \*int$"
45 printpointer(&x) // ERROR "live at call to printpointer: x$"
46 printpointer(&x)
47}
48
49func f3(b1, b2 bool) {
50 // Here x and y are ambiguously live. In previous go versions they
51 // were marked as live throughout the function to avoid being
52 // poisoned in GODEBUG=gcdead=1 mode; this is now no longer the
53 // case.
54
55 printint(0)
56 if b1 == false {
57 printint(0)
58 return
59 }
60
61 if b2 {
62 var x *int // ERROR "stack object x \*int$"
63 printpointer(&x) // ERROR "live at call to printpointer: x$"
64 printpointer(&x)
65 } else {
66 var y *int // ERROR "stack object y \*int$"
67 printpointer(&y) // ERROR "live at call to printpointer: y$"
68 printpointer(&y)
69 }
70 printint(0) // nothing is live here
71}
72
73// The old algorithm treated x as live on all code that
74// could flow to a return statement, so it included the
75// function entry and code above the declaration of x
76// but would not include an indirect use of x in an infinite loop.
77// Check that these cases are handled correctly.
78
79func f4(b1, b2 bool) { // x not live here
80 if b2 {
81 printint(0) // x not live here
82 return
83 }
84 var z **int
85 x := new(int) // ERROR "stack object x \*int$"
86 *x = 42
87 z = &x
88 printint(**z) // ERROR "live at call to printint: x$"
89 if b2 {
90 printint(1) // x not live here
91 return
92 }
93 for {
94 printint(**z) // ERROR "live at call to printint: x$"
95 }
96}
97
98func f5(b1 bool) {
99 var z **int
100 if b1 {
101 x := new(int) // ERROR "stack object x \*int$"
102 *x = 42
103 z = &x
104 } else {
105 y := new(int) // ERROR "stack object y \*int$"
106 *y = 54
107 z = &y
108 }
109 printint(**z) // nothing live here
110}
111
112// confusion about the _ result used to cause spurious "live at entry to f6: _".
113
114func f6() (_, y string) {
115 y = "hello"
116 return
117}
118
119// confusion about addressed results used to cause "live at entry to f7: x".
120
121func f7() (x string) { // ERROR "stack object x string"
122 _ = &x
123 x = "hello"
124 return
125}
126
127// ignoring block returns used to cause "live at entry to f8: x, y".
128
129func f8() (x, y string) {
130 return g8()
131}
132
133func g8() (string, string)
134
135// ignoring block assignments used to cause "live at entry to f9: x"
136// issue 7205
137
138var i9 interface{}
139
140func f9() bool {
141 g8()
142 x := i9
Keith Randall57668b82021-08-04 22:18:23 -0700143 y := interface{}(g18()) // ERROR "live at call to convT: x.data$" "live at call to g18: x.data$" "stack object .autotmp_[0-9]+ \[2\]string$"
144 i9 = y // make y escape so the line above has to call convT
Cherry Zhanga9c244a2021-04-17 00:46:53 -0400145 return x != y
146}
147
148// liveness formerly confused by UNDEF followed by RET,
149// leading to "live at entry to f10: ~r1" (unnamed result).
150
151func f10() string {
152 panic(1)
153}
154
155// liveness formerly confused by select, thinking runtime.selectgo
156// can return to next instruction; it always jumps elsewhere.
157// note that you have to use at least two cases in the select
158// to get a true select; smaller selects compile to optimized helper functions.
159
160var c chan *int
161var b bool
162
163// this used to have a spurious "live at entry to f11a: ~r0"
164func f11a() *int {
165 select { // ERROR "stack object .autotmp_[0-9]+ \[2\]struct"
166 case <-c:
167 return nil
168 case <-c:
169 return nil
170 }
171}
172
173func f11b() *int {
174 p := new(int)
175 if b {
176 // At this point p is dead: the code here cannot
177 // get to the bottom of the function.
178 // This used to have a spurious "live at call to printint: p".
179 printint(1) // nothing live here!
180 select { // ERROR "stack object .autotmp_[0-9]+ \[2\]struct"
181 case <-c:
182 return nil
183 case <-c:
184 return nil
185 }
186 }
187 println(*p)
188 return nil
189}
190
191var sink *int
192
193func f11c() *int {
194 p := new(int)
195 sink = p // prevent stack allocation, otherwise p is rematerializeable
196 if b {
197 // Unlike previous, the cases in this select fall through,
198 // so we can get to the println, so p is not dead.
199 printint(1) // ERROR "live at call to printint: p$"
200 select { // ERROR "live at call to selectgo: p$" "stack object .autotmp_[0-9]+ \[2\]struct"
201 case <-c:
202 case <-c:
203 }
204 }
205 println(*p)
206 return nil
207}
208
209// similarly, select{} does not fall through.
210// this used to have a spurious "live at entry to f12: ~r0".
211
212func f12() *int {
213 if b {
214 select {}
215 } else {
216 return nil
217 }
218}
219
220// incorrectly placed VARDEF annotations can cause missing liveness annotations.
221// this used to be missing the fact that s is live during the call to g13 (because it is
222// needed for the call to h13).
223
224func f13() {
225 s := g14()
226 s = h13(s, g13(s)) // ERROR "live at call to g13: s.ptr$"
227}
228
229func g13(string) string
230func h13(string, string) string
231
232// more incorrectly placed VARDEF.
233
234func f14() {
235 x := g14() // ERROR "stack object x string$"
236 printstringpointer(&x)
237}
238
239func g14() string
240
241// Checking that various temporaries do not persist or cause
242// ambiguously live values that must be zeroed.
243// The exact temporary names are inconsequential but we are
244// trying to check that there is only one at any given site,
245// and also that none show up in "ambiguously live" messages.
246
247var m map[string]int
248var mi map[interface{}]int
249
250// str and iface are used to ensure that a temp is required for runtime calls below.
251func str() string
252func iface() interface{}
253
254func f16() {
255 if b {
256 delete(mi, iface()) // ERROR "stack object .autotmp_[0-9]+ interface \{\}$"
257 }
258 delete(mi, iface())
259 delete(mi, iface())
260}
261
262var m2s map[string]*byte
263var m2 map[[2]string]*byte
264var x2 [2]string
265var bp *byte
266
267func f17a(p *byte) { // ERROR "live at entry to f17a: p$"
268 if b {
269 m2[x2] = p // ERROR "live at call to mapassign: p$"
270 }
271 m2[x2] = p // ERROR "live at call to mapassign: p$"
272 m2[x2] = p // ERROR "live at call to mapassign: p$"
273}
274
275func f17b(p *byte) { // ERROR "live at entry to f17b: p$"
276 // key temporary
277 if b {
278 m2s[str()] = p // ERROR "live at call to mapassign_faststr: p$" "live at call to str: p$"
279 }
280 m2s[str()] = p // ERROR "live at call to mapassign_faststr: p$" "live at call to str: p$"
281 m2s[str()] = p // ERROR "live at call to mapassign_faststr: p$" "live at call to str: p$"
282}
283
284func f17c() {
285 // key and value temporaries
286 if b {
287 m2s[str()] = f17d() // ERROR "live at call to f17d: .autotmp_[0-9]+$" "live at call to mapassign_faststr: .autotmp_[0-9]+$"
288 }
289 m2s[str()] = f17d() // ERROR "live at call to f17d: .autotmp_[0-9]+$" "live at call to mapassign_faststr: .autotmp_[0-9]+$"
290 m2s[str()] = f17d() // ERROR "live at call to f17d: .autotmp_[0-9]+$" "live at call to mapassign_faststr: .autotmp_[0-9]+$"
291}
292
293func f17d() *byte
294
295func g18() [2]string
296
297func f18() {
298 // key temporary for mapaccess.
299 // temporary introduced by orderexpr.
300 var z *byte
301 if b {
302 z = m2[g18()] // ERROR "stack object .autotmp_[0-9]+ \[2\]string$"
303 }
304 z = m2[g18()]
305 z = m2[g18()]
306 printbytepointer(z)
307}
308
309var ch chan *byte
310
311// byteptr is used to ensure that a temp is required for runtime calls below.
312func byteptr() *byte
313
314func f19() {
315 // dest temporary for channel receive.
316 var z *byte
317
318 if b {
319 z = <-ch // ERROR "stack object .autotmp_[0-9]+ \*byte$"
320 }
321 z = <-ch
322 z = <-ch // ERROR "live at call to chanrecv1: .autotmp_[0-9]+$"
323 printbytepointer(z)
324}
325
326func f20() {
327 // src temporary for channel send
328 if b {
329 ch <- byteptr() // ERROR "stack object .autotmp_[0-9]+ \*byte$"
330 }
331 ch <- byteptr()
332 ch <- byteptr()
333}
334
335func f21() {
336 // key temporary for mapaccess using array literal key.
337 var z *byte
338 if b {
339 z = m2[[2]string{"x", "y"}] // ERROR "stack object .autotmp_[0-9]+ \[2\]string$"
340 }
341 z = m2[[2]string{"x", "y"}]
342 z = m2[[2]string{"x", "y"}]
343 printbytepointer(z)
344}
345
346func f23() {
347 // key temporary for two-result map access using array literal key.
348 var z *byte
349 var ok bool
350 if b {
351 z, ok = m2[[2]string{"x", "y"}] // ERROR "stack object .autotmp_[0-9]+ \[2\]string$"
352 }
353 z, ok = m2[[2]string{"x", "y"}]
354 z, ok = m2[[2]string{"x", "y"}]
355 printbytepointer(z)
356 print(ok)
357}
358
359func f24() {
360 // key temporary for map access using array literal key.
361 // value temporary too.
362 if b {
363 m2[[2]string{"x", "y"}] = nil // ERROR "stack object .autotmp_[0-9]+ \[2\]string$"
364 }
365 m2[[2]string{"x", "y"}] = nil
366 m2[[2]string{"x", "y"}] = nil
367}
368
369// Non-open-coded defers should not cause autotmps. (Open-coded defers do create extra autotmps).
370func f25(b bool) {
371 for i := 0; i < 2; i++ {
372 // Put in loop to make sure defer is not open-coded
373 defer g25()
374 }
375 if b {
376 return
377 }
378 var x string
379 x = g14()
380 printstring(x)
381 return
382}
383
384func g25()
385
386// non-escaping ... slices passed to function call should die on return,
387// so that the temporaries do not stack and do not cause ambiguously
388// live variables.
389
390func f26(b bool) {
391 if b {
392 print26((*int)(nil), (*int)(nil), (*int)(nil)) // ERROR "stack object .autotmp_[0-9]+ \[3\]interface \{\}$"
393 }
394 print26((*int)(nil), (*int)(nil), (*int)(nil))
395 print26((*int)(nil), (*int)(nil), (*int)(nil))
396 printnl()
397}
398
399//go:noescape
400func print26(...interface{})
401
402// non-escaping closures passed to function call should die on return
403
404func f27(b bool) {
405 x := 0
406 if b {
407 call27(func() { x++ }) // ERROR "stack object .autotmp_[0-9]+ struct \{"
408 }
409 call27(func() { x++ })
410 call27(func() { x++ })
411 printnl()
412}
413
414// but defer does escape to later execution in the function
415
416func f27defer(b bool) {
417 x := 0
418 if b {
419 defer call27(func() { x++ }) // ERROR "stack object .autotmp_[0-9]+ struct \{"
420 }
421 defer call27(func() { x++ }) // ERROR "stack object .autotmp_[0-9]+ struct \{"
422 printnl() // ERROR "live at call to printnl: .autotmp_[0-9]+ .autotmp_[0-9]+"
423 return // ERROR "live at indirect call: .autotmp_[0-9]+"
424}
425
426// and newproc (go) escapes to the heap
427
428func f27go(b bool) {
429 x := 0
430 if b {
431 go call27(func() { x++ }) // ERROR "live at call to newobject: &x$" "live at call to newobject: &x .autotmp_[0-9]+$" "live at call to newproc: &x$" // allocate two closures, the func literal, and the wrapper for go
432 }
433 go call27(func() { x++ }) // ERROR "live at call to newobject: &x$" "live at call to newobject: .autotmp_[0-9]+$" // allocate two closures, the func literal, and the wrapper for go
434 printnl()
435}
436
437//go:noescape
438func call27(func())
439
440// concatstring slice should die on return
441
442var s1, s2, s3, s4, s5, s6, s7, s8, s9, s10 string
443
444func f28(b bool) {
445 if b {
446 printstring(s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9 + s10) // ERROR "stack object .autotmp_[0-9]+ \[10\]string$"
447 }
448 printstring(s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9 + s10)
449 printstring(s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9 + s10)
450}
451
452// map iterator should die on end of range loop
453
454func f29(b bool) {
455 if b {
456 for k := range m { // ERROR "live at call to mapiterinit: .autotmp_[0-9]+$" "live at call to mapiternext: .autotmp_[0-9]+$" "stack object .autotmp_[0-9]+ map.iter\[string\]int$"
457 printstring(k) // ERROR "live at call to printstring: .autotmp_[0-9]+$"
458 }
459 }
460 for k := range m { // ERROR "live at call to mapiterinit: .autotmp_[0-9]+$" "live at call to mapiternext: .autotmp_[0-9]+$"
461 printstring(k) // ERROR "live at call to printstring: .autotmp_[0-9]+$"
462 }
463 for k := range m { // ERROR "live at call to mapiterinit: .autotmp_[0-9]+$" "live at call to mapiternext: .autotmp_[0-9]+$"
464 printstring(k) // ERROR "live at call to printstring: .autotmp_[0-9]+$"
465 }
466}
467
468// copy of array of pointers should die at end of range loop
469var pstructarr [10]pstruct
470
471// Struct size chosen to make pointer to element in pstructarr
472// not computable by strength reduction.
473type pstruct struct {
474 intp *int
475 _ [8]byte
476}
477
478func f30(b bool) {
479 // live temp during printintpointer(p):
480 // the internal iterator pointer if a pointer to pstruct in pstructarr
481 // can not be easily computed by strength reduction.
482 if b {
483 for _, p := range pstructarr { // ERROR "stack object .autotmp_[0-9]+ \[10\]pstruct$"
484 printintpointer(p.intp) // ERROR "live at call to printintpointer: .autotmp_[0-9]+$"
485 }
486 }
487 for _, p := range pstructarr {
488 printintpointer(p.intp) // ERROR "live at call to printintpointer: .autotmp_[0-9]+$"
489 }
490 for _, p := range pstructarr {
491 printintpointer(p.intp) // ERROR "live at call to printintpointer: .autotmp_[0-9]+$"
492 }
493}
494
495// conversion to interface should not leave temporary behind
496
497func f31(b1, b2, b3 bool) {
498 if b1 {
499 g31(g18()) // ERROR "stack object .autotmp_[0-9]+ \[2\]string$"
500 }
501 if b2 {
Keith Randall57668b82021-08-04 22:18:23 -0700502 h31(g18()) // ERROR "live at call to convT: .autotmp_[0-9]+$" "live at call to newobject: .autotmp_[0-9]+$"
Cherry Zhanga9c244a2021-04-17 00:46:53 -0400503 }
504 if b3 {
505 panic(g18())
506 }
507 print(b3)
508}
509
510func g31(interface{})
511func h31(...interface{})
512
513// non-escaping partial functions passed to function call should die on return
514
515type T32 int
516
517func (t *T32) Inc() { // ERROR "live at entry to \(\*T32\).Inc: t$"
518 *t++
519}
520
521var t32 T32
522
523func f32(b bool) {
524 if b {
525 call32(t32.Inc) // ERROR "stack object .autotmp_[0-9]+ struct \{"
526 }
527 call32(t32.Inc)
528 call32(t32.Inc)
529}
530
531//go:noescape
532func call32(func())
533
534// temporaries introduced during if conditions and && || expressions
535// should die once the condition has been acted upon.
536
537var m33 map[interface{}]int
538
539func f33() {
540 if m33[byteptr()] == 0 { // ERROR "stack object .autotmp_[0-9]+ interface \{\}$"
541 printnl()
542 return
543 } else {
544 printnl()
545 }
546 printnl()
547}
548
549func f34() {
550 if m33[byteptr()] == 0 { // ERROR "stack object .autotmp_[0-9]+ interface \{\}$"
551 printnl()
552 return
553 }
554 printnl()
555}
556
557func f35() {
558 if m33[byteptr()] == 0 && // ERROR "stack object .autotmp_[0-9]+ interface \{\}"
559 m33[byteptr()] == 0 { // ERROR "stack object .autotmp_[0-9]+ interface \{\}"
560 printnl()
561 return
562 }
563 printnl()
564}
565
566func f36() {
567 if m33[byteptr()] == 0 || // ERROR "stack object .autotmp_[0-9]+ interface \{\}"
568 m33[byteptr()] == 0 { // ERROR "stack object .autotmp_[0-9]+ interface \{\}"
569 printnl()
570 return
571 }
572 printnl()
573}
574
575func f37() {
576 if (m33[byteptr()] == 0 || // ERROR "stack object .autotmp_[0-9]+ interface \{\}"
577 m33[byteptr()] == 0) && // ERROR "stack object .autotmp_[0-9]+ interface \{\}"
578 m33[byteptr()] == 0 {
579 printnl()
580 return
581 }
582 printnl()
583}
584
585// select temps should disappear in the case bodies
586
587var c38 chan string
588
589func fc38() chan string
590func fi38(int) *string
591func fb38() *bool
592
593func f38(b bool) {
594 // we don't care what temps are printed on the lines with output.
595 // we care that the println lines have no live variables
596 // and therefore no output.
597 if b {
598 select { // ERROR "live at call to selectgo:( .autotmp_[0-9]+)+$" "stack object .autotmp_[0-9]+ \[4\]struct \{"
599 case <-fc38():
600 printnl()
601 case fc38() <- *fi38(1): // ERROR "live at call to fc38:( .autotmp_[0-9]+)+$" "live at call to fi38:( .autotmp_[0-9]+)+$" "stack object .autotmp_[0-9]+ string$"
602 printnl()
603 case *fi38(2) = <-fc38(): // ERROR "live at call to fc38:( .autotmp_[0-9]+)+$" "live at call to fi38:( .autotmp_[0-9]+)+$" "stack object .autotmp_[0-9]+ string$"
604 printnl()
Matthew Dempskyf7513192022-06-29 17:15:08 -0700605 case *fi38(3), *fb38() = <-fc38(): // ERROR "stack object .autotmp_[0-9]+ string$" "live at call to f[ibc]38:( .autotmp_[0-9]+)+$"
Cherry Zhanga9c244a2021-04-17 00:46:53 -0400606 printnl()
607 }
608 printnl()
609 }
610 printnl()
611}
612
613// issue 8097: mishandling of x = x during return.
614
615func f39() (x []int) {
616 x = []int{1}
617 printnl() // ERROR "live at call to printnl: .autotmp_[0-9]+$"
618 return x
619}
620
621func f39a() (x []int) {
622 x = []int{1}
623 printnl() // ERROR "live at call to printnl: .autotmp_[0-9]+$"
624 return
625}
626
627func f39b() (x [10]*int) {
628 x = [10]*int{}
629 x[0] = new(int) // ERROR "live at call to newobject: x$"
630 printnl() // ERROR "live at call to printnl: x$"
631 return x
632}
633
634func f39c() (x [10]*int) {
635 x = [10]*int{}
636 x[0] = new(int) // ERROR "live at call to newobject: x$"
637 printnl() // ERROR "live at call to printnl: x$"
638 return
639}
640
641// issue 8142: lost 'addrtaken' bit on inlined variables.
642// no inlining in this test, so just checking that non-inlined works.
643
644type T40 struct {
645 m map[int]int
646}
647
648//go:noescape
649func useT40(*T40)
650
651func newT40() *T40 {
652 ret := T40{}
653 ret.m = make(map[int]int, 42) // ERROR "live at call to makemap: &ret$"
654 return &ret
655}
656
657func bad40() {
658 t := newT40()
659 _ = t
660 printnl()
661}
662
663func good40() {
664 ret := T40{} // ERROR "stack object ret T40$"
665 ret.m = make(map[int]int) // ERROR "live at call to fastrand: .autotmp_[0-9]+$" "stack object .autotmp_[0-9]+ map.hdr\[int\]int$"
666 t := &ret
667 printnl() // ERROR "live at call to printnl: ret$"
668 // Note: ret is live at the printnl because the compiler moves &ret
669 // from before the printnl to after.
670 useT40(t)
671}
672
673func ddd1(x, y *int) { // ERROR "live at entry to ddd1: x y$"
674 ddd2(x, y) // ERROR "stack object .autotmp_[0-9]+ \[2\]\*int$"
675 printnl()
676 // Note: no .?autotmp live at printnl. See issue 16996.
677}
678func ddd2(a ...*int) { // ERROR "live at entry to ddd2: a$"
679 sink = a[0]
680}
681
682// issue 16016: autogenerated wrapper should have arguments live
683type T struct{}
684
685func (*T) Foo(ptr *int) {}
686
Matthew Dempsky808dca32021-06-24 12:57:20 -0700687type R struct{ *T }
Cherry Zhanga9c244a2021-04-17 00:46:53 -0400688
689// issue 18860: output arguments must be live all the time if there is a defer.
690// In particular, at printint r must be live.
691func f41(p, q *int) (r *int) { // ERROR "live at entry to f41: p q$"
692 r = p
693 defer func() {
694 recover()
695 }()
696 printint(0) // ERROR "live at call to printint: q .autotmp_[0-9]+ r$"
697 r = q
698 return // ERROR "live at call to f41.func1: .autotmp_[0-9]+ r$"
699}
700
701func f42() {
702 var p, q, r int
703 f43([]*int{&p, &q, &r}) // ERROR "stack object .autotmp_[0-9]+ \[3\]\*int$"
704 f43([]*int{&p, &r, &q})
705 f43([]*int{&q, &p, &r})
706}
707
708//go:noescape
709func f43(a []*int)
710
711// Assigning to a sub-element that makes up an entire local variable
712// should clobber that variable.
713func f44(f func() [2]*int) interface{} { // ERROR "live at entry to f44: f"
714 type T struct {
715 s [1][2]*int
716 }
717 ret := T{}
718 ret.s[0] = f()
719 return ret // ERROR "stack object .autotmp_[0-9]+ T"
720}