1
0
mirror of https://github.com/golang/go synced 2024-11-26 11:08:38 -07:00

cmd/compile: declare inlined result params early for empty returns

The code for delayed declaration of inlined result parameters only
handles non-empty return statements. This is generally okay, because
we already early declare if there are any (non-blank) named result
parameters.

But if a user writes a function with only blank result parameters and
with exactly one return statement, which is empty, then they could end
up hitting the dreaded "Value live at entry" ICE.

This CL fixes the issue by ensuring we always early declare inlined
result parameters if there are any empty return statements.

Fixes #44355.

Change-Id: I315f3853be436452883b1ce31da1bdffdf24d506
Reviewed-on: https://go-review.googlesource.com/c/go/+/293293
TryBot-Result: Go Bot <gobot@golang.org>
Trust: Matthew Dempsky <mdempsky@google.com>
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Reviewed-by: David Chase <drchase@google.com>
This commit is contained in:
Matthew Dempsky 2021-02-17 17:49:40 -08:00
parent 526ee96f49
commit 6c3bcda866
4 changed files with 37 additions and 6 deletions

View File

@ -852,17 +852,25 @@ func mkinlcall(n *ir.CallExpr, fn *ir.Func, maxCost int32, inlMap map[*ir.Func]b
} }
} }
// We can delay declaring+initializing result parameters if:
// (1) there's exactly one "return" statement in the inlined function;
// (2) it's not an empty return statement (#44355); and
// (3) the result parameters aren't named.
delayretvars := true
nreturns := 0 nreturns := 0
ir.VisitList(ir.Nodes(fn.Inl.Body), func(n ir.Node) { ir.VisitList(ir.Nodes(fn.Inl.Body), func(n ir.Node) {
if n != nil && n.Op() == ir.ORETURN { if n, ok := n.(*ir.ReturnStmt); ok {
nreturns++ nreturns++
if len(n.Results) == 0 {
delayretvars = false // empty return statement (case 2)
}
} }
}) })
// We can delay declaring+initializing result parameters if: if nreturns != 1 {
// (1) there's only one "return" statement in the inlined delayretvars = false // not exactly one return statement (case 1)
// function, and (2) the result parameters aren't named. }
delayretvars := nreturns == 1
// temporaries for return values. // temporaries for return values.
var retvars []ir.Node var retvars []ir.Node
@ -873,7 +881,7 @@ func mkinlcall(n *ir.CallExpr, fn *ir.Func, maxCost int32, inlMap map[*ir.Func]b
m = inlvar(n) m = inlvar(n)
m = typecheck.Expr(m).(*ir.Name) m = typecheck.Expr(m).(*ir.Name)
inlvars[n] = m inlvars[n] = m
delayretvars = false // found a named result parameter delayretvars = false // found a named result parameter (case 3)
} else { } else {
// anonymous return values, synthesize names for use in assignment that replaces return // anonymous return values, synthesize names for use in assignment that replaces return
m = retvar(t, i) m = retvar(t, i)

View File

@ -0,0 +1,7 @@
// Copyright 2021 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 a
func F() (_ *int) { return nil }

View File

@ -0,0 +1,9 @@
// Copyright 2021 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 b
import "./a"
var _ = a.F()

View File

@ -0,0 +1,7 @@
// compiledir
// Copyright 2021 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 ignored