mirror of
https://github.com/golang/go
synced 2024-11-18 21:05:02 -07: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:
parent
890e4c0731
commit
c8a6890a12
@ -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))
|
||||
@ -403,7 +403,6 @@ func (b *builder) addr(fn *Function, e ast.Expr, escaping bool) lvalue {
|
||||
return &address{
|
||||
addr: emitFieldSelection(fn, v, sel.Index()[last], true, e.Sel.Pos()),
|
||||
expr: e.Sel,
|
||||
object: sel.Obj(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -425,6 +424,7 @@ func (b *builder) addr(fn *Function, e ast.Expr, escaping bool) lvalue {
|
||||
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
|
||||
// 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()),
|
||||
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:
|
||||
|
4
ssa/interp/testdata/coverage.go
vendored
4
ssa/interp/testdata/coverage.go
vendored
@ -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
|
||||
|
@ -26,7 +26,6 @@ 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
|
||||
}
|
||||
|
||||
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 {
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user