]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: initialize line number properly for temporaries
authorDavid Chase <drchase@google.com>
Mon, 29 Jun 2015 20:30:19 +0000 (16:30 -0400)
committerRuss Cox <rsc@golang.org>
Tue, 7 Jul 2015 21:30:59 +0000 (21:30 +0000)
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: Sameer Ajmani <sameer@golang.org>
Reviewed-by: Russ Cox <rsc@golang.org>
src/cmd/compile/internal/gc/inl.go
src/cmd/compile/internal/gc/sinit.go
src/cmd/compile/internal/gc/subr.go
src/runtime/symtab_test.go

index d29ee59c54c063568f394c11fdcf752f36c96c0b..b2eeeed315ef114c89d7a7ab8ba71cc650f21a6e 100644 (file)
@@ -787,8 +787,15 @@ func mkinlcall1(np **Node, fn *Node, isddd bool) {
        call.Type = n.Type
        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))
 
+       as.Rlist = args
+
        //dumplist("call body", body);
 
        *np = call
index 7875d1638053db026353b8d40fdca2d7d757a3e4..e1a99d4ca0ee681297bb3c4d393b8b799529ddc4 100644 (file)
@@ -380,6 +380,7 @@ func staticcopy(l *Node, r *Node, out **NodeList) bool {
                                        rr.Orig = rr // completely separate copy
                                        rr.Type = ll.Type
                                        rr.Xoffset += e.Xoffset
+                                       setlineno(rr)
                                        *out = list(*out, Nod(OAS, ll, rr))
                                }
                        }
@@ -484,6 +485,7 @@ func staticassign(l *Node, r *Node, out **NodeList) bool {
                        if e.Expr.Op == OLITERAL {
                                gdata(&n1, e.Expr, int(n1.Type.Width))
                        } else {
+                               setlineno(e.Expr)
                                a = Nod(OXXX, nil, nil)
                                *a = n1
                                a.Orig = a // completely separate copy
@@ -636,6 +638,7 @@ func structlit(ctxt int, pass int, n *Node, var_ *Node, init **NodeList) {
                }
 
                // build list of var.field = expr
+               setlineno(value)
                a = Nod(ODOT, var_, newname(index.Sym))
 
                a = Nod(OAS, a, value)
@@ -703,6 +706,7 @@ func arraylit(ctxt int, pass int, n *Node, var_ *Node, init **NodeList) {
                }
 
                // build list of var[index] = value
+               setlineno(value)
                a = Nod(OINDEX, var_, index)
 
                a = Nod(OAS, a, value)
@@ -866,6 +870,7 @@ func slicelit(ctxt int, n *Node, var_ *Node, init **NodeList) {
                }
 
                // build list of var[c] = expr
+               setlineno(value)
                a = Nod(OAS, a, value)
 
                typecheck(&a, Etop)
@@ -954,6 +959,7 @@ func maplit(ctxt int, n *Node, var_ *Node, init **NodeList) {
 
                        if isliteral(index) && isliteral(value) {
                                // build vstat[b].a = key;
+                               setlineno(index)
                                a = Nodintconst(b)
 
                                a = Nod(OINDEX, vstat, a)
@@ -965,6 +971,7 @@ func maplit(ctxt int, n *Node, var_ *Node, init **NodeList) {
                                *init = list(*init, a)
 
                                // build vstat[b].b = value;
+                               setlineno(value)
                                a = Nodintconst(b)
 
                                a = Nod(OINDEX, vstat, a)
@@ -1032,15 +1039,18 @@ func maplit(ctxt int, n *Node, var_ *Node, init **NodeList) {
                        val = temp(var_.Type.Type)
                }
 
+               setlineno(r.Left)
                a = Nod(OAS, key, r.Left)
                typecheck(&a, Etop)
                walkstmt(&a)
                *init = list(*init, a)
+               setlineno(r.Right)
                a = Nod(OAS, val, r.Right)
                typecheck(&a, Etop)
                walkstmt(&a)
                *init = list(*init, a)
 
+               setlineno(val)
                a = Nod(OAS, Nod(OINDEX, var_, key), val)
                typecheck(&a, Etop)
                walkstmt(&a)
index 058ae5ecdddc7bd0a27fd98c6f150a77cf7bebe9..7402e17e2a81aa10d04a687cf823ce7b78cf77f6 100644 (file)
@@ -770,7 +770,7 @@ func treecopy(n *Node, lineno int32) *Node {
                m.Left = treecopy(n.Left, lineno)
                m.Right = treecopy(n.Right, lineno)
                m.List = listtreecopy(n.List, lineno)
-               if lineno != -1 {
+               if lineno != 0 {
                        m.Lineno = lineno
                }
                if m.Name != nil && n.Op != ODCLFIELD {
index bd9fe18c47818b381911570cf3ac2e45e53a14b1..b15a2e9a855a19594b53cc1b94fde2b8b125bc32 100644 (file)
@@ -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)
+               }
+       }
+}