cmd/compile: disable inlining for functions using runtime.deferrangefunc

The rangefunc rewrite pass implements defer using deferrangefunc and
deferproccat. The loop body is rewritten into a closure, it cannot be
inlined due to defer call. But the outer function may still be inlined
in certain scenarios (e.g., with PGO), leading to the defer executing
at the wrong time.

Fixes #77033

Change-Id: I4649fad5cd1b65891832523522002d9352711123
Reviewed-on: https://go-review.googlesource.com/c/go/+/732140
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
This commit is contained in:
zuojunwei.1024
2025-12-23 16:12:04 +08:00
committed by Cherry Mui
parent 06eff0f7c3
commit cd668d744f
2 changed files with 43 additions and 0 deletions

View File

@@ -516,6 +516,9 @@ opSwitch:
break opSwitch
case "panicrangestate":
cheap = true
case "deferrangefunc":
v.reason = "defer call in range func"
return true
}
}
}

View File

@@ -0,0 +1,40 @@
go test -bench=Foo -cpuprofile=default.pgo
go test -bench=Foo -pgo=default.pgo
! stdout 'FAIL'
-- main_test.go --
package main
import (
"testing"
)
var a int
func save(x int) {
a = x
}
func foo() {
for i := range yield1 {
defer save(i)
}
}
func yield1(yield func(int) bool) {
yield(1)
}
func BenchmarkFoo(b *testing.B) {
for i := 0; i < b.N; i++ {
foo()
}
if a != 1 {
b.Fatalf("a = %d; want 1", a)
}
}
-- go.mod --
module demo
go 1.24