From cf7368c8793cb850c86266d7a8bdabb63f9ec321 Mon Sep 17 00:00:00 2001 From: Alan Donovan Date: Thu, 21 Nov 2013 15:38:58 -0500 Subject: [PATCH] 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 --- ssa/builder.go | 36 +++++++++++++++------------------ ssa/emit.go | 11 ++++------ ssa/interp/testdata/coverage.go | 25 +++++++++++++++++++++++ 3 files changed, 45 insertions(+), 27 deletions(-) diff --git a/ssa/builder.go b/ssa/builder.go index 3d1c6325..2686f9cb 100644 --- a/ssa/builder.go +++ b/ssa/builder.go @@ -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)) } } } diff --git a/ssa/emit.go b/ssa/emit.go index 900fb0e7..95bf5713 100644 --- a/ssa/emit.go +++ b/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 -// 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 diff --git a/ssa/interp/testdata/coverage.go b/ssa/interp/testdata/coverage.go index 1887de6c..235992b1 100644 --- a/ssa/interp/testdata/coverage.go +++ b/ssa/interp/testdata/coverage.go @@ -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 +}