]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: disable inlining for functions using runtime.deferrangefunc
authorzuojunwei.1024 <zuojunwei.1024@bytedance.com>
Tue, 23 Dec 2025 08:12:04 +0000 (16:12 +0800)
committerCherry Mui <cherryyz@google.com>
Tue, 30 Dec 2025 15:26:35 +0000 (07:26 -0800)
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>
src/cmd/compile/internal/inline/inl.go
src/cmd/compile/testdata/script/issue77033.txt [new file with mode: 0644]

index 33f9c325c36f5b1c1c79c879c4392f81313496aa..4fa9cf07fb86e452e4860bd467a56a3b8dbcf3fb 100644 (file)
@@ -516,6 +516,9 @@ opSwitch:
                                                break opSwitch
                                        case "panicrangestate":
                                                cheap = true
+                                       case "deferrangefunc":
+                                               v.reason = "defer call in range func"
+                                               return true
                                        }
                                }
                        }
diff --git a/src/cmd/compile/testdata/script/issue77033.txt b/src/cmd/compile/testdata/script/issue77033.txt
new file mode 100644 (file)
index 0000000..3b977e5
--- /dev/null
@@ -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