Repository: go
Issue: proposal: cmd/{go,cgo,compile}: change interpretation of relative //line directives
Labels: Proposal

**Background**: generated Go source files may contain //line directives that relate each line of Go source to the line of some other file from which it was generated. If the file named by the line directive is a relative path, cmd/compile currently interprets it like any other relative path, that is, relative to its own os.Getwd. This demands that the tool that generated the //line directive has the same working directory as the compiler (e.g. GOROOT/src), or that it creates the line directive in anticipation of the consuming process having (say) GOROOT/src as its working directory.

By contrast, go/scanner takes a different approach: it interprets relative line directives relative to the scanned file's directory. So, if it encounters the line directive `//line a.yacc:1` in a file named `a/a.go`, the relative line directive is resolved as `a/a.yacc`. (In March 2018 go/scanner was changed to resemble the compiler in [CL 100235](https://go.dev/cl/100235), but this was reverted in August 2018 by [CL 127658](https://go.dev/cl/127658).)

The difference in behavior is easily observed by introducing a dummy line directive with a compiler error into an arbitrary Go source file. In this case, we'll append a relative reference from gopls/main.go to its README.md file:

```diff
xtools$ git diff
diff --git a/gopls/main.go b/gopls/main.go
index 083c4efd8..b63784ba8 100644
--- a/gopls/main.go
+++ b/gopls/main.go
@@ -34,3 +34,6 @@ func main() {
        ctx := context.Background()
        tool.Main(ctx, cmd.New(), os.Args[1:])
 }
+
+//line README.md:1
+invalid
```

When we build the package, the error message names a non-existent file:

```
xtools$ go build -o /dev/null ./gopls
# golang.org/x/tools/gopls
README.md:1: syntax error: non-declaration statement outside function body
```
When we use tools based on go/scanner, the error message names the correct file:
```
xtools$ gopackages -mode=allsyntax -deps ./gopls 2>&1 | grep README
	/Users/adonovan/w/xtools/gopls/README.md:1: expected declaration, found invalid
```

This is true even when we run the same commands from a different directory. Again, `go build` names the non-existent file, and go/scanner names the correct file:

```
xtools$ cd internal/
internal$ go build -o /dev/null ../gopls
# golang.org/x/tools/gopls
README.md:1: syntax error: non-declaration statement outside function body
```

```
internal$ gopackages -mode=allsyntax -deps ../gopls 2>&1 | grep README
	/Users/adonovan/w/xtools/gopls/README.md:1: expected declaration, found invalid
```

**Proposal:** The compiler's scanner should interpret relative line directives relative to the directory of the scanned file, and this behavior should be documented at [https://pkg.go.dev/cmd/compile#hdr-Compiler_Directives](https://pkg.go.dev/cmd/compile#hdr-Compiler_Directives).

This may require changes to the line directives emitted by cgo and other tools (including [unparam and unconvert](https://go.dev/cl/127658), whatever they are).

Arguably, this is an incompatible change, but we notice that more often than not, when published Go modules use relative line directives, they already follow the proposed discipline.

See also:

  - [https://github.com/golang/go/issues/24183](https://github.com/golang/go/issues/24183)
  - [https://github.com/golang/go/issues/26671](https://github.com/golang/go/issues/26671)
  - [https://github.com/golang/go/issues/69689](https://github.com/golang/go/issues/69689)


@griesemer @ianlancetaylor @findleyr @timothy-king