avarinit := bvalloc(nvars)
any := bvalloc(nvars)
all := bvalloc(nvars)
- pparamout := bvalloc(localswords())
-
- // Record pointers to heap-allocated pparamout variables. These
- // are implicitly read by post-deferreturn code and thus must be
- // kept live throughout the function (if there is any defer that
- // recovers).
+ outLive := bvalloc(argswords()) // always-live output params
+ outLiveHeap := bvalloc(localswords()) // always-live pointers to heap-allocated copies of output params
+
+ // If there is a defer (that could recover), then all output
+ // parameters are live all the time. In addition, any locals
+ // that are pointers to heap-allocated output parameters are
+ // also always live (post-deferreturn code needs these
+ // pointers to copy values back to the stack).
+ // TODO: if the output parameter is heap-allocated, then we
+ // don't need to keep the stack copy live?
if hasdefer {
for _, n := range lv.vars {
+ if n.Class == PPARAMOUT {
+ if n.IsOutputParamHeapAddr() {
+ // Just to be paranoid.
+ Fatalf("variable %v both output param and heap output param", n)
+ }
+ // Needzero not necessary, as the compiler
+ // explicitly zeroes output vars at start of fn.
+ xoffset := n.Xoffset
+ onebitwalktype1(n.Type, &xoffset, outLive)
+ }
if n.IsOutputParamHeapAddr() {
n.Name.Needzero = true
xoffset := n.Xoffset + stkptrsize
- onebitwalktype1(n.Type, &xoffset, pparamout)
+ onebitwalktype1(n.Type, &xoffset, outLiveHeap)
}
}
}
// Mark pparamout variables (as described above)
if p.As == obj.ACALL {
- locals.Or(locals, pparamout)
+ args.Or(args, outLive)
+ locals.Or(locals, outLiveHeap)
}
// Show live pointer bitmaps.
func (*T) Foo(ptr *int) {}
type R struct{ *T } // ERRORAUTO "live at entry to \(\*R\)\.Foo: \.this ptr" "live at entry to R\.Foo: \.this ptr"
+
+// issue 18860: output arguments must be live all the time if there is a defer.
+// In particular, at printint r must be live.
+func f41(p, q *int) (r *int) { // ERROR "live at entry to f41: p q$"
+ r = p
+ defer func() {
+ recover()
+ }() // ERROR "live at call to deferproc: q r$" "live at call to deferreturn: r$"
+ printint(0) // ERROR "live at call to printint: q r$"
+ r = q
+ return // ERROR "live at call to deferreturn: r$"
+}