go.tools/ssa: fix builder crash in select { case n, _ := <-c: ... }.

Cause: emitExtract requires a type for each component of the
receive tuple; blank supplies no such type.

Solution: remove type parameter for emitExtract as it is no
longer needed: since rev b75cc03b4a56 it is always identical
to the tuple.Type().At(index).

+ tests.

Fixes golang/go#6806.

R=gri, gri
CC=axwalk, golang-dev
https://golang.org/cl/30410043
This commit is contained in:
Alan Donovan 2013-11-21 15:38:58 -05:00
parent 8f1fdf33de
commit cf7368c879
3 changed files with 45 additions and 27 deletions

View File

@ -855,7 +855,7 @@ func (b *builder) emitCallArgs(fn *Function, sig *types.Signature, e *ast.CallEx
v := b.expr(fn, arg)
if ttuple, ok := v.Type().(*types.Tuple); ok { // MRV chain
for i, n := 0, ttuple.Len(); i < n; i++ {
args = append(args, emitExtract(fn, v, i, ttuple.At(i).Type()))
args = append(args, emitExtract(fn, v, i))
}
} else {
args = append(args, v)
@ -955,12 +955,11 @@ func (b *builder) localValueSpec(fn *Function, spec *ast.ValueSpec) {
default:
// e.g. var x, y = pos()
tuple := b.exprN(fn, spec.Values[0])
result := tuple.Type().(*types.Tuple)
for i, id := range spec.Names {
if !isBlankIdent(id) {
fn.addLocalForIdent(id)
lhs := b.addr(fn, id, false) // non-escaping
lhs.store(fn, emitExtract(fn, tuple, i, result.At(i).Type()))
lhs.store(fn, emitExtract(fn, tuple, i))
}
}
}
@ -1012,9 +1011,8 @@ func (b *builder) assignStmt(fn *Function, lhss, rhss []ast.Expr, isDef bool) {
} else {
// e.g. x, y = pos()
tuple := b.exprN(fn, rhss[0])
result := tuple.Type().(*types.Tuple)
for i, lval := range lvals {
lval.store(fn, emitExtract(fn, tuple, i, result.At(i).Type()))
lval.store(fn, emitExtract(fn, tuple, i))
}
}
}
@ -1307,8 +1305,8 @@ func (b *builder) typeSwitchStmt(fn *Function, s *ast.TypeSwitchStmt, label *lbl
ti = x
} else {
yok := emitTypeTest(fn, x, casetype, cc.Case)
ti = emitExtract(fn, yok, 0, casetype)
condv = emitExtract(fn, yok, 1, tBool)
ti = emitExtract(fn, yok, 0)
condv = emitExtract(fn, yok, 1)
}
emitIf(fn, condv, body, next)
fn.currentBlock = next
@ -1451,7 +1449,7 @@ func (b *builder) selectStmt(fn *Function, s *ast.SelectStmt, label *lblock) {
sel.setType(types.NewTuple(vars...))
fn.emit(sel)
idx := emitExtract(fn, sel, 0, tInt)
idx := emitExtract(fn, sel, 0)
done := fn.newBasicBlock("select.done")
if label != nil {
@ -1478,7 +1476,7 @@ func (b *builder) selectStmt(fn *Function, s *ast.SelectStmt, label *lblock) {
switch comm := clause.Comm.(type) {
case *ast.ExprStmt: // <-ch
if debugInfo {
v := emitExtract(fn, sel, r, vars[r].Type())
v := emitExtract(fn, sel, r)
emitDebugRef(fn, states[state].DebugNode.(ast.Expr), v, false)
}
r++
@ -1488,7 +1486,7 @@ func (b *builder) selectStmt(fn *Function, s *ast.SelectStmt, label *lblock) {
fn.addLocalForIdent(comm.Lhs[0].(*ast.Ident))
}
x := b.addr(fn, comm.Lhs[0], false) // non-escaping
v := emitExtract(fn, sel, r, vars[r].Type())
v := emitExtract(fn, sel, r)
if debugInfo {
emitDebugRef(fn, states[state].DebugNode.(ast.Expr), v, false)
}
@ -1499,7 +1497,7 @@ func (b *builder) selectStmt(fn *Function, s *ast.SelectStmt, label *lblock) {
fn.addLocalForIdent(comm.Lhs[1].(*ast.Ident))
}
ok := b.addr(fn, comm.Lhs[1], false) // non-escaping
ok.store(fn, emitExtract(fn, sel, 1, deref(ok.typ())))
ok.store(fn, emitExtract(fn, sel, 1))
}
r++
}
@ -1717,14 +1715,14 @@ func (b *builder) rangeIter(fn *Function, x Value, tk, tv types.Type, pos token.
body := fn.newBasicBlock("rangeiter.body")
done = fn.newBasicBlock("rangeiter.done")
emitIf(fn, emitExtract(fn, okv, 0, tBool), body, done)
emitIf(fn, emitExtract(fn, okv, 0), body, done)
fn.currentBlock = body
if tk != tInvalid {
k = emitExtract(fn, okv, 1, tk)
k = emitExtract(fn, okv, 1)
}
if tv != tInvalid {
v = emitExtract(fn, okv, 2, tv)
v = emitExtract(fn, okv, 2)
}
return
}
@ -1763,10 +1761,10 @@ func (b *builder) rangeChan(fn *Function, x Value, tk types.Type, pos token.Pos)
ko := fn.emit(recv)
body := fn.newBasicBlock("rangechan.body")
done = fn.newBasicBlock("rangechan.done")
emitIf(fn, emitExtract(fn, ko, 1, tBool), body, done)
emitIf(fn, emitExtract(fn, ko, 1), body, done)
fn.currentBlock = body
if tk != nil {
k = emitExtract(fn, ko, 0, tk)
k = emitExtract(fn, ko, 0)
}
return
}
@ -1952,7 +1950,7 @@ start:
ttuple := tuple.Type().(*types.Tuple)
for i, n := 0, ttuple.Len(); i < n; i++ {
results = append(results,
emitConv(fn, emitExtract(fn, tuple, i, ttuple.At(i).Type()),
emitConv(fn, emitExtract(fn, tuple, i),
fn.Signature.Results().At(i).Type()))
}
} else {
@ -2239,13 +2237,11 @@ func (p *Package) Build() {
} else {
// n:1 initialization: var x, y := f()
tuple := b.exprN(init, varinit.Rhs)
result := tuple.Type().(*types.Tuple)
for i, v := range varinit.Lhs {
if v.Name() == "_" {
continue
}
emitStore(init, p.values[v].(*Global),
emitExtract(init, tuple, i, result.At(i).Type()))
emitStore(init, p.values[v].(*Global), emitExtract(init, tuple, i))
}
}
}

View File

@ -268,14 +268,11 @@ func emitIf(f *Function, cond Value, tblock, fblock *BasicBlock) {
}
// emitExtract emits to f an instruction to extract the index'th
// component of tuple, ascribing it type typ. It returns the
// extracted value.
// component of tuple. It returns the extracted value.
//
func emitExtract(f *Function, tuple Value, index int, typ types.Type) Value {
func emitExtract(f *Function, tuple Value, index int) Value {
e := &Extract{Tuple: tuple, Index: index}
// In all cases but one (tSelect's recv), typ is redundant w.r.t.
// tuple.Type().(*types.Tuple).Values[index].Type.
e.setType(typ)
e.setType(tuple.Type().(*types.Tuple).At(index).Type())
return f.emit(e)
}
@ -329,7 +326,7 @@ func emitTailCall(f *Function, call *Call) {
ret.Results = []Value{tuple}
default:
for i := 0; i < nr; i++ {
v := emitExtract(f, tuple, i, tresults.At(i).Type())
v := emitExtract(f, tuple, i)
// TODO(adonovan): in principle, this is required:
// v = emitConv(f, o.Type, f.Signature.Results[i].Type)
// but in practice emitTailCall is only used when

View File

@ -571,3 +571,28 @@ func init() {
panic(ints)
}
}
func init() {
// Regression test for issue 6806.
ch := make(chan int)
select {
case n, _ := <-ch:
_ = n
default:
// The default case disables the simplification of
// select to a simple receive statement.
}
// value,ok-form receive where TypeOf(ok) is a named boolean.
type mybool bool
var x int
var y mybool
select {
case x, y = <-ch:
default:
// The default case disables the simplification of
// select to a simple receive statement.
}
_ = x
_ = y
}