diff options
-rw-r--r-- | src/cmd/compile/internal/reflectdata/reflect.go | 21 | ||||
-rw-r--r-- | test/fixedbugs/issue53702.go | 39 |
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") + } +} |