From de47ebac4bb2750ce488a2e7595a1cec6a06ffc6 Mon Sep 17 00:00:00 2001 From: Alan Donovan Date: Tue, 27 Aug 2013 11:18:31 -0400 Subject: [PATCH] go.tools/ssa: fix bad type info in 'for _ = range channel'. Previously, if the result was not wanted, the received (value, ok) tuple had no type for 'value'. Now it is always set to the channel's element type. Also: set the position on such receive instructions to that of the = or := token, and document it. + (indirect) test via pointer analysis. R=crawshaw, gri CC=golang-dev https://golang.org/cl/12956052 --- pointer/testdata/channels.go | 7 +++++++ ssa/builder.go | 8 +++++--- ssa/ssa.go | 3 ++- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/pointer/testdata/channels.go b/pointer/testdata/channels.go index b7962558..001d7d23 100644 --- a/pointer/testdata/channels.go +++ b/pointer/testdata/channels.go @@ -81,6 +81,13 @@ func chan4() { print(chA) // @pointsto makechan@c4makeA:13 print(chB) // @pointsto makechan@c4makeB:13 } + + for k := range chA { + print(k) // @pointsto main.incr + } + // Exercise constraint generation (regtest for a crash). + for _ = range chA { + } } func main() { diff --git a/ssa/builder.go b/ssa/builder.go index 5cf5639a..fe4f7d64 100644 --- a/ssa/builder.go +++ b/ssa/builder.go @@ -1868,8 +1868,9 @@ func (b *builder) rangeIter(fn *Function, x Value, tk, tv types.Type, pos token. // channel x until it fails. // tk is the channel's element type, or nil if the k result is // not wanted +// pos is the position of the '=' or ':=' token. // -func (b *builder) rangeChan(fn *Function, x Value, tk types.Type) (k Value, loop, done *BasicBlock) { +func (b *builder) rangeChan(fn *Function, x Value, tk types.Type, pos token.Pos) (k Value, loop, done *BasicBlock) { // // loop: (target of continue) // ko = <-x (key, ok) @@ -1889,8 +1890,9 @@ func (b *builder) rangeChan(fn *Function, x Value, tk types.Type) (k Value, loop X: x, CommaOk: true, } + recv.setPos(pos) recv.setType(types.NewTuple( - types.NewVar(token.NoPos, nil, "k", tk), + types.NewVar(token.NoPos, nil, "k", x.Type().Underlying().(*types.Chan).Elem()), varOk, )) ko := fn.emit(recv) @@ -1940,7 +1942,7 @@ func (b *builder) rangeStmt(fn *Function, s *ast.RangeStmt, label *lblock) { k, v, loop, done = b.rangeIndexed(fn, x, tv) case *types.Chan: - k, loop, done = b.rangeChan(fn, x, tk) + k, loop, done = b.rangeChan(fn, x, tk, s.TokPos) case *types.Map, *types.Basic: // string k, v, loop, done = b.rangeIter(fn, x, tk, tv, s.For) diff --git a/ssa/ssa.go b/ssa/ssa.go index 4dfe2c67..1300fcbf 100644 --- a/ssa/ssa.go +++ b/ssa/ssa.go @@ -508,7 +508,8 @@ type BinOp struct { // and a boolean indicating the success of the receive. The // components of the tuple are accessed using Extract. // -// Pos() returns the ast.UnaryExpr.OpPos, if explicit in the source, +// Pos() returns the ast.UnaryExpr.OpPos or ast.RangeStmt.TokPos (for +// ranging over a channel), if explicit in the source. // // Example printed form: // t0 = *x