aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/cmd/compile/internal/reflectdata/reflect.go21
-rw-r--r--test/fixedbugs/issue53702.go39
2 files changed, 57 insertions, 3 deletions
diff --git a/src/cmd/compile/internal/reflectdata/reflect.go b/src/cmd/compile/internal/reflectdata/reflect.go
index aec7358c322..4ee9830db38 100644
--- a/src/cmd/compile/internal/reflectdata/reflect.go
+++ b/src/cmd/compile/internal/reflectdata/reflect.go
@@ -1878,14 +1878,14 @@ func methodWrapper(rcvr *types.Type, method *types.Field, forItab bool) *obj.LSy
// the TOC to the appropriate value for that module. But if it returns
// directly to the wrapper's caller, nothing will reset it to the correct
// value for that function.
+ var call *ir.CallExpr
if !base.Flag.Cfg.Instrumenting && rcvr.IsPtr() && methodrcvr.IsPtr() && method.Embedded != 0 && !types.IsInterfaceMethod(method.Type) && !(base.Ctxt.Arch.Name == "ppc64le" && base.Ctxt.Flag_dynlink) && !generic {
- call := ir.NewCallExpr(base.Pos, ir.OCALL, dot, nil)
+ call = ir.NewCallExpr(base.Pos, ir.OCALL, dot, nil)
call.Args = ir.ParamNames(tfn.Type())
call.IsDDD = tfn.Type().IsVariadic()
fn.Body.Append(ir.NewTailCallStmt(base.Pos, call))
} else {
fn.SetWrapper(true) // ignore frame for panic+recover matching
- var call *ir.CallExpr
if generic && dot.X != nthis {
// If there is embedding involved, then we should do the
@@ -1970,7 +1970,22 @@ func methodWrapper(rcvr *types.Type, method *types.Field, forItab bool) *obj.LSy
typecheck.Stmts(fn.Body)
if AfterGlobalEscapeAnalysis {
- inline.InlineCalls(fn)
+ // Inlining the method may reveal closures, which require walking all function bodies
+ // to decide whether to capture free variables by value or by ref. So we only do inline
+ // if the method do not contain any closures, otherwise, the escape analysis may make
+ // dead variables resurrected, and causing liveness analysis confused, see issue #53702.
+ var canInline bool
+ switch x := call.X.(type) {
+ case *ir.Name:
+ canInline = len(x.Func.Closures) == 0
+ case *ir.SelectorExpr:
+ if x.Op() == ir.OMETHEXPR {
+ canInline = x.FuncName().Func != nil && len(x.FuncName().Func.Closures) == 0
+ }
+ }
+ if canInline {
+ inline.InlineCalls(fn)
+ }
escape.Batch([]*ir.Func{fn}, false)
}
diff --git a/test/fixedbugs/issue53702.go b/test/fixedbugs/issue53702.go
new file mode 100644
index 00000000000..0b251c2d7be
--- /dev/null
+++ b/test/fixedbugs/issue53702.go
@@ -0,0 +1,39 @@
+// run
+
+// Copyright 2022 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.
+
+package main
+
+type Elem struct{}
+
+func (*Elem) Wait(callback func()) {}
+
+type Base struct {
+ elem [8]*Elem
+}
+
+var g_val = 1
+
+func (s *Base) Do() *int {
+ resp := &g_val
+ for _, e := range s.elem {
+ e.Wait(func() {
+ *resp = 0
+ })
+ }
+ return resp
+}
+
+type Sub struct {
+ *Base
+}
+
+func main() {
+ a := Sub{new(Base)}
+ resp := a.Do()
+ if resp != nil && *resp != 1 {
+ panic("FAIL")
+ }
+}