Skip to content

Commit 515fa58

Browse files
committed
cmd/compile: track line directives w/ column information
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 <[email protected]>
1 parent 6fa6bde commit 515fa58

File tree

7 files changed

+117
-46
lines changed

7 files changed

+117
-46
lines changed

src/cmd/asm/internal/lex/input.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -454,8 +454,8 @@ func (in *Input) line() {
454454
if tok != '\n' {
455455
in.Error("unexpected token at end of #line: ", tok)
456456
}
457-
pos := src.MakePos(in.Base(), uint(in.Line()), uint(in.Col()))
458-
in.Stack.SetBase(src.NewLinePragmaBase(pos, file, objabi.AbsFile(objabi.WorkingDir(), file, *flags.TrimPath), uint(line)))
457+
pos := src.MakePos(in.Base(), uint(in.Line())+1, 1) // +1 because #line nnn means line nnn starts on next line
458+
in.Stack.SetBase(src.NewLinePragmaBase(pos, file, objabi.AbsFile(objabi.WorkingDir(), file, *flags.TrimPath), uint(line), 1))
459459
}
460460

461461
// #undef processing

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

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -80,17 +80,8 @@ func (p *noder) makeSrcPosBase(b0 *syntax.PosBase) *src.PosBase {
8080
fn := b0.Filename()
8181
if p0 := b0.Pos(); p0.IsKnown() {
8282
// line directive base
83-
//
84-
// (A syntax.PosBase position is the position at which the PosBase's
85-
// new line and column are starting. For //line directives, that is
86-
// the position of the line following the directive. src.PosBases
87-
// on the other hand use the position of the line directive instead.
88-
// Hence the `p0.Line()-1` below.)
89-
//
90-
// TODO(gri) Once we implement /*line directives, we need to adjust
91-
// src.MakePos accordingly.
92-
p1 := src.MakePos(p.makeSrcPosBase(p0.Base()), p0.Line()-1, p0.Col())
93-
b1 = src.NewLinePragmaBase(p1, fn, fileh(fn), b0.Line())
83+
p1 := src.MakePos(p.makeSrcPosBase(p0.Base()), p0.Line(), p0.Col())
84+
b1 = src.NewLinePragmaBase(p1, fn, fileh(fn), b0.Line(), b0.Col())
9485
} else {
9586
// file base
9687
b1 = src.NewFileBase(fn, absFilename(fn))

src/cmd/internal/obj/line_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ func TestLinkgetlineFromPos(t *testing.T) {
1717

1818
afile := src.NewFileBase("a.go", "a.go")
1919
bfile := src.NewFileBase("b.go", "/foo/bar/b.go")
20-
lfile := src.NewLinePragmaBase(src.MakePos(afile, 7, 0), "linedir", "linedir", 100)
20+
lfile := src.NewLinePragmaBase(src.MakePos(afile, 8, 1), "linedir", "linedir", 100, 1)
2121

2222
var tests = []struct {
2323
pos src.Pos

src/cmd/internal/src/pos.go

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ import "strconv"
1818
// The position base is used to determine the "relative" position, that is the
1919
// filename and line number relative to the position base. If the base refers
2020
// to the current file, there is no difference between absolute and relative
21-
// positions. If it refers to a //line pragma, a relative position is relative
22-
// to that pragma. A position base in turn contains the position at which it
21+
// positions. If it refers to a //line directive, a relative position is relative
22+
// to that directive. A position base in turn contains the position at which it
2323
// was introduced in the current file.
2424
type Pos struct {
2525
base *PosBase
@@ -68,9 +68,19 @@ func (p *Pos) SetBase(base *PosBase) { p.base = base }
6868
// RelFilename returns the filename recorded with the position's base.
6969
func (p Pos) RelFilename() string { return p.base.Filename() }
7070

71-
// RelLine returns the line number relative to the positions's base.
71+
// RelLine returns the line number relative to the position's base.
7272
func (p Pos) RelLine() uint { b := p.base; return b.Line() + p.Line() - b.Pos().Line() }
7373

74+
// RelCol returns the column number relative to the position's base.
75+
func (p Pos) RelCol() uint {
76+
b := p.Base()
77+
if p.Line() == b.Pos().Line() {
78+
// p on same line as p's base => column is relative to p's base
79+
return b.Col() + p.Col() - b.Pos().Col()
80+
}
81+
return p.Col()
82+
}
83+
7484
// AbsFilename() returns the absolute filename recorded with the position's base.
7585
func (p Pos) AbsFilename() string { return p.base.AbsFilename() }
7686

@@ -97,6 +107,9 @@ func (p Pos) Format(showCol, showOrig bool) string {
97107
return format(p.Filename(), p.Line(), p.Col(), showCol)
98108
}
99109

110+
// TODO(gri): Column information should be printed if a line
111+
// directive explicitly specified a column, per issue #22662.
112+
100113
// base is relative
101114
// Print the column only for the original position since the
102115
// relative position's column information may be bogus (it's
@@ -126,16 +139,16 @@ func format(filename string, line, col uint, showCol bool) string {
126139
// ----------------------------------------------------------------------------
127140
// PosBase
128141

129-
// A PosBase encodes a filename and base line number.
130-
// Typically, each file and line pragma introduce a PosBase.
142+
// A PosBase encodes a filename and base position.
143+
// Typically, each file and line directive introduce a PosBase.
131144
// A nil *PosBase is a ready to use file PosBase for an unnamed
132145
// file with line numbers starting at 1.
133146
type PosBase struct {
134-
pos Pos
147+
pos Pos // position at which the relative position is (line, col)
135148
filename string // file name used to open source file, for error messages
136149
absFilename string // absolute file name, for PC-Line tables
137150
symFilename string // cached symbol file name, to avoid repeated string concatenation
138-
line uint // relative line number at pos
151+
line, col uint // relative line, column number at pos
139152
inl int // inlining index (see cmd/internal/obj/inl.go)
140153
}
141154

@@ -155,11 +168,12 @@ func NewFileBase(filename, absFilename string) *PosBase {
155168
return nil
156169
}
157170

158-
// NewLinePragmaBase returns a new *PosBase for a line pragma of the form
159-
// //line filename:line
171+
// NewLinePragmaBase returns a new *PosBase for a line directive of the form
172+
// //line filename:line:col
173+
// /*line filename:line:col*/
160174
// at position pos.
161-
func NewLinePragmaBase(pos Pos, filename, absFilename string, line uint) *PosBase {
162-
return &PosBase{pos, filename, absFilename, FileSymPrefix + absFilename, line - 1, -1}
175+
func NewLinePragmaBase(pos Pos, filename, absFilename string, line, col uint) *PosBase {
176+
return &PosBase{pos, filename, absFilename, FileSymPrefix + absFilename, line, col, -1}
163177
}
164178

165179
// NewInliningBase returns a copy of the old PosBase with the given inlining
@@ -229,6 +243,15 @@ func (b *PosBase) Line() uint {
229243
return 0
230244
}
231245

246+
// Col returns the column number recorded with the base.
247+
// If b == nil, the result is 0.
248+
func (b *PosBase) Col() uint {
249+
if b != nil {
250+
return b.col
251+
}
252+
return 0
253+
}
254+
232255
// InliningIndex returns the index into the global inlining
233256
// tree recorded with the base. If b == nil or the base has
234257
// not been inlined, the result is < 0.

src/cmd/internal/src/pos_test.go

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,19 @@ import (
1212
func TestPos(t *testing.T) {
1313
f0 := NewFileBase("", "")
1414
f1 := NewFileBase("f1", "f1")
15-
f2 := NewLinePragmaBase(Pos{}, "f2", "f2", 10)
16-
f3 := NewLinePragmaBase(MakePos(f1, 10, 1), "f3", "f3", 100)
17-
f4 := NewLinePragmaBase(MakePos(f3, 10, 1), "f4", "f4", 100)
15+
f2 := NewLinePragmaBase(Pos{}, "f2", "f2", 10, 0)
16+
f3 := NewLinePragmaBase(MakePos(f1, 10, 1), "f3", "f3", 100, 1)
17+
f4 := NewLinePragmaBase(MakePos(f3, 10, 1), "f4", "f4", 100, 1)
18+
19+
// line directives with non-1 columns
20+
f5 := NewLinePragmaBase(MakePos(f1, 5, 5), "f5", "f5", 10, 1)
1821

1922
// line directives from issue #19392
2023
fp := NewFileBase("p.go", "p.go")
21-
fc := NewLinePragmaBase(MakePos(fp, 3, 0), "c.go", "c.go", 10)
22-
ft := NewLinePragmaBase(MakePos(fp, 6, 0), "t.go", "t.go", 20)
23-
fv := NewLinePragmaBase(MakePos(fp, 9, 0), "v.go", "v.go", 30)
24-
ff := NewLinePragmaBase(MakePos(fp, 12, 0), "f.go", "f.go", 40)
24+
fc := NewLinePragmaBase(MakePos(fp, 4, 1), "c.go", "c.go", 10, 1)
25+
ft := NewLinePragmaBase(MakePos(fp, 7, 1), "t.go", "t.go", 20, 1)
26+
fv := NewLinePragmaBase(MakePos(fp, 10, 1), "v.go", "v.go", 30, 1)
27+
ff := NewLinePragmaBase(MakePos(fp, 13, 1), "f.go", "f.go", 40, 1)
2528

2629
for _, test := range []struct {
2730
pos Pos
@@ -32,22 +35,27 @@ func TestPos(t *testing.T) {
3235
line, col uint
3336

3437
// relative info
35-
relFilename string
36-
relLine uint
38+
relFilename string
39+
relLine, relCol uint
3740
}{
38-
{Pos{}, "<unknown line number>", "", 0, 0, "", 0},
39-
{MakePos(nil, 2, 3), ":2:3", "", 2, 3, "", 2},
40-
{MakePos(f0, 2, 3), ":2:3", "", 2, 3, "", 2},
41-
{MakePos(f1, 1, 1), "f1:1:1", "f1", 1, 1, "f1", 1},
42-
{MakePos(f2, 7, 10), "f2:16[:7:10]", "", 7, 10, "f2", 16},
43-
{MakePos(f3, 12, 7), "f3:101[f1:12:7]", "f1", 12, 7, "f3", 101},
44-
{MakePos(f4, 25, 1), "f4:114[f3:25:1]", "f3", 25, 1, "f4", 114},
41+
{Pos{}, "<unknown line number>", "", 0, 0, "", 0, 0},
42+
{MakePos(nil, 2, 3), ":2:3", "", 2, 3, "", 2, 3},
43+
{MakePos(f0, 2, 3), ":2:3", "", 2, 3, "", 2, 3},
44+
{MakePos(f1, 1, 1), "f1:1:1", "f1", 1, 1, "f1", 1, 1},
45+
{MakePos(f2, 7, 10), "f2:17[:7:10]", "", 7, 10, "f2", 17, 10},
46+
{MakePos(f3, 12, 7), "f3:102[f1:12:7]", "f1", 12, 7, "f3", 102, 7},
47+
{MakePos(f4, 25, 1), "f4:115[f3:25:1]", "f3", 25, 1, "f4", 115, 1},
48+
49+
// line directives with non-1 columns
50+
{MakePos(f5, 5, 5), "f5:10[f1:5:5]", "f1", 5, 5, "f5", 10, 1},
51+
{MakePos(f5, 5, 10), "f5:10[f1:5:10]", "f1", 5, 10, "f5", 10, 6},
52+
{MakePos(f5, 6, 10), "f5:11[f1:6:10]", "f1", 6, 10, "f5", 11, 10},
4553

4654
// positions from issue #19392
47-
{MakePos(fc, 4, 0), "c.go:10[p.go:4:0]", "p.go", 4, 0, "c.go", 10},
48-
{MakePos(ft, 7, 0), "t.go:20[p.go:7:0]", "p.go", 7, 0, "t.go", 20},
49-
{MakePos(fv, 10, 0), "v.go:30[p.go:10:0]", "p.go", 10, 0, "v.go", 30},
50-
{MakePos(ff, 13, 0), "f.go:40[p.go:13:0]", "p.go", 13, 0, "f.go", 40},
55+
{MakePos(fc, 4, 1), "c.go:10[p.go:4:1]", "p.go", 4, 1, "c.go", 10, 1},
56+
{MakePos(ft, 7, 1), "t.go:20[p.go:7:1]", "p.go", 7, 1, "t.go", 20, 1},
57+
{MakePos(fv, 10, 1), "v.go:30[p.go:10:1]", "p.go", 10, 1, "v.go", 30, 1},
58+
{MakePos(ff, 13, 1), "f.go:40[p.go:13:1]", "p.go", 13, 1, "f.go", 40, 1},
5159
} {
5260
pos := test.pos
5361
if got := pos.String(); got != test.string {
@@ -72,6 +80,9 @@ func TestPos(t *testing.T) {
7280
if got := pos.RelLine(); got != test.relLine {
7381
t.Errorf("%s: got relLine %d; want %d", test.string, got, test.relLine)
7482
}
83+
if got := pos.RelCol(); got != test.relCol {
84+
t.Errorf("%s: got relCol %d; want %d", test.string, got, test.relCol)
85+
}
7586
}
7687
}
7788

src/cmd/internal/src/xpos_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ func TestNoXPos(t *testing.T) {
1919
func TestConversion(t *testing.T) {
2020
b1 := NewFileBase("b1", "b1")
2121
b2 := NewFileBase("b2", "b2")
22-
b3 := NewLinePragmaBase(MakePos(b1, 10, 0), "b3", "b3", 123)
22+
b3 := NewLinePragmaBase(MakePos(b1, 10, 0), "b3", "b3", 123, 0)
2323

2424
var tab PosTable
2525
for _, want := range []Pos{

test/fixedbugs/issue22662.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// run
2+
3+
// Copyright 2018 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+
// Verify effect of various line directives.
8+
// TODO: check columns
9+
10+
package main
11+
12+
import (
13+
"fmt"
14+
"runtime"
15+
)
16+
17+
func check(file string, line int) {
18+
_, f, l, ok := runtime.Caller(1)
19+
if !ok {
20+
panic("runtime.Caller(1) failed")
21+
}
22+
if f != file || l != line {
23+
panic(fmt.Sprintf("got %s:%d; want %s:%d", f, l, file, line))
24+
}
25+
}
26+
27+
func main() {
28+
//-style line directives
29+
//line :1
30+
check("??", 1) // no file specified
31+
//line foo.go:1
32+
check("foo.go", 1)
33+
//line bar.go:10:20
34+
check("bar.go", 10)
35+
//line :11:22
36+
check("bar.go", 11) // no file, but column specified => keep old filename
37+
38+
/*-style line directives */
39+
/*line :1*/ check("??", 1) // no file specified
40+
/*line foo.go:1*/ check("foo.go", 1)
41+
/*line bar.go:10:20*/ check("bar.go", 10)
42+
/*line :11:22*/ check("bar.go", 11) // no file, but column specified => keep old filename
43+
44+
/*line :10*/ check("??", 10); /*line foo.go:20*/ check("foo.go", 20); /*line :30:1*/ check("foo.go", 30)
45+
check("foo.go", 31)
46+
}

0 commit comments

Comments
 (0)