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:
parent
890e4c0731
commit
c8a6890a12
|
@ -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:
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue