return xfunc
}
+// capturevarscomplete is set to true when the capturevars phase is done.
+var capturevarscomplete bool
+
// capturevars is called in a separate phase after all typechecking is done.
// It decides whether each variable captured by a closure should be captured
// by value or by reference.
)
var (
- Debug_append int
- Debug_asm bool
- Debug_closure int
- debug_dclstack int
- Debug_panic int
- Debug_slice int
- Debug_vlog bool
- Debug_wb int
- Debug_pctab string
+ Debug_append int
+ Debug_asm bool
+ Debug_closure int
+ Debug_compilelater int
+ debug_dclstack int
+ Debug_panic int
+ Debug_slice int
+ Debug_vlog bool
+ Debug_wb int
+ Debug_pctab string
)
// Debug arguments.
}{
{"append", "print information about append compilation", &Debug_append},
{"closure", "print information about closure compilation", &Debug_closure},
+ {"compilelater", "compile functions as late as possible", &Debug_compilelater},
{"disablenil", "disable nil checks", &disable_checknil},
{"dclstack", "run internal dclstack check", &debug_dclstack},
{"gcprog", "print dump of GC programs", &Debug_gcprog},
capturevars(n)
}
}
+ capturevarscomplete = true
Curfn = nil
// they are enqueued in compilequeue,
// which is drained by compileFunctions.
func compilenow() bool {
- return nBackendWorkers == 1
+ return nBackendWorkers == 1 && Debug_compilelater == 0
}
// compileSSA builds an SSA backend function,
var l *Node
for l = n.Left; l != r; l = l.Left {
l.SetAddrtaken(true)
- if l.IsClosureVar() {
+ if l.IsClosureVar() && !capturevarscomplete {
+ // Mark the original variable as Addrtaken so that capturevars
+ // knows not to pass it by value.
+ // But if the capturevars phase is complete, don't touch it,
+ // in case l.Name's containing function has not yet been compiled.
l.Name.Defn.SetAddrtaken(true)
}
}
Fatalf("found non-orig name node %v", l)
}
l.SetAddrtaken(true)
- if l.IsClosureVar() {
+ if l.IsClosureVar() && !capturevarscomplete {
+ // See comments above about closure variables.
l.Name.Defn.SetAddrtaken(true)
}
n.Left = defaultlit(n.Left, nil)
--- /dev/null
+// errorcheck -0 -live -d=compilelater
+
+// Copyright 2017 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.
+
+// Issue 20250: liveness differed with concurrent compilation
+// due to propagation of addrtaken to outer variables for
+// closure variables.
+
+package p
+
+type T struct {
+ s string
+}
+
+func f(a T) { // ERROR "live at entry to f: a"
+ var e interface{}
+ func() { // ERROR "live at entry to f.func1: &e a"
+ e = a.s // ERROR "live at call to convT2Estring: &e a" "live at call to writebarrierptr: a"
+ }() // ERROR "live at call to f.func1: e$"
+ // Before the fix, both a and e were live at the previous line.
+ _ = e
+}