Commit 7929a0dd authored by David Chase's avatar David Chase Committed by Russ Cox

cmd/compile: initialize line number properly for temporaries

The expansion of structure, array, slice, and map literals
does not use the right line number in its introduced assignments
to temporaries, which leads to incorrect line number attribution
for expressions in those literals.

Inlining also incorrectly replaced the line numbers of args to
inlined functions.

This was revealed in CL 9721 because a now-avoided temporary
assignment introduced the correct line number.
I.e. before CL 9721
  "tmp_wrongline := expr"
was transformed to
  "tmp_rightline := expr; tmp_wrongline := tmp_rightline"

Also includes a repair to CL 10334 involving line numbers
where a spurious -1 remained (should have been 0, now is 0).

Fixes #11400.

Change-Id: I3a4687efe463977fa1e2c996606f4d91aaf22722
Reviewed-on: https://go-review.googlesource.com/11730
Run-TryBot: David Chase <drchase@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarSameer Ajmani <sameer@golang.org>
Reviewed-by: default avatarRuss Cox <rsc@golang.org>
parent 20280778
...@@ -787,8 +787,15 @@ func mkinlcall1(np **Node, fn *Node, isddd bool) { ...@@ -787,8 +787,15 @@ func mkinlcall1(np **Node, fn *Node, isddd bool) {
call.Type = n.Type call.Type = n.Type
call.Typecheck = 1 call.Typecheck = 1
// Hide the args from setlno -- the parameters to the inlined
// call already have good line numbers that should be preserved.
args := as.Rlist
as.Rlist = nil
setlno(call, int(n.Lineno)) setlno(call, int(n.Lineno))
as.Rlist = args
//dumplist("call body", body); //dumplist("call body", body);
*np = call *np = call
......
...@@ -380,6 +380,7 @@ func staticcopy(l *Node, r *Node, out **NodeList) bool { ...@@ -380,6 +380,7 @@ func staticcopy(l *Node, r *Node, out **NodeList) bool {
rr.Orig = rr // completely separate copy rr.Orig = rr // completely separate copy
rr.Type = ll.Type rr.Type = ll.Type
rr.Xoffset += e.Xoffset rr.Xoffset += e.Xoffset
setlineno(rr)
*out = list(*out, Nod(OAS, ll, rr)) *out = list(*out, Nod(OAS, ll, rr))
} }
} }
...@@ -484,6 +485,7 @@ func staticassign(l *Node, r *Node, out **NodeList) bool { ...@@ -484,6 +485,7 @@ func staticassign(l *Node, r *Node, out **NodeList) bool {
if e.Expr.Op == OLITERAL { if e.Expr.Op == OLITERAL {
gdata(&n1, e.Expr, int(n1.Type.Width)) gdata(&n1, e.Expr, int(n1.Type.Width))
} else { } else {
setlineno(e.Expr)
a = Nod(OXXX, nil, nil) a = Nod(OXXX, nil, nil)
*a = n1 *a = n1
a.Orig = a // completely separate copy a.Orig = a // completely separate copy
...@@ -636,6 +638,7 @@ func structlit(ctxt int, pass int, n *Node, var_ *Node, init **NodeList) { ...@@ -636,6 +638,7 @@ func structlit(ctxt int, pass int, n *Node, var_ *Node, init **NodeList) {
} }
// build list of var.field = expr // build list of var.field = expr
setlineno(value)
a = Nod(ODOT, var_, newname(index.Sym)) a = Nod(ODOT, var_, newname(index.Sym))
a = Nod(OAS, a, value) a = Nod(OAS, a, value)
...@@ -703,6 +706,7 @@ func arraylit(ctxt int, pass int, n *Node, var_ *Node, init **NodeList) { ...@@ -703,6 +706,7 @@ func arraylit(ctxt int, pass int, n *Node, var_ *Node, init **NodeList) {
} }
// build list of var[index] = value // build list of var[index] = value
setlineno(value)
a = Nod(OINDEX, var_, index) a = Nod(OINDEX, var_, index)
a = Nod(OAS, a, value) a = Nod(OAS, a, value)
...@@ -866,6 +870,7 @@ func slicelit(ctxt int, n *Node, var_ *Node, init **NodeList) { ...@@ -866,6 +870,7 @@ func slicelit(ctxt int, n *Node, var_ *Node, init **NodeList) {
} }
// build list of var[c] = expr // build list of var[c] = expr
setlineno(value)
a = Nod(OAS, a, value) a = Nod(OAS, a, value)
typecheck(&a, Etop) typecheck(&a, Etop)
...@@ -954,6 +959,7 @@ func maplit(ctxt int, n *Node, var_ *Node, init **NodeList) { ...@@ -954,6 +959,7 @@ func maplit(ctxt int, n *Node, var_ *Node, init **NodeList) {
if isliteral(index) && isliteral(value) { if isliteral(index) && isliteral(value) {
// build vstat[b].a = key; // build vstat[b].a = key;
setlineno(index)
a = Nodintconst(b) a = Nodintconst(b)
a = Nod(OINDEX, vstat, a) a = Nod(OINDEX, vstat, a)
...@@ -965,6 +971,7 @@ func maplit(ctxt int, n *Node, var_ *Node, init **NodeList) { ...@@ -965,6 +971,7 @@ func maplit(ctxt int, n *Node, var_ *Node, init **NodeList) {
*init = list(*init, a) *init = list(*init, a)
// build vstat[b].b = value; // build vstat[b].b = value;
setlineno(value)
a = Nodintconst(b) a = Nodintconst(b)
a = Nod(OINDEX, vstat, a) a = Nod(OINDEX, vstat, a)
...@@ -1032,15 +1039,18 @@ func maplit(ctxt int, n *Node, var_ *Node, init **NodeList) { ...@@ -1032,15 +1039,18 @@ func maplit(ctxt int, n *Node, var_ *Node, init **NodeList) {
val = temp(var_.Type.Type) val = temp(var_.Type.Type)
} }
setlineno(r.Left)
a = Nod(OAS, key, r.Left) a = Nod(OAS, key, r.Left)
typecheck(&a, Etop) typecheck(&a, Etop)
walkstmt(&a) walkstmt(&a)
*init = list(*init, a) *init = list(*init, a)
setlineno(r.Right)
a = Nod(OAS, val, r.Right) a = Nod(OAS, val, r.Right)
typecheck(&a, Etop) typecheck(&a, Etop)
walkstmt(&a) walkstmt(&a)
*init = list(*init, a) *init = list(*init, a)
setlineno(val)
a = Nod(OAS, Nod(OINDEX, var_, key), val) a = Nod(OAS, Nod(OINDEX, var_, key), val)
typecheck(&a, Etop) typecheck(&a, Etop)
walkstmt(&a) walkstmt(&a)
......
...@@ -770,7 +770,7 @@ func treecopy(n *Node, lineno int32) *Node { ...@@ -770,7 +770,7 @@ func treecopy(n *Node, lineno int32) *Node {
m.Left = treecopy(n.Left, lineno) m.Left = treecopy(n.Left, lineno)
m.Right = treecopy(n.Right, lineno) m.Right = treecopy(n.Right, lineno)
m.List = listtreecopy(n.List, lineno) m.List = listtreecopy(n.List, lineno)
if lineno != -1 { if lineno != 0 {
m.Lineno = lineno m.Lineno = lineno
} }
if m.Name != nil && n.Op != ODCLFIELD { if m.Name != nil && n.Op != ODCLFIELD {
......
...@@ -45,3 +45,108 @@ func testCallerBar(t *testing.T) { ...@@ -45,3 +45,108 @@ func testCallerBar(t *testing.T) {
} }
} }
} }
func lineNumber() int {
_, _, line, _ := runtime.Caller(1)
return line // return 0 for error
}
// Do not add/remove lines in this block without updating the line numbers.
var firstLine = lineNumber() // 0
var ( // 1
lineVar1 = lineNumber() // 2
lineVar2a, lineVar2b = lineNumber(), lineNumber() // 3
) // 4
var compLit = []struct { // 5
lineA, lineB int // 6
}{ // 7
{ // 8
lineNumber(), lineNumber(), // 9
}, // 10
{ // 11
lineNumber(), // 12
lineNumber(), // 13
}, // 14
{ // 15
lineB: lineNumber(), // 16
lineA: lineNumber(), // 17
}, // 18
} // 19
var arrayLit = [...]int{lineNumber(), // 20
lineNumber(), lineNumber(), // 21
lineNumber(), // 22
} // 23
var sliceLit = []int{lineNumber(), // 24
lineNumber(), lineNumber(), // 25
lineNumber(), // 26
} // 27
var mapLit = map[int]int{ // 28
29: lineNumber(), // 29
30: lineNumber(), // 30
lineNumber(): 31, // 31
lineNumber(): 32, // 32
} // 33
var intLit = lineNumber() + // 34
lineNumber() + // 35
lineNumber() // 36
func trythis() { // 37
recordLines(lineNumber(), // 38
lineNumber(), // 39
lineNumber()) // 40
}
// Modifications below this line are okay.
var l38, l39, l40 int
func recordLines(a, b, c int) {
l38 = a
l39 = b
l40 = c
}
func TestLineNumber(t *testing.T) {
trythis()
for _, test := range []struct {
name string
val int
want int
}{
{"firstLine", firstLine, 0},
{"lineVar1", lineVar1, 2},
{"lineVar2a", lineVar2a, 3},
{"lineVar2b", lineVar2b, 3},
{"compLit[0].lineA", compLit[0].lineA, 9},
{"compLit[0].lineB", compLit[0].lineB, 9},
{"compLit[1].lineA", compLit[1].lineA, 12},
{"compLit[1].lineB", compLit[1].lineB, 13},
{"compLit[2].lineA", compLit[2].lineA, 17},
{"compLit[2].lineB", compLit[2].lineB, 16},
{"arrayLit[0]", arrayLit[0], 20},
{"arrayLit[1]", arrayLit[1], 21},
{"arrayLit[2]", arrayLit[2], 21},
{"arrayLit[3]", arrayLit[3], 22},
{"sliceLit[0]", sliceLit[0], 24},
{"sliceLit[1]", sliceLit[1], 25},
{"sliceLit[2]", sliceLit[2], 25},
{"sliceLit[3]", sliceLit[3], 26},
{"mapLit[29]", mapLit[29], 29},
{"mapLit[30]", mapLit[30], 30},
{"mapLit[31]", mapLit[31+firstLine] + firstLine, 31}, // nb it's the key not the value
{"mapLit[32]", mapLit[32+firstLine] + firstLine, 32}, // nb it's the key not the value
{"intLit", intLit - 2*firstLine, 34 + 35 + 36},
{"l38", l38, 38},
{"l39", l39, 39},
{"l40", l40, 40},
} {
if got := test.val - firstLine; got != test.want {
t.Errorf("%s on firstLine+%d want firstLine+%d (firstLine=%d, val=%d)",
test.name, got, test.want, firstLine, test.val)
}
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment