go/test/fixedbugs/issue13799.go
Matthew Dempsky 18c6ec1e4a cmd/compile/internal/noder: stop preserving original const strings
One of the more tedious quirks of the original frontend (i.e.,
typecheck) to preserve was that it preserved the original
representation of constants into the backend. To fit into the unified
IR model, I ended up implementing a fairly heavyweight workaround:
simply record the original constant's string expression in the export
data, so that diagnostics could still report it back, and match the
old test expectations.

But now that there's just a single frontend to support, it's easy
enough to just update the test expectations and drop this support for
"raw" constant expressions.

Change-Id: I1d859c5109d679879d937a2b213e777fbddf4f2f
Reviewed-on: https://go-review.googlesource.com/c/go/+/526376
Reviewed-by: Keith Randall <khr@golang.org>
Reviewed-by: Keith Randall <khr@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Matthew Dempsky <mdempsky@google.com>
Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
2023-09-08 18:50:24 +00:00

192 lines
4.9 KiB
Go

// errorcheck -0 -m -l
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Test, using compiler diagnostic flags, that the escape analysis is working.
// Compiles but does not run. Inlining is disabled.
// Registerization is disabled too (-N), which should
// have no effect on escape analysis.
package main
import "fmt"
func main() {
// Just run test over and over again. This main func is just for
// convenience; if test were the main func, we could also trigger
// the panic just by running the program over and over again
// (sometimes it takes 1 time, sometimes it takes ~4,000+).
for iter := 0; ; iter++ {
if iter%50 == 0 {
fmt.Println(iter) // ERROR "iter escapes to heap$" "... argument does not escape$"
}
test1(iter)
test2(iter)
test3(iter)
test4(iter)
test5(iter)
test6(iter)
}
}
func test1(iter int) {
const maxI = 500
m := make(map[int][]int) // ERROR "make\(map\[int\]\[\]int\) escapes to heap$"
// The panic seems to be triggered when m is modified inside a
// closure that is both recursively called and reassigned to in a
// loop.
// Cause of bug -- escape of closure failed to escape (shared) data structures
// of map. Assign to fn declared outside of loop triggers escape of closure.
// Heap -> stack pointer eventually causes badness when stack reallocation
// occurs.
var fn func() // ERROR "moved to heap: fn$"
i := 0 // ERROR "moved to heap: i$"
for ; i < maxI; i++ {
// var fn func() // this makes it work, because fn stays off heap
j := 0 // ERROR "moved to heap: j$"
fn = func() { // ERROR "func literal escapes to heap$"
m[i] = append(m[i], 0)
if j < 25 {
j++
fn()
}
}
fn()
}
if len(m) != maxI {
panic(fmt.Sprintf("iter %d: maxI = %d, len(m) = %d", iter, maxI, len(m))) // ERROR "iter escapes to heap$" "len\(m\) escapes to heap$" "500 escapes to heap$" "... argument does not escape$" "fmt.Sprintf\(.*\) escapes to heap"
}
}
func test2(iter int) {
const maxI = 500
m := make(map[int][]int) // ERROR "make\(map\[int\]\[\]int\) does not escape$"
// var fn func()
for i := 0; i < maxI; i++ {
var fn func() // this makes it work, because fn stays off heap
j := 0
fn = func() { // ERROR "func literal does not escape$"
m[i] = append(m[i], 0)
if j < 25 {
j++
fn()
}
}
fn()
}
if len(m) != maxI {
panic(fmt.Sprintf("iter %d: maxI = %d, len(m) = %d", iter, maxI, len(m))) // ERROR "iter escapes to heap$" "len\(m\) escapes to heap$" "500 escapes to heap$" "... argument does not escape$" "fmt.Sprintf\(.*\) escapes to heap"
}
}
func test3(iter int) {
const maxI = 500
var x int // ERROR "moved to heap: x$"
m := &x
var fn func() // ERROR "moved to heap: fn$"
for i := 0; i < maxI; i++ {
// var fn func() // this makes it work, because fn stays off heap
j := 0 // ERROR "moved to heap: j$"
fn = func() { // ERROR "func literal escapes to heap$"
if j < 100 {
j++
fn()
} else {
*m = *m + 1
}
}
fn()
}
if *m != maxI {
panic(fmt.Sprintf("iter %d: maxI = %d, *m = %d", iter, maxI, *m)) // ERROR "\*m escapes to heap$" "iter escapes to heap$" "500 escapes to heap$" "... argument does not escape$" "fmt.Sprintf\(.*\) escapes to heap"
}
}
func test4(iter int) {
const maxI = 500
var x int
m := &x
// var fn func()
for i := 0; i < maxI; i++ {
var fn func() // this makes it work, because fn stays off heap
j := 0
fn = func() { // ERROR "func literal does not escape$"
if j < 100 {
j++
fn()
} else {
*m = *m + 1
}
}
fn()
}
if *m != maxI {
panic(fmt.Sprintf("iter %d: maxI = %d, *m = %d", iter, maxI, *m)) // ERROR "\*m escapes to heap$" "iter escapes to heap$" "500 escapes to heap$" "... argument does not escape$" "fmt.Sprintf\(.*\) escapes to heap"
}
}
type str struct {
m *int
}
func recur1(j int, s *str) { // ERROR "s does not escape"
if j < 100 {
j++
recur1(j, s)
} else {
*s.m++
}
}
func test5(iter int) {
const maxI = 500
var x int // ERROR "moved to heap: x$"
m := &x
var fn *str
for i := 0; i < maxI; i++ {
// var fn *str // this makes it work, because fn stays off heap
fn = &str{m} // ERROR "&str{...} escapes to heap"
recur1(0, fn)
}
if *m != maxI {
panic(fmt.Sprintf("iter %d: maxI = %d, *m = %d", iter, maxI, *m)) // ERROR "\*m escapes to heap$" "iter escapes to heap$" "500 escapes to heap$" "... argument does not escape$" "fmt.Sprintf\(.*\) escapes to heap"
}
}
func test6(iter int) {
const maxI = 500
var x int
m := &x
// var fn *str
for i := 0; i < maxI; i++ {
var fn *str // this makes it work, because fn stays off heap
fn = &str{m} // ERROR "&str{...} does not escape"
recur1(0, fn)
}
if *m != maxI {
panic(fmt.Sprintf("iter %d: maxI = %d, *m = %d", iter, maxI, *m)) // ERROR "\*m escapes to heap$" "iter escapes to heap$" "500 escapes to heap$" "... argument does not escape$" "fmt.Sprintf\(.*\) escapes to heap"
}
}