diff --git a/go/ssa/builder.go b/go/ssa/builder.go index 1460d488..4bab92d2 100644 --- a/go/ssa/builder.go +++ b/go/ssa/builder.go @@ -347,7 +347,7 @@ func (b *builder) addr(fn *Function, e ast.Expr, escaping bool) lvalue { if v == nil { v = fn.lookup(obj, escaping) } - return &address{addr: v, expr: e} + return &address{addr: v, pos: e.Pos(), expr: e} case *ast.CompositeLit: t := deref(fn.Pkg.typeOf(e)) @@ -359,7 +359,7 @@ func (b *builder) addr(fn *Function, e ast.Expr, escaping bool) lvalue { } v.Comment = "complit" b.compLit(fn, v, e, true) // initialize in place - return &address{addr: v, expr: e} + return &address{addr: v, pos: e.Lbrace, expr: e} case *ast.ParenExpr: return b.addr(fn, e.X, escaping) @@ -378,6 +378,7 @@ func (b *builder) addr(fn *Function, e ast.Expr, escaping bool) lvalue { last := len(sel.Index()) - 1 return &address{ addr: emitFieldSelection(fn, v, sel.Index()[last], true, e.Sel), + pos: e.Sel.Pos(), expr: e.Sel, } @@ -410,10 +411,10 @@ func (b *builder) addr(fn *Function, e ast.Expr, escaping bool) lvalue { } v.setPos(e.Lbrack) v.setType(et) - return &address{addr: fn.emit(v), expr: e} + return &address{addr: fn.emit(v), pos: e.Lbrack, expr: e} case *ast.StarExpr: - return &address{addr: b.expr(fn, e.X), starPos: e.Star, expr: e} + return &address{addr: b.expr(fn, e.X), pos: e.Star, expr: e} } panic(fmt.Sprintf("unexpected address expression: %T", e)) @@ -891,7 +892,7 @@ func (b *builder) emitCallArgs(fn *Function, sig *types.Signature, e *ast.CallEx } iaddr.setType(types.NewPointer(vt)) fn.emit(iaddr) - emitStore(fn, iaddr, arg) + emitStore(fn, iaddr, arg, arg.Pos()) } s := &Slice{X: a} s.setType(st) @@ -1044,17 +1045,19 @@ func (b *builder) compLit(fn *Function, addr Value, e *ast.CompositeLit, isZero switch t := typ.Underlying().(type) { case *types.Struct: if !isZero && len(e.Elts) != t.NumFields() { - emitMemClear(fn, addr) + emitMemClear(fn, addr, e.Lbrace) isZero = true } for i, e := range e.Elts { fieldIndex := i + pos := e.Pos() if kv, ok := e.(*ast.KeyValueExpr); ok { fname := kv.Key.(*ast.Ident).Name for i, n := 0, t.NumFields(); i < n; i++ { sf := t.Field(i) if sf.Name() == fname { fieldIndex = i + pos = kv.Colon e = kv.Value break } @@ -1067,7 +1070,7 @@ func (b *builder) compLit(fn *Function, addr Value, e *ast.CompositeLit, isZero } faddr.setType(types.NewPointer(sf.Type())) fn.emit(faddr) - b.exprInPlace(fn, &address{addr: faddr, expr: e}, e, isZero) + b.exprInPlace(fn, &address{addr: faddr, pos: pos, expr: e}, e, isZero) } case *types.Array, *types.Slice: @@ -1086,7 +1089,7 @@ func (b *builder) compLit(fn *Function, addr Value, e *ast.CompositeLit, isZero } if !isZero && int64(len(e.Elts)) != at.Len() { - emitMemClear(fn, array) + emitMemClear(fn, array, e.Lbrace) isZero = true } @@ -1108,20 +1111,20 @@ func (b *builder) compLit(fn *Function, addr Value, e *ast.CompositeLit, isZero } iaddr.setType(types.NewPointer(at.Elem())) fn.emit(iaddr) - b.exprInPlace(fn, &address{addr: iaddr, expr: e}, e, isZero) + b.exprInPlace(fn, &address{addr: iaddr, pos: e.Pos(), expr: e}, e, isZero) } if t != at { // slice s := &Slice{X: array} s.setPos(e.Lbrace) s.setType(typ) - emitStore(fn, addr, fn.emit(s)) + emitStore(fn, addr, fn.emit(s), e.Lbrace) } case *types.Map: m := &MakeMap{Reserve: intConst(int64(len(e.Elts)))} m.setPos(e.Lbrace) m.setType(typ) - emitStore(fn, addr, fn.emit(m)) + emitStore(fn, addr, fn.emit(m), e.Lbrace) for _, e := range e.Elts { e := e.(*ast.KeyValueExpr) loc := &element{ @@ -1337,7 +1340,7 @@ func (b *builder) typeCaseBody(fn *Function, cc *ast.CaseClause, x Value, done * // In a single-type case, y has that type. // In multi-type cases, 'case nil' and default, // y has the same type as the interface operand. - emitStore(fn, fn.addNamedLocal(obj), x) + emitStore(fn, fn.addNamedLocal(obj), x, obj.Pos()) } fn.targets = &targets{ tail: fn.targets, @@ -1588,8 +1591,9 @@ func (b *builder) forStmt(fn *Function, s *ast.ForStmt, label *lblock) { // rangeIndexed emits to fn the header for an integer-indexed loop // over array, *array or slice value x. // The v result is defined only if tv is non-nil. +// forPos is the position of the "for" token. // -func (b *builder) rangeIndexed(fn *Function, x Value, tv types.Type) (k, v Value, loop, done *BasicBlock) { +func (b *builder) rangeIndexed(fn *Function, x Value, tv types.Type, pos token.Pos) (k, v Value, loop, done *BasicBlock) { // // length = len(x) // index = -1 @@ -1623,7 +1627,7 @@ func (b *builder) rangeIndexed(fn *Function, x Value, tv types.Type) (k, v Value } index := fn.addLocal(tInt, token.NoPos) - emitStore(fn, index, intConst(-1)) + emitStore(fn, index, intConst(-1), pos) loop = fn.newBasicBlock("rangeindex.loop") emitJump(fn, loop) @@ -1635,7 +1639,7 @@ func (b *builder) rangeIndexed(fn *Function, x Value, tv types.Type) (k, v Value Y: vOne, } incr.setType(tInt) - emitStore(fn, index, fn.emit(incr)) + emitStore(fn, index, fn.emit(incr), pos) body := fn.newBasicBlock("rangeindex.body") done = fn.newBasicBlock("rangeindex.done") @@ -1814,10 +1818,10 @@ func (b *builder) rangeStmt(fn *Function, s *ast.RangeStmt, label *lblock) { var loop, done *BasicBlock switch rt := x.Type().Underlying().(type) { case *types.Slice, *types.Array, *types.Pointer: // *array - k, v, loop, done = b.rangeIndexed(fn, x, tv) + k, v, loop, done = b.rangeIndexed(fn, x, tv, s.For) case *types.Chan: - k, loop, done = b.rangeChan(fn, x, tk, s.TokPos) + k, loop, done = b.rangeChan(fn, x, tk, s.For) case *types.Map, *types.Basic: // string k, v, loop, done = b.rangeIter(fn, x, tk, tv, s.For) @@ -1955,7 +1959,7 @@ start: // Function has named result parameters (NRPs). // Perform parallel assignment of return operands to NRPs. for i, r := range results { - emitStore(fn, fn.namedResults[i], r) + emitStore(fn, fn.namedResults[i], r, s.Return) } } // Run function calls deferred in this @@ -2206,7 +2210,7 @@ func (p *Package) Build() { done = init.newBasicBlock("init.done") emitIf(init, emitLoad(init, initguard), done, doinit) init.currentBlock = doinit - emitStore(init, initguard, vTrue) + emitStore(init, initguard, vTrue, token.NoPos) // Call the init() function of each package we import. for _, pkg := range p.info.Pkg.Imports() { @@ -2234,7 +2238,7 @@ func (p *Package) Build() { // 1:1 initialization: var x, y = a(), b() var lval lvalue if v := varinit.Lhs[0]; v.Name() != "_" { - lval = &address{addr: p.values[v].(*Global)} + lval = &address{addr: p.values[v].(*Global), pos: v.Pos()} } else { lval = blank{} } @@ -2246,7 +2250,7 @@ func (p *Package) Build() { if v.Name() == "_" { continue } - emitStore(init, p.values[v].(*Global), emitExtract(init, tuple, i)) + emitStore(init, p.values[v].(*Global), emitExtract(init, tuple, i), v.Pos()) } } } diff --git a/go/ssa/emit.go b/go/ssa/emit.go index 84246c6b..261d6e04 100644 --- a/go/ssa/emit.go +++ b/go/ssa/emit.go @@ -246,10 +246,11 @@ func emitConv(f *Function, val Value, typ types.Type) Value { // emitStore emits to f an instruction to store value val at location // addr, applying implicit conversions as required by assignability rules. // -func emitStore(f *Function, addr, val Value) *Store { +func emitStore(f *Function, addr, val Value, pos token.Pos) *Store { s := &Store{ Addr: addr, Val: emitConv(f, val, deref(addr.Type())), + pos: pos, } f.emit(s) return s @@ -430,9 +431,9 @@ func zeroValue(f *Function, t types.Type) Value { } // emitMemClear emits to f code to zero the value pointed to by ptr. -func emitMemClear(f *Function, ptr Value) { +func emitMemClear(f *Function, ptr Value, pos token.Pos) { // TODO(adonovan): define and use a 'memclr' intrinsic for aggregate types. - emitStore(f, ptr, zeroValue(f, deref(ptr.Type()))) + emitStore(f, ptr, zeroValue(f, deref(ptr.Type())), pos) } // createRecoverBlock emits to f a block of code to return after a diff --git a/go/ssa/lvalue.go b/go/ssa/lvalue.go index e58bc247..8342645b 100644 --- a/go/ssa/lvalue.go +++ b/go/ssa/lvalue.go @@ -27,20 +27,19 @@ type lvalue interface { // An address is an lvalue represented by a true pointer. type address struct { - addr Value - starPos token.Pos // source position, if from explicit *addr - expr ast.Expr // source syntax [debug mode] + addr Value + pos token.Pos // source position + expr ast.Expr // source syntax [debug mode] } func (a *address) load(fn *Function) Value { load := emitLoad(fn, a.addr) - load.pos = a.starPos + load.pos = a.pos return load } func (a *address) store(fn *Function, v Value) { - store := emitStore(fn, a.addr, v) - store.pos = a.starPos + store := emitStore(fn, a.addr, v, a.pos) if a.expr != nil { // store.Val is v, converted for assignability. emitDebugRef(fn, a.expr, store.Val, false) diff --git a/go/ssa/ssa.go b/go/ssa/ssa.go index bc5e9da2..406611e5 100644 --- a/go/ssa/ssa.go +++ b/go/ssa/ssa.go @@ -564,8 +564,12 @@ type BinOp struct { // and a boolean indicating the success of the receive. The // components of the tuple are accessed using Extract. // -// Pos() returns the ast.UnaryExpr.OpPos or ast.RangeStmt.TokPos (for -// ranging over a channel), if explicit in the source. +// Pos() returns the ast.UnaryExpr.OpPos, if explicit in the source. +// For receive operations (ARROW) implicit in ranging over a channel, +// Pos() returns the ast.RangeStmt.For. +// For implicit memory loads (STAR), Pos() returns the position of the +// most closely associated source-level construct; the details are not +// specified. // // Example printed form: // t0 = *x @@ -1162,7 +1166,10 @@ type Send struct { // The Store instruction stores Val at address Addr. // Stores can be of arbitrary types. // -// Pos() returns the ast.StarExpr.Star, if explicit in the source. +// Pos() returns the position of the source-level construct most closely +// associated with the memory store operation. +// Since implicit memory stores are numerous and varied and depend upon +// implementation choices, the details are not specified. // // Example printed form: // *x = y diff --git a/go/ssa/testmain.go b/go/ssa/testmain.go index 422c7db9..ae9ec1c9 100644 --- a/go/ssa/testmain.go +++ b/go/ssa/testmain.go @@ -247,7 +247,7 @@ func testMainSlice(fn *Function, testfuncs []*Function, slice types.Type) Value pname := fn.emit(fa) // Emit: *pname = "testfunc" - emitStore(fn, pname, stringConst(testfunc.Name())) + emitStore(fn, pname, stringConst(testfunc.Name()), token.NoPos) // Emit: pfunc = &pitem.F fa = &FieldAddr{X: pitem, Field: 1} // .F @@ -255,7 +255,7 @@ func testMainSlice(fn *Function, testfuncs []*Function, slice types.Type) Value pfunc := fn.emit(fa) // Emit: *pfunc = testfunc - emitStore(fn, pfunc, testfunc) + emitStore(fn, pfunc, testfunc, token.NoPos) } // Emit: slice array[:]