aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/noder/reader.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/compile/internal/noder/reader.go')
-rw-r--r--src/cmd/compile/internal/noder/reader.go100
1 files changed, 66 insertions, 34 deletions
diff --git a/src/cmd/compile/internal/noder/reader.go b/src/cmd/compile/internal/noder/reader.go
index 24977ed7f0..275baead04 100644
--- a/src/cmd/compile/internal/noder/reader.go
+++ b/src/cmd/compile/internal/noder/reader.go
@@ -886,27 +886,25 @@ func (r *reader) funcBody(fn *ir.Func) {
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)
}
@@ -1045,7 +1043,42 @@ func (r *reader) closeAnotherScope() {
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 {
@@ -1068,6 +1101,7 @@ func (r *reader) stmt() ir.Node {
}
func (r *reader) stmts() []ir.Node {
+ assert(ir.CurFunc == r.curfn)
var res ir.Nodes
r.sync(syncStmts)
@@ -1079,7 +1113,7 @@ func (r *reader) stmts() []ir.Node {
}
if n := r.stmt1(tag, &res); n != nil {
- res.Append(n)
+ res.Append(typecheck.Stmt(n))
}
}
}
@@ -1108,7 +1142,7 @@ func (r *reader) stmt1(tag codeStmt, out *ir.Nodes) ir.Node {
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
}
@@ -1488,6 +1522,9 @@ func (r *reader) expr() ir.Node {
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()
@@ -1574,11 +1611,15 @@ func (r *reader) funcLit() ir.Node {
}
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) {
@@ -1591,7 +1632,8 @@ func (r *reader) funcLit() ir.Node {
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 {
@@ -1788,7 +1830,7 @@ func InlineCall(call *ir.CallExpr, fn *ir.Func, inlIndex int) *ir.InlinedCallExp
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
@@ -1872,17 +1914,13 @@ func InlineCall(call *ir.CallExpr, fn *ir.Func, inlIndex int) *ir.InlinedCallExp
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 {
@@ -1892,9 +1930,7 @@ func InlineCall(call *ir.CallExpr, fn *ir.Func, inlIndex int) *ir.InlinedCallExp
return n
}
edit(r.curfn)
- }
-
- ir.CurFunc = oldcurfn
+ })
body := ir.Nodes(r.curfn.Body)
@@ -1998,15 +2034,11 @@ func expandInline(fn *ir.Func, pri pkgReaderIndex) {
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)