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

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

View File

@ -571,3 +571,28 @@ func init() {
panic(ints) 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
}