"log"
"os"
"runtime"
+ "sort"
)
func hidePanic() {
typecheck.Export(initTask)
}
+ // Stability quirk: sort top-level declarations, so we're not
+ // sensitive to the order that functions are added. In particular,
+ // the order that noder+typecheck add function closures is very
+ // subtle, and not important to reproduce.
+ //
+ // Note: This needs to happen after pkginit.Task, otherwise it risks
+ // changing the order in which top-level variables are initialized.
+ if base.Debug.UnifiedQuirks != 0 {
+ s := typecheck.Target.Decls
+ sort.SliceStable(s, func(i, j int) bool {
+ return s[i].Pos().Before(s[j].Pos())
+ })
+ }
+
// Eliminate some obviously dead code.
// Must happen after typechecking.
for _, n := range typecheck.Target.Decls {
r.curfn = fn
r.closureVars = fn.ClosureVars
- // TODO(mdempsky): Get rid of uses of typecheck.NodAddrAt so we
- // don't have to set ir.CurFunc.
- outerCurFunc := ir.CurFunc
- ir.CurFunc = fn
+ ir.WithFunc(fn, func() {
+ r.funcargs(fn)
- r.funcargs(fn)
+ if !r.bool() {
+ return
+ }
- if r.bool() {
body := r.stmts()
if body == nil {
pos := src.NoXPos
if quirksMode() {
pos = funcParamsEndPos(fn)
}
- body = []ir.Node{ir.NewBlockStmt(pos, nil)}
+ body = []ir.Node{typecheck.Stmt(ir.NewBlockStmt(pos, nil))}
}
fn.Body = body
fn.Endlineno = r.pos()
- }
+ })
- ir.CurFunc = outerCurFunc
r.marker.WriteTo(fn)
}
scopeVars := r.scopeVars[len(r.scopeVars)-1]
r.scopeVars = r.scopeVars[:len(r.scopeVars)-1]
- if scopeVars == len(r.curfn.Dcl) {
+ // Quirkish: noder decides which scopes to keep before
+ // typechecking, whereas incremental typechecking during IR
+ // construction can result in new autotemps being allocated. To
+ // produce identical output, we ignore autotemps here for the
+ // purpose of deciding whether to retract the scope.
+ //
+ // This is important for net/http/fcgi, because it contains:
+ //
+ // var body io.ReadCloser
+ // if len(content) > 0 {
+ // body, req.pw = io.Pipe()
+ // } else { … }
+ //
+ // Notably, io.Pipe is inlinable, and inlining it introduces a ~R0
+ // variable at the call site.
+ //
+ // Noder does not preserve the scope where the io.Pipe() call
+ // resides, because it doesn't contain any declared variables in
+ // source. So the ~R0 variable ends up being assigned to the
+ // enclosing scope instead.
+ //
+ // However, typechecking this assignment also introduces
+ // autotemps, because io.Pipe's results need conversion before
+ // they can be assigned to their respective destination variables.
+ //
+ // TODO(mdempsky): We should probably just keep all scopes, and
+ // let dwarfgen take care of pruning them instead.
+ retract := true
+ for _, n := range r.curfn.Dcl[scopeVars:] {
+ if !n.AutoTemp() {
+ retract = false
+ break
+ }
+ }
+
+ if retract {
// no variables were declared in this scope, so we can retract it.
r.marker.Unpush()
} else {
}
func (r *reader) stmts() []ir.Node {
+ assert(ir.CurFunc == r.curfn)
var res ir.Nodes
r.sync(syncStmts)
}
if n := r.stmt1(tag, &res); n != nil {
- res.Append(n)
+ res.Append(typecheck.Stmt(n))
}
}
}
for _, name := range names {
as := ir.NewAssignStmt(pos, name, nil)
as.PtrInit().Append(ir.NewDecl(pos, ir.ODCL, name))
- out.Append(as)
+ out.Append(typecheck.Stmt(as))
}
return nil
}
case exprCall:
fun := r.expr()
+ if clo, ok := fun.(*ir.ClosureExpr); ok {
+ clo.Func.SetClosureCalled(true)
+ }
pos := r.pos()
args := r.exprs()
dots := r.bool()
}
fn := ir.NewClosureFunc(opos, r.curfn != nil)
+ clo := fn.OClosure
+ ir.NameClosure(clo, r.curfn)
r.setType(fn.Nname, xtype2)
if quirksMode() {
fn.Nname.Ntype = ir.TypeNodeAt(typPos, xtype2)
}
+ typecheck.Func(fn)
+ r.setType(clo, fn.Type())
fn.ClosureVars = make([]*ir.Name, 0, r.len())
for len(fn.ClosureVars) < cap(fn.ClosureVars) {
r.addBody(fn)
- return fn.OClosure
+ // TODO(mdempsky): Remove hard-coding of typecheck.Target.
+ return ir.UseClosure(clo, typecheck.Target)
}
func (r *reader) exprList() []ir.Node {
r.setType(tmpfn.Nname, fn.Type())
r.curfn = tmpfn
- r.inlCaller = ir.CurFunc
+ r.inlCaller = callerfn
r.inlCall = call
r.inlFunc = fn
r.inlTreeIndex = inlIndex
nparams := len(r.curfn.Dcl)
- oldcurfn := ir.CurFunc
- ir.CurFunc = r.curfn
-
- r.curfn.Body = r.stmts()
- r.curfn.Endlineno = r.pos()
+ ir.WithFunc(r.curfn, func() {
+ r.curfn.Body = r.stmts()
+ r.curfn.Endlineno = r.pos()
- typecheck.Stmts(r.curfn.Body)
- deadcode.Func(r.curfn)
+ deadcode.Func(r.curfn)
- // Replace any "return" statements within the function body.
- {
+ // Replace any "return" statements within the function body.
var edit func(ir.Node) ir.Node
edit = func(n ir.Node) ir.Node {
if ret, ok := n.(*ir.ReturnStmt); ok {
return n
}
edit(r.curfn)
- }
-
- ir.CurFunc = oldcurfn
+ })
body := ir.Nodes(r.curfn.Body)
r.funarghack = true
r.funcBody(tmpfn)
- }
-
- oldcurfn := ir.CurFunc
- ir.CurFunc = tmpfn
- typecheck.Stmts(tmpfn.Body)
- deadcode.Func(tmpfn)
-
- ir.CurFunc = oldcurfn
+ ir.WithFunc(tmpfn, func() {
+ deadcode.Func(tmpfn)
+ })
+ }
used := usedLocals(tmpfn.Body)