# Test closure naming with inlining. go build -gcflags=-S -o x.exe x.go # original closure name should appear stderr 'adder\.func1' # inlining should not cause the closure to have longer names ! stderr 'F1\.adder\.func1' ! stderr 'F2\.adder\.func1' # the counter should match the original one, regardless of # how many closures are in the inlined caller ! stderr 'adder\.func2' ! stderr 'adder\.func3' ! stderr 'adder\.func4' # user closure counter and range func counter should not # interfere stderr 'ranger\.func1' stderr 'ranger-range1' stderr 'ranger\.func2' go tool nm x.exe # same applies to the nm output stdout 'adder\.func1' ! stdout 'F1\.adder\.func1' ! stdout 'F2\.adder\.func1' ! stdout 'adder\.func2' ! stdout 'adder\.func3' ! stdout 'adder\.func4' stdout 'ranger\.func1' stdout 'ranger-range1' stdout 'ranger\.func2' # the inline hash should not make into the final binary ! stdout 'adder\.func1#' -- x.go -- package main // keep prevents closures being optimized out // //go:noinline func keep(x func()) func() { return x } func adder(n int) func(int) int { return func(x int) int { return x + n } } //go:noinline func F1() func(int) int { // adder is inlined into F1, along with its closure. // The closure should still be named addr.func1. return adder(1) } //go:noinline func F2() func(int) int { keep(func() {}) keep(func() {}) keep(func() {}) // Closures in the outer function should not change // the counter. It should still be addr.func1. return adder(2) } //go:noinline func iter(yield func(int) bool) { _ = yield(1) && yield(2) && yield(3) } func ranger() func(int) int { keep(func() {}) // func1 s := 0 for x := range iter { // range1 s += x } return func(x int) int { return s + x } // func2 } func main() { x := 1 F1()(F2()(ranger()(x))) }