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:
parent
8f1fdf33de
commit
cf7368c879
|
|
@ -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()))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
11
ssa/emit.go
11
ssa/emit.go
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue