]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: track line directives w/ column information
authorRobert Griesemer <gri@golang.org>
Fri, 23 Feb 2018 01:24:19 +0000 (17:24 -0800)
committerRobert Griesemer <gri@golang.org>
Mon, 26 Feb 2018 18:32:03 +0000 (18:32 +0000)
Extend cmd/internal/src.PosBase to track column information,
and adjust the meaning of the PosBase position to mean the
position at which the PosBase's relative (line, col) position
starts (rather than indicating the position of the //line
directive). Because this semantic change is made in the
compiler's noder, it doesn't affect the logic of src.PosBase,
only its test setup (where PosBases are constructed with
corrected incomming positions). In short, src.PosBase now
matches syntax.PosBase with respect to the semantics of
src.PosBase.pos.

For #22662.

Change-Id: I5b1451cb88fff3f149920c2eec08b6167955ce27
Reviewed-on: https://go-review.googlesource.com/96535
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
src/cmd/asm/internal/lex/input.go
src/cmd/compile/internal/gc/noder.go
src/cmd/internal/obj/line_test.go
src/cmd/internal/src/pos.go
src/cmd/internal/src/pos_test.go
src/cmd/internal/src/xpos_test.go
test/fixedbugs/issue22662.go [new file with mode: 0644]

index 666611e17996e176e0b59cb5d88b88fe0403a0c3..5186635fe701b32c7d9d48d01a083aa202b9e7c7 100644 (file)
@@ -454,8 +454,8 @@ func (in *Input) line() {
        if tok != '\n' {
                in.Error("unexpected token at end of #line: ", tok)
        }
-       pos := src.MakePos(in.Base(), uint(in.Line()), uint(in.Col()))
-       in.Stack.SetBase(src.NewLinePragmaBase(pos, file, objabi.AbsFile(objabi.WorkingDir(), file, *flags.TrimPath), uint(line)))
+       pos := src.MakePos(in.Base(), uint(in.Line())+1, 1) // +1 because #line nnn means line nnn starts on next line
+       in.Stack.SetBase(src.NewLinePragmaBase(pos, file, objabi.AbsFile(objabi.WorkingDir(), file, *flags.TrimPath), uint(line), 1))
 }
 
 // #undef processing
