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