diff --git a/compiler/compiler.go b/compiler/compiler.go index c6e577fd6..e34ac978e 100644 --- a/compiler/compiler.go +++ b/compiler/compiler.go @@ -964,11 +964,59 @@ func (b *builder) createFunction() { } } +// posser is an interface that's implemented by both ssa.Value and +// ssa.Instruction. It is implemented by everything that has a Pos() method, +// which is all that getPos() needs. +type posser interface { + Pos() token.Pos +} + +// getPos returns position information for a ssa.Value or ssa.Instruction. +// +// Not all instructions have position information, especially when they're +// implicit (such as implicit casts or implicit returns at the end of a +// function). In these cases, it makes sense to try a bit harder to guess what +// the position really should be. +func getPos(val posser) token.Pos { + pos := val.Pos() + if pos != token.NoPos { + // Easy: position is known. + return pos + } + + // No position information is known. + switch val := val.(type) { + case *ssa.MakeInterface: + return getPos(val.X) + case *ssa.Return: + syntax := val.Parent().Syntax() + if syntax != nil { + // non-synthetic + return syntax.End() + } + return token.NoPos + case *ssa.FieldAddr: + return getPos(val.X) + case *ssa.IndexAddr: + return getPos(val.X) + case *ssa.Slice: + return getPos(val.X) + case *ssa.Store: + return getPos(val.Addr) + case *ssa.Extract: + return getPos(val.Tuple) + default: + // This is reachable, for example with *ssa.Const, *ssa.If, and + // *ssa.Jump. They might be implemented in some way in the future. + return token.NoPos + } +} + // createInstruction builds the LLVM IR equivalent instructions for the // particular Go SSA instruction. func (b *builder) createInstruction(instr ssa.Instruction) { if b.Debug { - pos := b.program.Fset.Position(instr.Pos()) + pos := b.program.Fset.Position(getPos(instr)) b.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), b.difunc, llvm.Metadata{}) } diff --git a/transform/testdata/allocs2.go b/transform/testdata/allocs2.go index 3e1df07df..aeddcf6ba 100644 --- a/transform/testdata/allocs2.go +++ b/transform/testdata/allocs2.go @@ -24,11 +24,24 @@ func main() { readByteSlice(s4) s5 := make([]int, 4) // OUT: object allocated on the heap: escapes at line 27 - s5 = append(s5, 5) + _ = append(s5, 5) s6 := make([]int, 3) s7 := []int{1, 2, 3} copySlice(s6, s7) + + c1 := getComplex128() // OUT: object allocated on the heap: escapes at line 34 + useInterface(c1) + + n3 := 5 // OUT: object allocated on the heap: escapes at line 39 + func() int { + return n3 + }() + + callVariadic(3, 5, 8) // OUT: object allocated on the heap: escapes at line 41 + + s8 := []int{3, 5, 8} // OUT: object allocated on the heap: escapes at line 44 + callVariadic(s8...) } func derefInt(x *int) int { @@ -56,3 +69,9 @@ func getUnknownNumber() int func copySlice(out, in []int) { copy(out, in) } + +func getComplex128() complex128 + +func useInterface(interface{}) + +func callVariadic(...int)