1
0
mirror of https://github.com/golang/go synced 2024-10-01 03:08:33 -06:00

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 {
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:

View File

@ -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

View File

@ -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 {

View File

@ -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