Since CL 685355, gorecover detects a valid recover call by unwinding the stack and counting the non-wrapper frames between gopanic and gorecover. The unwinder counts inline-expanded frames as separate logical frames, so inlining a function that calls recover no longer changes whether that recover stops the panic. Drop the restriction and charge the usual call cost for recover. This allows inlining of ordinary calls to functions that call recover, including calls from compiler-generated wrappers such as deferred method values, where the inlined recover remains active. Deferred call sites are still not inline-expanded, so deferred recover closures like the ones in net/http.(*conn).serve and text/template.safeCall are only marked inlinable; that becomes useful if the inliner later learns to expand deferred calls. In test/closure3.dir/main.go and test/codegen/issue60324.go, recover was used as a device to keep a closure from being inlined; use defer instead, which still disables inlining. Update test/escape4.go, which expected functions calling recover to not be inlinable. Add test/recover6.go to verify that recover semantics are unchanged when functions calling recover are inlined. Change-Id: I4e15622af62d05faefc2a482b43fc46e0ac6a52d Reviewed-on: https://go-review.googlesource.com/c/go/+/815361 Reviewed-by: Michael Pratt <mpratt@google.com> Reviewed-by: Keith Randall <khr@golang.org> LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com> Reviewed-by: Keith Randall <khr@google.com> Auto-Submit: Keith Randall <khr@golang.org>
60 lines
1.4 KiB
Go
60 lines
1.4 KiB
Go
// errorcheck -0 -m
|
|
|
|
//go:build !goexperiment.newinliner
|
|
|
|
// Copyright 2010 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 enabled.
|
|
|
|
package foo
|
|
|
|
var p *int
|
|
|
|
func alloc(x int) *int { // ERROR "can inline alloc" "moved to heap: x"
|
|
return &x
|
|
}
|
|
|
|
var f func()
|
|
|
|
func f1() {
|
|
p = alloc(2) // ERROR "inlining call to alloc" "moved to heap: x"
|
|
|
|
// Escape analysis used to miss inlined code in closures.
|
|
|
|
func() { // ERROR "can inline f1.func1"
|
|
p = alloc(3) // ERROR "inlining call to alloc" "moved to heap: x"
|
|
}() // ERROR "inlining call to f1.func1" "inlining call to alloc" "moved to heap: x"
|
|
|
|
f = func() { // ERROR "func literal escapes to heap" "can inline f1.func2"
|
|
p = alloc(3) // ERROR "inlining call to alloc" "moved to heap: x"
|
|
}
|
|
f()
|
|
}
|
|
|
|
func f2() {} // ERROR "can inline f2"
|
|
|
|
// Both panic and recover are allowed to inline.
|
|
func f3() { panic(1) } // ERROR "can inline f3" "1 escapes to heap"
|
|
func f4() { recover() } // ERROR "can inline f4"
|
|
|
|
func f5() *byte { // ERROR "can inline f5"
|
|
type T struct {
|
|
x [1]byte
|
|
}
|
|
t := new(T) // ERROR "new.T. escapes to heap"
|
|
return &t.x[0]
|
|
}
|
|
|
|
func f6() *byte { // ERROR "can inline f6"
|
|
type T struct {
|
|
x struct {
|
|
y byte
|
|
}
|
|
}
|
|
t := new(T) // ERROR "new.T. escapes to heap"
|
|
return &t.x.y
|
|
}
|