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
This commit is contained in:
Alan Donovan 2013-08-22 10:13:51 -04:00
parent 890e4c0731
commit c8a6890a12
4 changed files with 39 additions and 27 deletions

View File

@ -370,7 +370,7 @@ func (b *builder) addr(fn *Function, e ast.Expr, escaping bool) lvalue {
if v == nil { if v == nil {
v = fn.lookup(obj, escaping) v = fn.lookup(obj, escaping)
} }
return &address{addr: v, expr: e, object: obj} return &address{addr: v, expr: e}
case *ast.CompositeLit: case *ast.CompositeLit:
t := deref(fn.Pkg.typeOf(e)) 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) v := b.receiver(fn, e.X, wantAddr, escaping, sel)
last := len(sel.Index()) - 1 last := len(sel.Index()) - 1
return &address{ return &address{
addr: emitFieldSelection(fn, v, sel.Index()[last], true, e.Sel.Pos()), addr: emitFieldSelection(fn, v, sel.Index()[last], true, e.Sel.Pos()),
expr: e.Sel, expr: e.Sel,
object: sel.Obj(),
} }
} }
@ -422,9 +421,10 @@ func (b *builder) addr(fn *Function, e ast.Expr, escaping bool) lvalue {
et = types.NewPointer(t.Elem()) et = types.NewPointer(t.Elem())
case *types.Map: case *types.Map:
return &element{ return &element{
m: b.expr(fn, e.X), m: b.expr(fn, e.X),
k: emitConv(fn, b.expr(fn, e.Index), t.Key()), k: emitConv(fn, b.expr(fn, e.Index), t.Key()),
t: t.Elem(), t: t.Elem(),
pos: e.Lbrack,
} }
default: default:
panic("unexpected container type in IndexExpr: " + t.String()) 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. // in an addressable location.
// //
func (b *builder) exprInPlace(fn *Function, loc lvalue, e ast.Expr) { func (b *builder) exprInPlace(fn *Function, loc lvalue, e ast.Expr) {
if _, ok := loc.(*address); ok { if e, ok := e.(*ast.CompositeLit); ok {
if e, ok := e.(*ast.CompositeLit); ok { // A CompositeLit never evaluates to a pointer,
typ := loc.typ() // so if the type of the location is a pointer,
switch typ.Underlying().(type) { // an &-operation is implied.
case *types.Pointer: // implicit & -- possibly escaping if _, ok := loc.(blank); !ok { // avoid calling blank.typ()
if isPointer(loc.typ()) {
ptr := b.addr(fn, e, true).address(fn) ptr := b.addr(fn, e, true).address(fn)
loc.store(fn, ptr) // copy address loc.store(fn, ptr) // copy address
return 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{...} // e.g. var x interface{} = T{...}
// Can't in-place initialize an interface value. // Can't in-place initialize an interface value.
// Fall back to copying. // Fall back to copying.
} else {
default:
b.compLit(fn, loc.address(fn), e, typ) // in place b.compLit(fn, loc.address(fn), e, typ) // in place
return return
} }
@ -1246,13 +1250,13 @@ func (b *builder) compLit(fn *Function, addr Value, e *ast.CompositeLit, typ typ
emitStore(fn, addr, fn.emit(m)) emitStore(fn, addr, fn.emit(m))
for _, e := range e.Elts { for _, e := range e.Elts {
e := e.(*ast.KeyValueExpr) e := e.(*ast.KeyValueExpr)
up := &MapUpdate{ loc := &element{
Map: m, m: m,
Key: emitConv(fn, b.expr(fn, e.Key), t.Key()), k: emitConv(fn, b.expr(fn, e.Key), t.Key()),
Value: emitConv(fn, b.expr(fn, e.Value), t.Elem()), t: t.Elem(),
pos: e.Colon, pos: e.Colon,
} }
fn.emit(up) b.exprInPlace(fn, loc, e.Value)
} }
case *types.Pointer: case *types.Pointer:

View File

@ -271,6 +271,10 @@ func main() {
if v, ok := map[string]string{}["foo5"]; v != "" || ok { if v, ok := map[string]string{}["foo5"]; v != "" || ok {
panic("oops") panic("oops")
} }
// Regression test: implicit address-taken struct literal
// inside literal map element.
_ = map[int]*struct{}{0: {}}
} }
type mybool bool type mybool bool

View File

@ -24,9 +24,8 @@ type lvalue interface {
// An address is an lvalue represented by a true pointer. // An address is an lvalue represented by a true pointer.
type address struct { type address struct {
addr Value addr Value
starPos token.Pos // source position, if from explicit *addr starPos token.Pos // source position, if from explicit *addr
expr ast.Expr // source syntax [debug mode] expr ast.Expr // source syntax [debug mode]
object types.Object // source var, if from *ast.Ident
} }
func (a *address) load(fn *Function) Value { func (a *address) load(fn *Function) Value {
@ -64,6 +63,7 @@ func (a *address) typ() types.Type {
type element struct { type element struct {
m, k Value // map or string m, k Value // map or string
t types.Type // map element type or string byte type 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 { func (e *element) load(fn *Function) Value {
@ -71,16 +71,19 @@ func (e *element) load(fn *Function) Value {
X: e.m, X: e.m,
Index: e.k, Index: e.k,
} }
l.setPos(e.pos)
l.setType(e.t) l.setType(e.t)
return fn.emit(l) return fn.emit(l)
} }
func (e *element) store(fn *Function, v Value) { func (e *element) store(fn *Function, v Value) {
fn.emit(&MapUpdate{ up := &MapUpdate{
Map: e.m, Map: e.m,
Key: e.k, Key: e.k,
Value: emitConv(fn, v, e.t), Value: emitConv(fn, v, e.t),
}) }
up.pos = e.pos
fn.emit(up)
} }
func (e *element) address(fn *Function) Value { func (e *element) address(fn *Function) Value {

View File

@ -1121,7 +1121,8 @@ type Store struct {
// The MapUpdate instruction updates the association of Map[Key] to // The MapUpdate instruction updates the association of Map[Key] to
// Value. // 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: // Example printed form:
// t0[t1] = t2 // t0[t1] = t2