index 9418bc5c2fd292b9e8877d0e2c5816f34a4720ed..78655502934b4ef6e8340e5e5a258ae332593710 100644 (file)
@@ -80,17 +80,8 @@ func (p *noder) makeSrcPosBase(b0 *syntax.PosBase) *src.PosBase {
                fn := b0.Filename()
                if p0 := b0.Pos(); p0.IsKnown() {
                        // line directive base
-                       //
-                       // (A syntax.PosBase position is the position at which the PosBase's
-                       // new line and column are starting. For //line directives, that is
-                       // the position of the line following the directive. src.PosBases
-                       // on the other hand use the position of the line directive instead.
-                       // Hence the `p0.Line()-1` below.)
-                       //
-                       // TODO(gri) Once we implement /*line directives, we need to adjust
-                       //           src.MakePos accordingly.
-                       p1 := src.MakePos(p.makeSrcPosBase(p0.Base()), p0.Line()-1, p0.Col())
-                       b1 = src.NewLinePragmaBase(p1, fn, fileh(fn), b0.Line())
+                       p1 := src.MakePos(p.makeSrcPosBase(p0.Base()), p0.Line(), p0.Col())
+                       b1 = src.NewLinePragmaBase(p1, fn, fileh(fn), b0.Line(), b0.Col())
                } else {
                        // file base
                        b1 = src.NewFileBase(fn, absFilename(fn))
index f159a65e2b9e5fffe120bbf5f400092d2883d6d9..e0db7f3420ff1af8aa33770835426b43b456835f 100644 (file)
@@ -17,7 +17,7 @@ func TestLinkgetlineFromPos(t *testing.T) {
 
        afile := src.NewFileBase("a.go", "a.go")
        bfile := src.NewFileBase("b.go", "/foo/bar/b.go")
-       lfile := src.NewLinePragmaBase(src.MakePos(afile, 7, 0), "linedir", "linedir", 100)
+       lfile := src.NewLinePragmaBase(src.MakePos(afile, 8, 1), "linedir", "linedir", 100, 1)
 
        var tests = []struct {
                pos  src.Pos
index 10fa924c0bef1bc7effea841387d885b74fcf81b..ca7a10e955e47182e995a7c8eee4913b7590d312 100644 (file)
@@ -18,8 +18,8 @@ import "strconv"
 // The position base is used to determine the "relative" position, that is the
 // filename and line number relative to the position base. If the base refers
 // to the current file, there is no difference between absolute and relative
-// positions. If it refers to a //line pragma, a relative position is relative
-// to that pragma. A position base in turn contains the position at which it
+// positions. If it refers to a //line directive, a relative position is relative
+// to that directive. A position base in turn contains the position at which it
 // was introduced in the current file.
 type Pos struct {
        base *PosBase
@@ -68,9 +68,19 @@ func (p *Pos) SetBase(base *PosBase) { p.base = base }
 // RelFilename returns the filename recorded with the position's base.
 func (p Pos) RelFilename() string { return p.base.Filename() }
 
-// RelLine returns the line number relative to the positions's base.
+// RelLine returns the line number relative to the position's base.
 func (p Pos) RelLine() uint { b := p.base; return b.Line() + p.Line() - b.Pos().Line() }
 
+// RelCol returns the column number relative to the position's base.
+func (p Pos) RelCol() uint {
+       b := p.Base()
+       if p.Line() == b.Pos().Line() {
+               // p on same line as p's base => column is relative to p's base
+               return b.Col() + p.Col() - b.Pos().Col()
+       }
+       return p.Col()
+}
+
 // AbsFilename() returns the absolute filename recorded with the position's base.
 func (p Pos) AbsFilename() string { return p.base.AbsFilename() }
 
@@ -97,6 +107,9 @@ func (p Pos) Format(showCol, showOrig bool) string {
                return format(p.Filename(), p.Line(), p.Col(), showCol)
        }
 
+       // TODO(gri): Column information should be printed if a line
+       // directive explicitly specified a column, per issue #22662.
+
        // base is relative
        // Print the column only for the original position since the
        // relative position's column information may be bogus (it's
@@ -126,16 +139,16 @@ func format(filename string, line, col uint, showCol bool) string {
 // ----------------------------------------------------------------------------
 // PosBase
 
-// A PosBase encodes a filename and base line number.
-// Typically, each file and line pragma introduce a PosBase.
+// A PosBase encodes a filename and base position.
+// Typically, each file and line directive introduce a PosBase.
 // A nil *PosBase is a ready to use file PosBase for an unnamed
 // file with line numbers starting at 1.
 type PosBase struct {
-       pos         Pos
+       pos         Pos    // position at which the relative position is (line, col)
        filename    string // file name used to open source file, for error messages
        absFilename string // absolute file name, for PC-Line tables
        symFilename string // cached symbol file name, to avoid repeated string concatenation
-       line        uint   // relative line number at pos
+       line, col   uint   // relative line, column number at pos
        inl         int    // inlining index (see cmd/internal/obj/inl.go)
 }
 
@@ -155,11 +168,12 @@ func NewFileBase(filename, absFilename string) *PosBase {
        return nil
 }
 
-// NewLinePragmaBase returns a new *PosBase for a line pragma of the form
-//      //line filename:line
+// NewLinePragmaBase returns a new *PosBase for a line directive of the form
+//      //line filename:line:col
+//      /*line filename:line:col*/
 // at position pos.
-func NewLinePragmaBase(pos Pos, filename, absFilename string, line uint) *PosBase {
-       return &PosBase{pos, filename, absFilename, FileSymPrefix + absFilename, line - 1, -1}
+func NewLinePragmaBase(pos Pos, filename, absFilename string, line, col uint) *PosBase {
+       return &PosBase{pos, filename, absFilename, FileSymPrefix + absFilename, line, col, -1}
 }
 
 // NewInliningBase returns a copy of the old PosBase with the given inlining
@@ -229,6 +243,15 @@ func (b *PosBase) Line() uint {
        return 0
 }
 
+// Col returns the column number recorded with the base.
+// If b == nil, the result is 0.
+func (b *PosBase) Col() uint {
+       if b != nil {
+               return b.col
+       }
+       return 0
+}
+
 // InliningIndex returns the index into the global inlining
 // tree recorded with the base. If b == nil or the base has
 // not been inlined, the result is < 0.
index b06d38253611879a583cd4877d598c53a89e355f..1cebf6f0f66efe7769f018e39a7a362968cf4f25 100644 (file)
@@ -12,16 +12,19 @@ import (
 func TestPos(t *testing.T) {
        f0 := NewFileBase("", "")
        f1 := NewFileBase("f1", "f1")
-       f2 := NewLinePragmaBase(Pos{}, "f2", "f2", 10)
-       f3 := NewLinePragmaBase(MakePos(f1, 10, 1), "f3", "f3", 100)
-       f4 := NewLinePragmaBase(MakePos(f3, 10, 1), "f4", "f4", 100)
+       f2 := NewLinePragmaBase(Pos{}, "f2", "f2", 10, 0)
+       f3 := NewLinePragmaBase(MakePos(f1, 10, 1), "f3", "f3", 100, 1)
+       f4 := NewLinePragmaBase(MakePos(f3, 10, 1), "f4", "f4", 100, 1)
+
+       // line directives with non-1 columns
+       f5 := NewLinePragmaBase(MakePos(f1, 5, 5), "f5", "f5", 10, 1)
 
        // line directives from issue #19392
        fp := NewFileBase("p.go", "p.go")
-       fc := NewLinePragmaBase(MakePos(fp, 3, 0), "c.go", "c.go", 10)
-       ft := NewLinePragmaBase(MakePos(fp, 6, 0), "t.go", "t.go", 20)
-       fv := NewLinePragmaBase(MakePos(fp, 9, 0), "v.go", "v.go", 30)
-       ff := NewLinePragmaBase(MakePos(fp, 12, 0), "f.go", "f.go", 40)
+       fc := NewLinePragmaBase(MakePos(fp, 4, 1), "c.go", "c.go", 10, 1)
+       ft := NewLinePragmaBase(MakePos(fp, 7, 1), "t.go", "t.go", 20, 1)
+       fv := NewLinePragmaBase(MakePos(fp, 10, 1), "v.go", "v.go", 30, 1)
+       ff := NewLinePragmaBase(MakePos(fp, 13, 1), "f.go", "f.go", 40, 1)
 
        for _, test := range []struct {
                pos    Pos
@@ -32,22 +35,27 @@ func TestPos(t *testing.T) {
                line, col uint
 
                // relative info
-               relFilename string
-               relLine     uint
+               relFilename     string
+               relLine, relCol uint
        }{
-               {Pos{}, "<unknown line number>", "", 0, 0, "", 0},
-               {MakePos(nil, 2, 3), ":2:3", "", 2, 3, "", 2},
-               {MakePos(f0, 2, 3), ":2:3", "", 2, 3, "", 2},
-               {MakePos(f1, 1, 1), "f1:1:1", "f1", 1, 1, "f1", 1},
-               {MakePos(f2, 7, 10), "f2:16[:7:10]", "", 7, 10, "f2", 16},
-               {MakePos(f3, 12, 7), "f3:101[f1:12:7]", "f1", 12, 7, "f3", 101},
-               {MakePos(f4, 25, 1), "f4:114[f3:25:1]", "f3", 25, 1, "f4", 114},
+               {Pos{}, "<unknown line number>", "", 0, 0, "", 0, 0},
+               {MakePos(nil, 2, 3), ":2:3", "", 2, 3, "", 2, 3},
+               {MakePos(f0, 2, 3), ":2:3", "", 2, 3, "", 2, 3},
+               {MakePos(f1, 1, 1), "f1:1:1", "f1", 1, 1, "f1", 1, 1},
+               {MakePos(f2, 7, 10), "f2:17[:7:10]", "", 7, 10, "f2", 17, 10},
+               {MakePos(f3, 12, 7), "f3:102[f1:12:7]", "f1", 12, 7, "f3", 102, 7},
+               {MakePos(f4, 25, 1), "f4:115[f3:25:1]", "f3", 25, 1, "f4", 115, 1},
+
+               // line directives with non-1 columns
+               {MakePos(f5, 5, 5), "f5:10[f1:5:5]", "f1", 5, 5, "f5", 10, 1},
+               {MakePos(f5, 5, 10), "f5:10[f1:5:10]", "f1", 5, 10, "f5", 10, 6},
+               {MakePos(f5, 6, 10), "f5:11[f1:6:10]", "f1", 6, 10, "f5", 11, 10},
 
                // positions from issue #19392
-               {MakePos(fc, 4, 0), "c.go:10[p.go:4:0]", "p.go", 4, 0, "c.go", 10},
-               {MakePos(ft, 7, 0), "t.go:20[p.go:7:0]", "p.go", 7, 0, "t.go", 20},
-               {MakePos(fv, 10, 0), "v.go:30[p.go:10:0]", "p.go", 10, 0, "v.go", 30},
-               {MakePos(ff, 13, 0), "f.go:40[p.go:13:0]", "p.go", 13, 0, "f.go", 40},
+               {MakePos(fc, 4, 1), "c.go:10[p.go:4:1]", "p.go", 4, 1, "c.go", 10, 1},
+               {MakePos(ft, 7, 1), "t.go:20[p.go:7:1]", "p.go", 7, 1, "t.go", 20, 1},
+               {MakePos(fv, 10, 1), "v.go:30[p.go:10:1]", "p.go", 10, 1, "v.go", 30, 1},
+               {MakePos(ff, 13, 1), "f.go:40[p.go:13:1]", "p.go", 13, 1, "f.go", 40, 1},
        } {
                pos := test.pos
                if got := pos.String(); got != test.string {
@@ -72,6 +80,9 @@ func TestPos(t *testing.T) {
                if got := pos.RelLine(); got != test.relLine {
                        t.Errorf("%s: got relLine %d; want %d", test.string, got, test.relLine)
                }
+               if got := pos.RelCol(); got != test.relCol {
+                       t.Errorf("%s: got relCol %d; want %d", test.string, got, test.relCol)
+               }
        }
 }
 
index 8ac9c9dc4ec006e6d395f987bc6f1aec0f688c31..e5bfe57484b16f9d4773a2c1816d51048d6ab741 100644 (file)
@@ -19,7 +19,7 @@ func TestNoXPos(t *testing.T) {
 func TestConversion(t *testing.T) {
        b1 := NewFileBase("b1", "b1")
        b2 := NewFileBase("b2", "b2")
-       b3 := NewLinePragmaBase(MakePos(b1, 10, 0), "b3", "b3", 123)
+       b3 := NewLinePragmaBase(MakePos(b1, 10, 0), "b3", "b3", 123, 0)
 
        var tab PosTable
        for _, want := range []Pos{
diff --git a/test/fixedbugs/issue22662.go b/test/fixedbugs/issue22662.go
new file mode 100644 (file)
index 0000000..a1f00bf
--- /dev/null
@@ -0,0 +1,46 @@
+// run
+
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Verify effect of various line directives.
+// TODO: check columns
+
+package main
+
+import (
+       "fmt"
+       "runtime"
+)
+
+func check(file string, line int) {
+       _, f, l, ok := runtime.Caller(1)
+       if !ok {
+               panic("runtime.Caller(1) failed")
+       }
+       if f != file || l != line {
+               panic(fmt.Sprintf("got %s:%d; want %s:%d", f, l, file, line))
+       }
+}
+
+func main() {
+//-style line directives
+//line :1
+       check("??", 1) // no file specified
+//line foo.go:1
+       check("foo.go", 1)
+//line bar.go:10:20
+       check("bar.go", 10)
+//line :11:22
+       check("bar.go", 11) // no file, but column specified => keep old filename
+
+/*-style line directives */
+/*line :1*/ check("??", 1) // no file specified
+/*line foo.go:1*/ check("foo.go", 1)
+/*line bar.go:10:20*/ check("bar.go", 10)
+/*line :11:22*/ check("bar.go", 11) // no file, but column specified => keep old filename
+
+       /*line :10*/ check("??", 10); /*line foo.go:20*/ check("foo.go", 20); /*line :30:1*/ check("foo.go", 30)
+       check("foo.go", 31)
+}