From c8a6890a12cba10819c367a5d4c8b2d2ef24b2ed Mon Sep 17 00:00:00 2001 From: Alan Donovan Date: Thu, 22 Aug 2013 10:13:51 -0400 Subject: [PATCH] go.tools/ssa: fix a bug building SSA code for ast.CompositeLit. Map literals should use the same recursion logic as struct/array/slice literals to apply an implicit &-operator to the nested literals when a pointer is wanted. + test. Also: - ensure we set the source location for all Lookup and MapUpdate instructions. - remove obsolete address.object field. R=gri, crawshaw CC=golang-dev https://golang.org/cl/12787048 --- ssa/builder.go | 46 ++++++++++++++++++--------------- ssa/interp/testdata/coverage.go | 4 +++ ssa/lvalue.go | 13 ++++++---- ssa/ssa.go | 3 ++- 4 files changed, 39 insertions(+), 27 deletions(-) diff --git a/ssa/builder.go b/ssa/builder.go index 8b0019f164..5cf5639a98 100644 --- a/ssa/builder.go +++ b/ssa/builder.go @@ -370,7 +370,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, object: obj} + return &address{addr: v, expr: e} case *ast.CompositeLit: t := deref(fn.Pkg.typeOf(e)) @@ -401,9 +401,8 @@ func (b *builder) addr(fn *Function, e ast.Expr, escaping bool) lvalue { v := b.receiver(fn, e.X, wantAddr, escaping, sel) last := len(sel.Index()) - 1 return &address{ - addr: emitFieldSelection(fn, v, sel.Index()[last], true, e.Sel.Pos()), - expr: e.Sel, - object: sel.Obj(), + addr: emitFieldSelection(fn, v, sel.Index()[last], true, e.Sel.Pos()), + expr: e.Sel, } } @@ -422,9 +421,10 @@ func (b *builder) addr(fn *Function, e ast.Expr, escaping bool) lvalue { et = types.NewPointer(t.Elem()) case *types.Map: return &element{ - m: b.expr(fn, e.X), - k: emitConv(fn, b.expr(fn, e.Index), t.Key()), - t: t.Elem(), + m: b.expr(fn, e.X), + k: emitConv(fn, b.expr(fn, e.Index), t.Key()), + t: t.Elem(), + pos: e.Lbrack, } default: panic("unexpected container type in IndexExpr: " + t.String()) @@ -452,21 +452,25 @@ func (b *builder) addr(fn *Function, e ast.Expr, escaping bool) lvalue { // in an addressable location. // func (b *builder) exprInPlace(fn *Function, loc lvalue, e ast.Expr) { - if _, ok := loc.(*address); ok { - if e, ok := e.(*ast.CompositeLit); ok { - typ := loc.typ() - switch typ.Underlying().(type) { - case *types.Pointer: // implicit & -- possibly escaping + if e, ok := e.(*ast.CompositeLit); ok { + // A CompositeLit never evaluates to a pointer, + // so if the type of the location is a pointer, + // an &-operation is implied. + if _, ok := loc.(blank); !ok { // avoid calling blank.typ() + if isPointer(loc.typ()) { ptr := b.addr(fn, e, true).address(fn) loc.store(fn, ptr) // copy address return + } + } - case *types.Interface: + if _, ok := loc.(*address); ok { + typ := loc.typ() + if _, ok := typ.Underlying().(*types.Interface); ok { // e.g. var x interface{} = T{...} // Can't in-place initialize an interface value. // Fall back to copying. - - default: + } else { b.compLit(fn, loc.address(fn), e, typ) // in place return } @@ -1246,13 +1250,13 @@ func (b *builder) compLit(fn *Function, addr Value, e *ast.CompositeLit, typ typ emitStore(fn, addr, fn.emit(m)) for _, e := range e.Elts { e := e.(*ast.KeyValueExpr) - up := &MapUpdate{ - Map: m, - Key: emitConv(fn, b.expr(fn, e.Key), t.Key()), - Value: emitConv(fn, b.expr(fn, e.Value), t.Elem()), - pos: e.Colon, + loc := &element{ + m: m, + k: emitConv(fn, b.expr(fn, e.Key), t.Key()), + t: t.Elem(), + pos: e.Colon, } - fn.emit(up) + b.exprInPlace(fn, loc, e.Value) } case *types.Pointer: diff --git a/ssa/interp/testdata/coverage.go b/ssa/interp/testdata/coverage.go index e9dc3d1669..682bfb3106 100644 --- a/ssa/interp/testdata/coverage.go +++ b/ssa/interp/testdata/coverage.go @@ -271,6 +271,10 @@ func main() { if v, ok := map[string]string{}["foo5"]; v != "" || ok { panic("oops") } + + // Regression test: implicit address-taken struct literal + // inside literal map element. + _ = map[int]*struct{}{0: {}} } type mybool bool diff --git a/ssa/lvalue.go b/ssa/lvalue.go index 449d0bcc9d..48ccf8db90 100644 --- a/ssa/lvalue.go +++ b/ssa/lvalue.go @@ -24,9 +24,8 @@ 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] - object types.Object // source var, if from *ast.Ident + starPos token.Pos // source position, if from explicit *addr + expr ast.Expr // source syntax [debug mode] } func (a *address) load(fn *Function) Value { @@ -64,6 +63,7 @@ func (a *address) typ() types.Type { type element struct { m, k Value // map or string t types.Type // map element type or string byte type + pos token.Pos // source position of colon ({k:v}) or lbrack (m[k]=v) } func (e *element) load(fn *Function) Value { @@ -71,16 +71,19 @@ func (e *element) load(fn *Function) Value { X: e.m, Index: e.k, } + l.setPos(e.pos) l.setType(e.t) return fn.emit(l) } func (e *element) store(fn *Function, v Value) { - fn.emit(&MapUpdate{ + up := &MapUpdate{ Map: e.m, Key: e.k, Value: emitConv(fn, v, e.t), - }) + } + up.pos = e.pos + fn.emit(up) } func (e *element) address(fn *Function) Value { diff --git a/ssa/ssa.go b/ssa/ssa.go index c73cc87373..4dfe2c671e 100644 --- a/ssa/ssa.go +++ b/ssa/ssa.go @@ -1121,7 +1121,8 @@ type Store struct { // The MapUpdate instruction updates the association of Map[Key] to // Value. // -// Pos() returns the ast.KeyValueExpr.Colon, if explicit in the source. +// Pos() returns the ast.KeyValueExpr.Colon or ast.IndexExpr.Lbrack, +// if explicit in the source. // // Example printed form: // t0[t1] = t2