Skip to content

Commit 1c6ef9a

Browse files
committed
cmd/compile: copy literals when inlining
Without this, literals keep their original source positions through inlining, which results in strange jumps in line numbers of inlined function bodies. By copying literals, inlining can update their source position like other nodes. Fixes #15453. Change-Id: Iad5d9bbfe183883794213266dc30e31bab89ee69 Reviewed-on: https://go-review.googlesource.com/37232 Run-TryBot: David Lazar <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Matthew Dempsky <[email protected]> Reviewed-by: Russ Cox <[email protected]>
1 parent 699175a commit 1c6ef9a

File tree

2 files changed

+77
-16
lines changed

2 files changed

+77
-16
lines changed

src/cmd/compile/internal/gc/inl.go

+27-16
Original file line numberDiff line numberDiff line change
@@ -977,7 +977,12 @@ func (subst *inlsubst) node(n *Node) *Node {
977977
return n
978978

979979
case OLITERAL, OTYPE:
980-
return n
980+
// If n is a named constant or type, we can continue
981+
// using it in the inline copy. Otherwise, make a copy
982+
// so we can update the line number.
983+
if n.Sym != nil {
984+
return n
985+
}
981986

982987
// Since we don't handle bodies with closures, this return is guaranteed to belong to the current inlined function.
983988

@@ -1015,24 +1020,24 @@ func (subst *inlsubst) node(n *Node) *Node {
10151020
m.Left = newname(lookup(p))
10161021

10171022
return m
1018-
default:
1019-
m := nod(OXXX, nil, nil)
1020-
*m = *n
1021-
m.Ninit.Set(nil)
1022-
1023-
if n.Op == OCLOSURE {
1024-
Fatalf("cannot inline function containing closure: %+v", n)
1025-
}
1023+
}
10261024

1027-
m.Left = subst.node(n.Left)
1028-
m.Right = subst.node(n.Right)
1029-
m.List.Set(subst.list(n.List))
1030-
m.Rlist.Set(subst.list(n.Rlist))
1031-
m.Ninit.Set(append(m.Ninit.Slice(), subst.list(n.Ninit)...))
1032-
m.Nbody.Set(subst.list(n.Nbody))
1025+
m := nod(OXXX, nil, nil)
1026+
*m = *n
1027+
m.Ninit.Set(nil)
10331028

1034-
return m
1029+
if n.Op == OCLOSURE {
1030+
Fatalf("cannot inline function containing closure: %+v", n)
10351031
}
1032+
1033+
m.Left = subst.node(n.Left)
1034+
m.Right = subst.node(n.Right)
1035+
m.List.Set(subst.list(n.List))
1036+
m.Rlist.Set(subst.list(n.Rlist))
1037+
m.Ninit.Set(append(m.Ninit.Slice(), subst.list(n.Ninit)...))
1038+
m.Nbody.Set(subst.list(n.Nbody))
1039+
1040+
return m
10361041
}
10371042

10381043
// setPos is a visitor to update position info with a new inlining index.
@@ -1051,6 +1056,12 @@ func (s *setPos) node(n *Node) {
10511056
if n == nil {
10521057
return
10531058
}
1059+
if n.Op == OLITERAL || n.Op == OTYPE {
1060+
if n.Sym != nil {
1061+
// This node is not a copy, so don't clobber position.
1062+
return
1063+
}
1064+
}
10541065

10551066
// don't clobber names, unless they're freshly synthesized
10561067
if n.Op != ONAME || !n.Pos.IsKnown() {

test/inline_literal.go

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// run
2+
3+
// Copyright 2017 The Go Authors. All rights reserved.
4+
// Use of this source code is governed by a BSD-style
5+
// license that can be found in the LICENSE file.
6+
7+
package main
8+
9+
import (
10+
"log"
11+
"reflect"
12+
"runtime"
13+
)
14+
15+
func hello() string {
16+
return "Hello World" // line 16
17+
}
18+
19+
func foo() string { // line 19
20+
x := hello() // line 20
21+
y := hello() // line 21
22+
return x + y // line 22
23+
}
24+
25+
func bar() string {
26+
x := hello() // line 26
27+
return x
28+
}
29+
30+
// funcPC returns the PC for the func value f.
31+
func funcPC(f interface{}) uintptr {
32+
return reflect.ValueOf(f).Pointer()
33+
}
34+
35+
// Test for issue #15453. Previously, line 26 would appear in foo().
36+
func main() {
37+
pc := funcPC(foo)
38+
f := runtime.FuncForPC(pc)
39+
for ; runtime.FuncForPC(pc) == f; pc++ {
40+
file, line := f.FileLine(pc)
41+
if line == 0 {
42+
continue
43+
}
44+
// Line 16 can appear inside foo() because PC-line table has
45+
// innermost line numbers after inlining.
46+
if line != 16 && !(line >= 19 && line <= 22) {
47+
log.Fatalf("unexpected line at PC=%d: %s:%d\n", pc, file, line)
48+
}
49+
}
50+
}

0 commit comments

Comments
 (0)