mirror of https://github.com/golang/go.git
go.tools/ssa: fix crash on 'select { case x, ok = <-ch: }' (= not :=).
Added test. Also: - abstracted Function.addLocalForIdent (9 calls). - remove vestige of old typeswitch hack. - specify and fix CallCommon.Signature() for calls to built-ins. R=gri CC=golang-dev https://golang.org/cl/10884044
This commit is contained in:
parent
997111ba7d
commit
ea8ba6f45b
|
|
@ -1119,7 +1119,7 @@ func (b *builder) localValueSpec(fn *Function, spec *ast.ValueSpec) {
|
|||
for i, id := range spec.Names {
|
||||
var lval lvalue = blank{}
|
||||
if !isBlankIdent(id) {
|
||||
lval = address{addr: fn.addNamedLocal(fn.Pkg.objectOf(id))}
|
||||
lval = address{addr: fn.addLocalForIdent(id)}
|
||||
}
|
||||
b.exprInPlace(fn, lval, spec.Values[i])
|
||||
}
|
||||
|
|
@ -1129,7 +1129,7 @@ func (b *builder) localValueSpec(fn *Function, spec *ast.ValueSpec) {
|
|||
// Locals are implicitly zero-initialized.
|
||||
for _, id := range spec.Names {
|
||||
if !isBlankIdent(id) {
|
||||
fn.addNamedLocal(fn.Pkg.objectOf(id))
|
||||
fn.addLocalForIdent(id)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1139,7 +1139,7 @@ func (b *builder) localValueSpec(fn *Function, spec *ast.ValueSpec) {
|
|||
result := tuple.Type().(*types.Tuple)
|
||||
for i, id := range spec.Names {
|
||||
if !isBlankIdent(id) {
|
||||
lhs := fn.addNamedLocal(fn.Pkg.objectOf(id))
|
||||
lhs := fn.addLocalForIdent(id)
|
||||
emitStore(fn, lhs, emitExtract(fn, tuple, i, result.At(i).Type()))
|
||||
}
|
||||
}
|
||||
|
|
@ -1446,16 +1446,13 @@ func (b *builder) typeSwitchStmt(fn *Function, s *ast.TypeSwitchStmt, label *lbl
|
|||
b.stmt(fn, s.Init)
|
||||
}
|
||||
|
||||
var x, y Value
|
||||
var id *ast.Ident
|
||||
var x Value
|
||||
switch ass := s.Assign.(type) {
|
||||
case *ast.ExprStmt: // x.(type)
|
||||
x = b.expr(fn, unparen(ass.X).(*ast.TypeAssertExpr).X)
|
||||
case *ast.AssignStmt: // y := x.(type)
|
||||
x = b.expr(fn, unparen(ass.Rhs[0]).(*ast.TypeAssertExpr).X)
|
||||
id = ass.Lhs[0].(*ast.Ident)
|
||||
y = fn.addNamedLocal(fn.Pkg.objectOf(id))
|
||||
emitStore(fn, y, x)
|
||||
emitStore(fn, fn.addLocalForIdent(ass.Lhs[0].(*ast.Ident)), x)
|
||||
}
|
||||
|
||||
done := fn.newBasicBlock("typeswitch.done")
|
||||
|
|
@ -1488,10 +1485,10 @@ func (b *builder) typeSwitchStmt(fn *Function, s *ast.TypeSwitchStmt, label *lbl
|
|||
fn.currentBlock = next
|
||||
}
|
||||
fn.currentBlock = body
|
||||
if id != nil && len(cc.List) == 1 && casetype != tUntypedNil {
|
||||
if obj := fn.Pkg.info.TypeCaseVar(cc); obj != nil {
|
||||
// Declare a new shadow local variable of the
|
||||
// same name but a more specific type.
|
||||
y2 := fn.addNamedLocal(fn.Pkg.info.TypeCaseVar(cc))
|
||||
y2 := fn.addNamedLocal(obj)
|
||||
y2.name += "'" // debugging aid
|
||||
y2.typ = pointer(casetype)
|
||||
emitStore(fn, y2, ti)
|
||||
|
|
@ -1502,9 +1499,6 @@ func (b *builder) typeSwitchStmt(fn *Function, s *ast.TypeSwitchStmt, label *lbl
|
|||
}
|
||||
b.stmtList(fn, cc.Body)
|
||||
fn.targets = fn.targets.tail
|
||||
if id != nil {
|
||||
fn.objects[fn.Pkg.objectOf(id)] = y // restore previous y binding
|
||||
}
|
||||
emitJump(fn, done)
|
||||
fn.currentBlock = next
|
||||
}
|
||||
|
|
@ -1634,12 +1628,18 @@ func (b *builder) selectStmt(fn *Function, s *ast.SelectStmt, label *lblock) {
|
|||
r++
|
||||
|
||||
case *ast.AssignStmt: // x := <-states[state].Chan
|
||||
xdecl := fn.addNamedLocal(fn.Pkg.objectOf(comm.Lhs[0].(*ast.Ident)))
|
||||
emitStore(fn, xdecl, emitExtract(fn, sel, r, vars[r].Type()))
|
||||
if comm.Tok == token.DEFINE {
|
||||
fn.addLocalForIdent(comm.Lhs[0].(*ast.Ident))
|
||||
}
|
||||
x := b.addr(fn, comm.Lhs[0], false) // non-escaping
|
||||
x.store(fn, emitExtract(fn, sel, r, vars[r].Type()))
|
||||
|
||||
if len(comm.Lhs) == 2 { // x, ok := ...
|
||||
okdecl := fn.addNamedLocal(fn.Pkg.objectOf(comm.Lhs[1].(*ast.Ident)))
|
||||
emitStore(fn, okdecl, emitExtract(fn, sel, 1, okdecl.Type().Deref()))
|
||||
if comm.Tok == token.DEFINE {
|
||||
fn.addLocalForIdent(comm.Lhs[1].(*ast.Ident))
|
||||
}
|
||||
ok := b.addr(fn, comm.Lhs[1], false) // non-escaping
|
||||
ok.store(fn, emitExtract(fn, sel, 1, ok.typ().Deref()))
|
||||
}
|
||||
r++
|
||||
}
|
||||
|
|
@ -1929,10 +1929,10 @@ func (b *builder) rangeStmt(fn *Function, s *ast.RangeStmt, label *lblock) {
|
|||
// always creates a new one.
|
||||
if s.Tok == token.DEFINE {
|
||||
if tk != nil {
|
||||
fn.addNamedLocal(fn.Pkg.objectOf(s.Key.(*ast.Ident)))
|
||||
fn.addLocalForIdent(s.Key.(*ast.Ident))
|
||||
}
|
||||
if tv != nil {
|
||||
fn.addNamedLocal(fn.Pkg.objectOf(s.Value.(*ast.Ident)))
|
||||
fn.addLocalForIdent(s.Value.(*ast.Ident))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -256,7 +256,7 @@ func (f *Function) createSyntacticParams() {
|
|||
for _, field := range f.syntax.resultFields.List {
|
||||
// Implicit "var" decl of locals for named results.
|
||||
for _, n := range field.Names {
|
||||
f.namedResults = append(f.namedResults, f.addNamedLocal(f.Pkg.objectOf(n)))
|
||||
f.namedResults = append(f.namedResults, f.addLocalForIdent(n))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -386,6 +386,10 @@ func (f *Function) addNamedLocal(obj types.Object) *Alloc {
|
|||
return l
|
||||
}
|
||||
|
||||
func (f *Function) addLocalForIdent(id *ast.Ident) *Alloc {
|
||||
return f.addNamedLocal(f.Pkg.objectOf(id))
|
||||
}
|
||||
|
||||
// addLocal creates an anonymous local variable of type typ, adds it
|
||||
// to function f and returns it. pos is the optional source location.
|
||||
//
|
||||
|
|
|
|||
|
|
@ -180,6 +180,14 @@ func main() {
|
|||
if <-ch != 1 {
|
||||
panic("couldn't receive")
|
||||
}
|
||||
// A "receive" select-case that doesn't declare its vars. (regression test)
|
||||
anint := 0
|
||||
ok := false
|
||||
select {
|
||||
case anint, ok = <-ch:
|
||||
case anint = <-ch:
|
||||
default:
|
||||
}
|
||||
|
||||
// Anon structs with methods.
|
||||
anon := struct{ T }{T: T{z: 1}}
|
||||
|
|
|
|||
|
|
@ -1235,12 +1235,15 @@ func (c *CallCommon) Pos() token.Pos { return c.pos }
|
|||
// In either "call" or "invoke" mode, if the callee is a method, its
|
||||
// receiver is represented by sig.Recv, not sig.Params().At(0).
|
||||
//
|
||||
// Signature returns nil for a call to a built-in function.
|
||||
//
|
||||
func (c *CallCommon) Signature() *types.Signature {
|
||||
if c.Recv != nil {
|
||||
iface := c.Recv.Type().Underlying().(*types.Interface)
|
||||
return iface.Method(c.Method).Type().(*types.Signature)
|
||||
}
|
||||
return c.Func.Type().Underlying().(*types.Signature)
|
||||
sig, _ := c.Func.Type().Underlying().(*types.Signature) // nil for *Builtin
|
||||
return sig
|
||||
}
|
||||
|
||||
// StaticCallee returns the called function if this is a trivially
|
||||
|
|
|
|||
Loading…
Reference in New Issue