all: merge dev.inline into master

Change-Id: I7715581a04e513dcda9918e853fa6b1ddc703770
This commit is contained in:
Russ Cox 2017-02-01 09:35:27 -05:00
commit 47ce87877b
124 changed files with 6096 additions and 5655 deletions

View file

@ -61,7 +61,7 @@ func (p *Parser) append(prog *obj.Prog, cond string, doLabel bool) {
}
prog.Pc = p.pc
if *flags.Debug {
fmt.Println(p.histLineNum, prog)
fmt.Println(p.lineNum, prog)
}
if testOut != nil {
fmt.Fprintln(testOut, prog)
@ -161,10 +161,10 @@ func (p *Parser) asmText(word string, operands [][]lex.Token) {
argSize = p.positiveAtoi(op[1].String())
}
prog := &obj.Prog{
Ctxt: p.ctxt,
As: obj.ATEXT,
Lineno: p.histLineNum,
From: nameAddr,
Ctxt: p.ctxt,
As: obj.ATEXT,
Pos: p.pos(),
From: nameAddr,
From3: &obj.Addr{
Type: obj.TYPE_CONST,
Offset: flag,
@ -294,11 +294,11 @@ func (p *Parser) asmPCData(word string, operands [][]lex.Token) {
// log.Printf("PCDATA $%d, $%d", key.Offset, value.Offset)
prog := &obj.Prog{
Ctxt: p.ctxt,
As: obj.APCDATA,
Lineno: p.histLineNum,
From: key,
To: value,
Ctxt: p.ctxt,
As: obj.APCDATA,
Pos: p.pos(),
From: key,
To: value,
}
p.append(prog, "", true)
}
@ -324,11 +324,11 @@ func (p *Parser) asmFuncData(word string, operands [][]lex.Token) {
}
prog := &obj.Prog{
Ctxt: p.ctxt,
As: obj.AFUNCDATA,
Lineno: p.histLineNum,
From: valueAddr,
To: nameAddr,
Ctxt: p.ctxt,
As: obj.AFUNCDATA,
Pos: p.pos(),
From: valueAddr,
To: nameAddr,
}
p.append(prog, "", true)
}
@ -340,9 +340,9 @@ func (p *Parser) asmFuncData(word string, operands [][]lex.Token) {
func (p *Parser) asmJump(op obj.As, cond string, a []obj.Addr) {
var target *obj.Addr
prog := &obj.Prog{
Ctxt: p.ctxt,
Lineno: p.histLineNum,
As: op,
Ctxt: p.ctxt,
Pos: p.pos(),
As: op,
}
switch len(a) {
case 1:
@ -468,9 +468,9 @@ func (p *Parser) branch(jmp, target *obj.Prog) {
func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
// fmt.Printf("%s %+v\n", op, a)
prog := &obj.Prog{
Ctxt: p.ctxt,
Lineno: p.histLineNum,
As: op,
Ctxt: p.ctxt,
Pos: p.pos(),
As: op,
}
switch len(a) {
case 0:

View file

@ -26,10 +26,9 @@ import (
// result against a golden file.
func testEndToEnd(t *testing.T, goarch, file string) {
lex.InitHist()
input := filepath.Join("testdata", file+".s")
architecture, ctxt := setArch(goarch)
lexer := lex.NewLexer(input, ctxt)
lexer := lex.NewLexer(input)
parser := NewParser(ctxt, architecture, lexer)
pList := obj.Linknewplist(ctxt)
var ok bool
@ -264,10 +263,9 @@ var (
)
func testErrors(t *testing.T, goarch, file string) {
lex.InitHist()
input := filepath.Join("testdata", file+".s")
architecture, ctxt := setArch(goarch)
lexer := lex.NewLexer(input, ctxt)
lexer := lex.NewLexer(input)
parser := NewParser(ctxt, architecture, lexer)
pList := obj.Linknewplist(ctxt)
var ok bool

View file

@ -19,14 +19,14 @@ import (
"cmd/asm/internal/flags"
"cmd/asm/internal/lex"
"cmd/internal/obj"
"cmd/internal/src"
"cmd/internal/sys"
)
type Parser struct {
lex lex.TokenReader
lineNum int // Line number in source file.
histLineNum int32 // Cumulative line number across source files.
errorLine int32 // (Cumulative) line number of last error.
errorLine int // Line number of last error.
errorCount int // Number of errors.
pc int64 // virtual PC; count of Progs; doesn't advance for GLOBL or DATA.
input []lex.Token
@ -60,7 +60,7 @@ func NewParser(ctxt *obj.Link, ar *arch.Arch, lexer lex.TokenReader) *Parser {
}
}
// panicOnError is enable when testing to abort execution on the first error
// panicOnError is enabled when testing to abort execution on the first error
// and turn it into a recoverable panic.
var panicOnError bool
@ -68,11 +68,11 @@ func (p *Parser) errorf(format string, args ...interface{}) {
if panicOnError {
panic(fmt.Errorf(format, args...))
}
if p.histLineNum == p.errorLine {
if p.lineNum == p.errorLine {
// Only one error per line.
return
}
p.errorLine = p.histLineNum
p.errorLine = p.lineNum
if p.lex != nil {
// Put file and line information on head of message.
format = "%s:%d: " + format + "\n"
@ -85,6 +85,10 @@ func (p *Parser) errorf(format string, args ...interface{}) {
}
}
func (p *Parser) pos() src.XPos {
return p.ctxt.PosTable.XPos(src.MakePos(p.lex.Base(), uint(p.lineNum), 0))
}
func (p *Parser) Parse() (*obj.Prog, bool) {
for p.line() {
}
@ -105,7 +109,6 @@ func (p *Parser) line() bool {
// are labeled with this line. Otherwise we complain after we've absorbed
// the terminating newline and the line numbers are off by one in errors.
p.lineNum = p.lex.Line()
p.histLineNum = lex.HistLine()
switch tok {
case '\n', ';':
continue

View file

@ -56,7 +56,6 @@ func TestErroneous(t *testing.T) {
for _, test := range tests {
parser.errorCount = 0
parser.lineNum++
parser.histLineNum++
if !parser.pseudo(test.pseudo, tokenize(test.operands)) {
t.Fatalf("Wrong pseudo-instruction: %s", test.pseudo)
}

View file

@ -13,6 +13,7 @@ import (
"text/scanner"
"cmd/asm/internal/flags"
"cmd/internal/src"
)
// Input is the main input: a stack of readers and some macro definitions.
@ -290,7 +291,7 @@ func lookup(args []string, arg string) int {
func (in *Input) invokeMacro(macro *Macro) {
// If the macro has no arguments, just substitute the text.
if macro.args == nil {
in.Push(NewSlice(in.File(), in.Line(), macro.tokens))
in.Push(NewSlice(in.Base(), in.Line(), macro.tokens))
return
}
tok := in.Stack.Next()
@ -300,7 +301,7 @@ func (in *Input) invokeMacro(macro *Macro) {
in.peekToken = tok
in.peekText = in.text
in.peek = true
in.Push(NewSlice(in.File(), in.Line(), []Token{Make(macroName, macro.name)}))
in.Push(NewSlice(in.Base(), in.Line(), []Token{Make(macroName, macro.name)}))
return
}
actuals := in.argsFor(macro)
@ -317,7 +318,7 @@ func (in *Input) invokeMacro(macro *Macro) {
}
tokens = append(tokens, substitution...)
}
in.Push(NewSlice(in.File(), in.Line(), tokens))
in.Push(NewSlice(in.Base(), in.Line(), tokens))
}
// argsFor returns a map from formal name to actual value for this argumented macro invocation.
@ -452,8 +453,8 @@ func (in *Input) line() {
if tok != '\n' {
in.Error("unexpected token at end of #line: ", tok)
}
linkCtxt.LineHist.Update(histLine, file, line)
in.Stack.SetPos(line, file)
pos := src.MakePos(in.Base(), uint(in.Line()), uint(in.Col()))
in.Stack.SetBase(src.NewLinePragmaBase(pos, file, uint(line)))
}
// #undef processing

View file

@ -12,7 +12,7 @@ import (
"strings"
"text/scanner"
"cmd/internal/obj"
"cmd/internal/src"
)
// A ScanToken represents an input item. It is a simple wrapping of rune, as
@ -57,23 +57,8 @@ func (t ScanToken) String() string {
}
}
var (
// It might be nice if these weren't global.
linkCtxt *obj.Link // The link context for all instructions.
histLine int = 1 // The cumulative count of lines processed.
)
// HistLine reports the cumulative source line number of the token,
// for use in the Prog structure for the linker. (It's always handling the
// instruction from the current lex line.)
// It returns int32 because that's what type ../asm prefers.
func HistLine() int32 {
return int32(histLine)
}
// NewLexer returns a lexer for the named file and the given link context.
func NewLexer(name string, ctxt *obj.Link) TokenReader {
linkCtxt = ctxt
func NewLexer(name string) TokenReader {
input := NewInput(name)
fd, err := os.Open(name)
if err != nil {
@ -83,16 +68,11 @@ func NewLexer(name string, ctxt *obj.Link) TokenReader {
return input
}
// InitHist sets the line count to 1, for reproducible testing.
func InitHist() {
histLine = 1
}
// The other files in this directory each contain an implementation of TokenReader.
// A TokenReader is like a reader, but returns lex tokens of type Token. It also can tell you what
// the text of the most recently returned token is, and where it was found.
// The underlying scanner elides all spaces except newline, so the input looks like a stream of
// The underlying scanner elides all spaces except newline, so the input looks like a stream of
// Tokens; original spacing is lost but we don't need it.
type TokenReader interface {
// Next returns the next token.
@ -102,12 +82,14 @@ type TokenReader interface {
Text() string
// File reports the source file name of the token.
File() string
// Base reports the position base of the token.
Base() *src.PosBase
// SetBase sets the position base.
SetBase(*src.PosBase)
// Line reports the source line number of the token.
Line() int
// Col reports the source column number of the token.
Col() int
// SetPos sets the file and line number.
SetPos(line int, file string)
// Close does any teardown required.
Close()
}

View file

@ -4,22 +4,26 @@
package lex
import "text/scanner"
import (
"text/scanner"
"cmd/internal/src"
)
// A Slice reads from a slice of Tokens.
type Slice struct {
tokens []Token
fileName string
line int
pos int
tokens []Token
base *src.PosBase
line int
pos int
}
func NewSlice(fileName string, line int, tokens []Token) *Slice {
func NewSlice(base *src.PosBase, line int, tokens []Token) *Slice {
return &Slice{
tokens: tokens,
fileName: fileName,
line: line,
pos: -1, // Next will advance to zero.
tokens: tokens,
base: base,
line: line,
pos: -1, // Next will advance to zero.
}
}
@ -36,7 +40,17 @@ func (s *Slice) Text() string {
}
func (s *Slice) File() string {
return s.fileName
return s.base.Filename()
}
func (s *Slice) Base() *src.PosBase {
return s.base
}
func (s *Slice) SetBase(base *src.PosBase) {
// Cannot happen because we only have slices of already-scanned text,
// but be prepared.
s.base = base
}
func (s *Slice) Line() int {
@ -56,12 +70,5 @@ func (s *Slice) Col() int {
return s.pos
}
func (s *Slice) SetPos(line int, file string) {
// Cannot happen because we only have slices of already-scanned
// text, but be prepared.
s.line = line
s.fileName = file
}
func (s *Slice) Close() {
}

View file

@ -4,7 +4,11 @@
package lex
import "text/scanner"
import (
"text/scanner"
"cmd/internal/src"
)
// A Stack is a stack of TokenReaders. As the top TokenReader hits EOF,
// it resumes reading the next one down.
@ -34,7 +38,15 @@ func (s *Stack) Text() string {
}
func (s *Stack) File() string {
return s.tr[len(s.tr)-1].File()
return s.Base().Filename()
}
func (s *Stack) Base() *src.PosBase {
return s.tr[len(s.tr)-1].Base()
}
func (s *Stack) SetBase(base *src.PosBase) {
s.tr[len(s.tr)-1].SetBase(base)
}
func (s *Stack) Line() int {
@ -45,9 +57,5 @@ func (s *Stack) Col() int {
return s.tr[len(s.tr)-1].Col()
}
func (s *Stack) SetPos(line int, file string) {
s.tr[len(s.tr)-1].SetPos(line, file)
}
func (s *Stack) Close() { // Unused.
}

View file

@ -10,17 +10,21 @@ import (
"strings"
"text/scanner"
"unicode"
"cmd/asm/internal/flags"
"cmd/internal/obj"
"cmd/internal/src"
)
// A Tokenizer is a simple wrapping of text/scanner.Scanner, configured
// for our purposes and made a TokenReader. It forms the lowest level,
// turning text from readers into tokens.
type Tokenizer struct {
tok ScanToken
s *scanner.Scanner
line int
fileName string
file *os.File // If non-nil, file descriptor to close.
tok ScanToken
s *scanner.Scanner
base *src.PosBase
line int
file *os.File // If non-nil, file descriptor to close.
}
func NewTokenizer(name string, r io.Reader, file *os.File) *Tokenizer {
@ -37,14 +41,11 @@ func NewTokenizer(name string, r io.Reader, file *os.File) *Tokenizer {
scanner.ScanComments
s.Position.Filename = name
s.IsIdentRune = isIdentRune
if file != nil {
linkCtxt.LineHist.Push(histLine, name)
}
return &Tokenizer{
s: &s,
line: 1,
fileName: name,
file: file,
s: &s,
base: src.NewFileBase(name, obj.AbsFile(obj.WorkingDir(), name, *flags.TrimPath)),
line: 1,
file: file,
}
}
@ -80,7 +81,15 @@ func (t *Tokenizer) Text() string {
}
func (t *Tokenizer) File() string {
return t.fileName
return t.base.Filename()
}
func (t *Tokenizer) Base() *src.PosBase {
return t.base
}
func (t *Tokenizer) SetBase(base *src.PosBase) {
t.base = base
}
func (t *Tokenizer) Line() int {
@ -91,11 +100,6 @@ func (t *Tokenizer) Col() int {
return t.s.Pos().Column
}
func (t *Tokenizer) SetPos(line int, file string) {
t.line = line
t.fileName = file
}
func (t *Tokenizer) Next() ScanToken {
s := t.s
for {
@ -105,15 +109,11 @@ func (t *Tokenizer) Next() ScanToken {
}
length := strings.Count(s.TokenText(), "\n")
t.line += length
histLine += length
// TODO: If we ever have //go: comments in assembly, will need to keep them here.
// For now, just discard all comments.
}
switch t.tok {
case '\n':
if t.file != nil {
histLine++
}
t.line++
case '-':
if s.Peek() == '>' {
@ -146,7 +146,5 @@ func (t *Tokenizer) Next() ScanToken {
func (t *Tokenizer) Close() {
if t.file != nil {
t.file.Close()
// It's an open file, so pop the line history.
linkCtxt.LineHist.Pop(histLine)
}
}

View file

@ -37,7 +37,6 @@ func main() {
if *flags.PrintOut {
ctxt.Debugasm = 1
}
ctxt.LineHist.TrimPathPrefix = *flags.TrimPath
ctxt.Flag_dynlink = *flags.Dynlink
ctxt.Flag_shared = *flags.Shared || *flags.Dynlink
ctxt.Bso = bufio.NewWriter(os.Stdout)
@ -57,7 +56,7 @@ func main() {
var ok, diag bool
var failedFile string
for _, f := range flag.Args() {
lexer := lex.NewLexer(f, ctxt)
lexer := lex.NewLexer(f)
parser := asm.NewParser(ctxt, architecture, lexer)
ctxt.DiagFunc = func(format string, args ...interface{}) {
diag = true

View file

@ -654,6 +654,7 @@ var knownFormats = map[string]string{
"cmd/compile/internal/syntax.token %q": "",
"cmd/compile/internal/syntax.token %s": "",
"cmd/internal/obj.As %v": "",
"cmd/internal/src.Pos %s": "",
"error %v": "",
"float64 %.2f": "",
"float64 %.3f": "",
@ -663,7 +664,6 @@ var knownFormats = map[string]string{
"int %-12d": "",
"int %-6d": "",
"int %-8o": "",
"int %5d": "",
"int %6d": "",
"int %c": "",
"int %d": "",
@ -699,6 +699,7 @@ var knownFormats = map[string]string{
"time.Duration %d": "",
"time.Duration %v": "",
"uint %04x": "",
"uint %5d": "",
"uint %d": "",
"uint16 %d": "",
"uint16 %v": "",

View file

@ -147,7 +147,7 @@ func duff(size int64) (int64, int64) {
}
func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
s.SetLineno(v.Line)
s.SetPos(v.Pos)
switch v.Op {
case ssa.OpAMD64ADDQ, ssa.OpAMD64ADDL:
r := v.Reg()
@ -875,8 +875,8 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p.To.Type = obj.TYPE_MEM
p.To.Reg = v.Args[0].Reg()
gc.AddAux(&p.To, v)
if gc.Debug_checknil != 0 && v.Line > 1 { // v.Line==1 in generated wrappers
gc.Warnl(v.Line, "generated nil check")
if gc.Debug_checknil != 0 && v.Pos.Line() > 1 { // v.Pos.Line()==1 in generated wrappers
gc.Warnl(v.Pos, "generated nil check")
}
case ssa.OpAMD64MOVLatomicload, ssa.OpAMD64MOVQatomicload:
p := gc.Prog(v.Op.Asm())
@ -962,7 +962,7 @@ var nefJumps = [2][2]gc.FloatingEQNEJump{
}
func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
s.SetLineno(b.Line)
s.SetPos(b.Pos)
switch b.Kind {
case ssa.BlockPlain:

View file

@ -118,7 +118,7 @@ func genregshift(as obj.As, r0, r1, r2, r int16, typ int64) *obj.Prog {
}
func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
s.SetLineno(v.Line)
s.SetPos(v.Pos)
switch v.Op {
case ssa.OpInitMem:
// memory arg needs no code
@ -705,8 +705,8 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
gc.AddAux(&p.From, v)
p.To.Type = obj.TYPE_REG
p.To.Reg = arm.REGTMP
if gc.Debug_checknil != 0 && v.Line > 1 { // v.Line==1 in generated wrappers
gc.Warnl(v.Line, "generated nil check")
if gc.Debug_checknil != 0 && v.Pos.Line() > 1 { // v.Pos.Line()==1 in generated wrappers
gc.Warnl(v.Pos, "generated nil check")
}
case ssa.OpARMLoweredZero:
// MOVW.P Rarg2, 4(R1)
@ -861,7 +861,7 @@ var blockJump = map[ssa.BlockKind]struct {
}
func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
s.SetLineno(b.Line)
s.SetPos(b.Pos)
switch b.Kind {
case ssa.BlockPlain:

View file

@ -92,7 +92,7 @@ func genshift(as obj.As, r0, r1, r int16, typ int64, s int64) *obj.Prog {
}
func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
s.SetLineno(v.Line)
s.SetPos(v.Pos)
switch v.Op {
case ssa.OpInitMem:
// memory arg needs no code
@ -690,8 +690,8 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
gc.AddAux(&p.From, v)
p.To.Type = obj.TYPE_REG
p.To.Reg = arm64.REGTMP
if gc.Debug_checknil != 0 && v.Line > 1 { // v.Line==1 in generated wrappers
gc.Warnl(v.Line, "generated nil check")
if gc.Debug_checknil != 0 && v.Pos.Line() > 1 { // v.Line==1 in generated wrappers
gc.Warnl(v.Pos, "generated nil check")
}
case ssa.OpVarDef:
gc.Gvardef(v.Aux.(*gc.Node))
@ -768,7 +768,7 @@ var blockJump = map[ssa.BlockKind]struct {
}
func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
s.SetLineno(b.Line)
s.SetPos(b.Pos)
switch b.Kind {
case ssa.BlockPlain:

View file

@ -186,7 +186,7 @@ func genhash(sym *Sym, t *Type) {
fmt.Printf("genhash %v %v\n", sym, t)
}
lineno = 1 // less confusing than end of input
lineno = MakePos(nil, 1, 0) // less confusing than end of input
dclcontext = PEXTERN
markdcl()
@ -364,7 +364,7 @@ func geneq(sym *Sym, t *Type) {
fmt.Printf("geneq %v %v\n", sym, t)
}
lineno = 1 // less confusing than end of input
lineno = MakePos(nil, 1, 0) // less confusing than end of input
dclcontext = PEXTERN
markdcl()

View file

@ -126,7 +126,7 @@ func dowidth(t *Type) {
if t.Width == -2 {
if !t.Broke {
t.Broke = true
yyerrorl(t.Lineno, "invalid recursive type %v", t)
yyerrorl(t.Pos, "invalid recursive type %v", t)
}
t.Width = 0
@ -143,7 +143,7 @@ func dowidth(t *Type) {
defercalc++
lno := lineno
lineno = t.Lineno
lineno = t.Pos
t.Width = -2
t.Align = 0

View file

@ -286,6 +286,6 @@ var issue16214src = `
package main
func Mod32(x uint32) uint32 {
return x % 3 // frontend rewrites it as HMUL with 2863311531, the LITERAL node has Lineno 0
return x % 3 // frontend rewrites it as HMUL with 2863311531, the LITERAL node has unknown Pos
}
`

View file

@ -574,7 +574,9 @@ func (p *exporter) pos(n *Node) {
func fileLine(n *Node) (file string, line int) {
if n != nil {
file, line = Ctxt.LineHist.AbsFileLine(int(n.Lineno))
pos := Ctxt.PosTable.Pos(n.Pos)
file = pos.AbsFilename()
line = int(pos.Line())
}
return
}
@ -784,7 +786,7 @@ func (p *exporter) typ(t *Type) {
// for the issue.
if p.nesting > 100 {
p.int(0) // 0 methods to indicate empty interface
yyerrorl(t.Lineno, "cannot export unnamed recursive interface")
yyerrorl(t.Pos, "cannot export unnamed recursive interface")
break
}

View file

@ -247,7 +247,7 @@ func makeclosure(func_ *Node) *Node {
// after capturing (effectively constant).
func capturevars(xfunc *Node) {
lno := lineno
lineno = xfunc.Lineno
lineno = xfunc.Pos
func_ := xfunc.Func.Closure
func_.Func.Enter.Set(nil)
@ -288,7 +288,7 @@ func capturevars(xfunc *Node) {
if v.Name.Byval {
how = "value"
}
Warnl(v.Lineno, "%v capturing by %s: %v (addr=%v assign=%v width=%d)", name, how, v.Sym, outermost.Addrtaken, outermost.Assigned, int32(v.Type.Width))
Warnl(v.Pos, "%v capturing by %s: %v (addr=%v assign=%v width=%d)", name, how, v.Sym, outermost.Addrtaken, outermost.Assigned, int32(v.Type.Width))
}
outer = typecheck(outer, Erv)
@ -302,7 +302,7 @@ func capturevars(xfunc *Node) {
// It transform closure bodies to properly reference captured variables.
func transformclosure(xfunc *Node) {
lno := lineno
lineno = xfunc.Lineno
lineno = xfunc.Pos
func_ := xfunc.Func.Closure
if func_.Func.Top&Ecall != 0 {
@ -441,13 +441,13 @@ func hasemptycvars(func_ *Node) bool {
func closuredebugruntimecheck(r *Node) {
if Debug_closure > 0 {
if r.Esc == EscHeap {
Warnl(r.Lineno, "heap closure, captured vars = %v", r.Func.Cvars)
Warnl(r.Pos, "heap closure, captured vars = %v", r.Func.Cvars)
} else {
Warnl(r.Lineno, "stack closure, captured vars = %v", r.Func.Cvars)
Warnl(r.Pos, "stack closure, captured vars = %v", r.Func.Cvars)
}
}
if compiling_runtime && r.Esc == EscHeap {
yyerrorl(r.Lineno, "heap-allocated closure, not allowed in runtime.")
yyerrorl(r.Pos, "heap-allocated closure, not allowed in runtime.")
}
}
@ -455,7 +455,7 @@ func walkclosure(func_ *Node, init *Nodes) *Node {
// If no closure vars, don't bother wrapping.
if hasemptycvars(func_) {
if Debug_closure > 0 {
Warnl(func_.Lineno, "closure converted to global")
Warnl(func_.Pos, "closure converted to global")
}
return func_.Func.Closure.Func.Nname
} else {

View file

@ -4,7 +4,10 @@
package gc
import "strings"
import (
"cmd/internal/src"
"strings"
)
// Ctype describes the constant kind of an "ideal" (untyped) constant.
type Ctype int8
@ -676,7 +679,7 @@ func evconst(n *Node) {
nr := n.Right
var rv Val
var lno int32
var lno src.XPos
var wr EType
var v Val
var norig *Node

View file

@ -5,7 +5,9 @@
package gc
import (
"cmd/compile/internal/syntax"
"cmd/internal/obj"
"cmd/internal/src"
"fmt"
"sort"
"strings"
@ -113,7 +115,7 @@ func testdclstack() {
// redeclare emits a diagnostic about symbol s being redeclared somewhere.
func redeclare(s *Sym, where string) {
if s.Lastlineno == 0 {
if !s.Lastlineno.IsKnown() {
var tmp string
if s.Origpkg != nil {
tmp = s.Origpkg.Path
@ -162,7 +164,7 @@ func declare(n *Node, ctxt Class) {
// named OLITERAL needs Name; most OLITERALs don't.
n.Name = new(Name)
}
n.Lineno = lineno
n.Pos = lineno
s := n.Sym
// kludgy: typecheckok means we're past parsing. Eg genwrapper may declare out of package names later.
@ -287,14 +289,14 @@ func variter(vl []*Node, t *Node, el []*Node) []*Node {
// declare constants from grammar
// new_name_list [[type] = expr_list]
func constiter(vl []*Node, t *Node, cl []*Node) []*Node {
lno := int32(0) // default is to leave line number alone in listtreecopy
var lno src.XPos // default is to leave line number alone in listtreecopy
if len(cl) == 0 {
if t != nil {
yyerror("const declaration cannot have type without expression")
}
cl = lastconst
t = lasttype
lno = vl[0].Lineno
lno = vl[0].Pos
} else {
lastconst = cl
lasttype = t
@ -467,13 +469,13 @@ func colasdefn(left []*Node, defn *Node) {
continue
}
if !colasname(n) {
yyerrorl(defn.Lineno, "non-name %v on left side of :=", n)
yyerrorl(defn.Pos, "non-name %v on left side of :=", n)
nerr++
continue
}
if n.Sym.Flags&SymUniq == 0 {
yyerrorl(defn.Lineno, "%v repeated on left side of :=", n.Sym)
yyerrorl(defn.Pos, "%v repeated on left side of :=", n.Sym)
n.Diag = true
nerr++
continue
@ -493,7 +495,7 @@ func colasdefn(left []*Node, defn *Node) {
}
if nnew == 0 && nerr == 0 {
yyerrorl(defn.Lineno, "no new variables on left side of :=")
yyerrorl(defn.Pos, "no new variables on left side of :=")
}
}
@ -692,7 +694,7 @@ func typedcl0(s *Sym) *Node {
// node n, which was returned by typedcl0
// is being declared to have uncompiled type t.
// returns the ODCLTYPE node to use.
func typedcl1(n *Node, t *Node, pragma Pragma, alias bool) *Node {
func typedcl1(n *Node, t *Node, pragma syntax.Pragma, alias bool) *Node {
if pragma != 0 && alias {
yyerror("cannot specify directive with type alias")
pragma = 0
@ -724,14 +726,14 @@ func checkembeddedtype(t *Type) {
if t.IsPtr() || t.IsUnsafePtr() {
yyerror("embedded type cannot be a pointer")
} else if t.Etype == TFORW && t.ForwardType().Embedlineno == 0 {
} else if t.Etype == TFORW && !t.ForwardType().Embedlineno.IsKnown() {
t.ForwardType().Embedlineno = lineno
}
}
func structfield(n *Node) *Field {
lno := lineno
lineno = n.Lineno
lineno = n.Pos
if n.Op != ODCLFIELD {
Fatalf("structfield: oops %v\n", n)
@ -789,7 +791,7 @@ func checkdupfields(what string, ts ...*Type) {
continue
}
if seen[f.Sym] {
lineno = f.Nname.Lineno
lineno = f.Nname.Pos
yyerror("duplicate %s %s", what, f.Sym.Name)
continue
}
@ -870,7 +872,7 @@ func tofunargsfield(fields []*Field, funarg Funarg) *Type {
func interfacefield(n *Node) *Field {
lno := lineno
lineno = n.Lineno
lineno = n.Pos
if n.Op != ODCLFIELD {
Fatalf("interfacefield: oops %v\n", n)
@ -1352,7 +1354,7 @@ type nowritebarrierrecChecker struct {
type nowritebarrierrecCall struct {
target *Node
depth int
lineno int32
lineno src.XPos
}
func checknowritebarrierrec() {
@ -1362,8 +1364,8 @@ func checknowritebarrierrec() {
visitBottomUp(xtop, func(list []*Node, recursive bool) {
// Functions with write barriers have depth 0.
for _, n := range list {
if n.Func.WBLineno != 0 && n.Func.Pragma&Yeswritebarrierrec == 0 {
c.best[n] = nowritebarrierrecCall{target: nil, depth: 0, lineno: n.Func.WBLineno}
if n.Func.WBPos.IsKnown() && n.Func.Pragma&Yeswritebarrierrec == 0 {
c.best[n] = nowritebarrierrecCall{target: nil, depth: 0, lineno: n.Func.WBPos}
}
}
@ -1380,7 +1382,7 @@ func checknowritebarrierrec() {
// yeswritebarrierrec function.
continue
}
if n.Func.WBLineno == 0 {
if !n.Func.WBPos.IsKnown() {
c.curfn = n
c.visitcodelist(n.Nbody)
}
@ -1408,7 +1410,7 @@ func checknowritebarrierrec() {
call = c.best[n]
}
err = fmt.Sprintf("write barrier prohibited by caller; %v%s", n.Func.Nname, err)
yyerrorl(n.Func.WBLineno, err)
yyerrorl(n.Func.WBPos, err)
}
})
}
@ -1454,6 +1456,6 @@ func (c *nowritebarrierrecChecker) visitcall(n *Node) {
if ok && fnbest.depth+1 >= best.depth {
return
}
c.best[c.curfn] = nowritebarrierrecCall{target: defn, depth: fnbest.depth + 1, lineno: n.Lineno}
c.best[c.curfn] = nowritebarrierrecCall{target: defn, depth: fnbest.depth + 1, lineno: n.Pos}
c.stable = false
}

View file

@ -504,7 +504,7 @@ func escAnalyze(all []*Node, recursive bool) {
if n.Esc != escapes[i] {
done = false
if Debug['m'] > 2 {
Warnl(n.Lineno, "Reflooding %v %S", e.curfnSym(n), n)
Warnl(n.Pos, "Reflooding %v %S", e.curfnSym(n), n)
}
escapes[i] = n.Esc
e.escflood(n)
@ -525,7 +525,7 @@ func escAnalyze(all []*Node, recursive bool) {
if Debug['m'] != 0 {
for _, n := range e.noesc {
if n.Esc == EscNone {
Warnl(n.Lineno, "%v %S does not escape", e.curfnSym(n), n)
Warnl(n.Pos, "%v %S does not escape", e.curfnSym(n), n)
}
}
}
@ -678,7 +678,7 @@ func (e *EscState) esc(n *Node, parent *Node) {
(n.Op == ONEW || n.Op == OPTRLIT) && n.Type.Elem().Width >= 1<<16 ||
n.Op == OMAKESLICE && !isSmallMakeSlice(n)) {
if Debug['m'] > 2 {
Warnl(n.Lineno, "%v is too large for stack", n)
Warnl(n.Pos, "%v is too large for stack", n)
}
n.Esc = EscHeap
addrescapes(n)
@ -778,7 +778,7 @@ func (e *EscState) esc(n *Node, parent *Node) {
// b escapes as well. If we ignore such OSLICEARR, we will conclude
// that b does not escape when b contents do.
if Debug['m'] != 0 {
Warnl(n.Lineno, "%v ignoring self-assignment to %S", e.curfnSym(n), n.Left)
Warnl(n.Pos, "%v ignoring self-assignment to %S", e.curfnSym(n), n.Left)
}
break
@ -882,7 +882,7 @@ func (e *EscState) esc(n *Node, parent *Node) {
slice2 := n.List.Second()
e.escassignDereference(&e.theSink, slice2, e.stepAssignWhere(n, slice2, "appended slice...", n)) // lose track of assign of dereference
if Debug['m'] > 3 {
Warnl(n.Lineno, "%v special treatment of append(slice1, slice2...) %S", e.curfnSym(n), n)
Warnl(n.Pos, "%v special treatment of append(slice1, slice2...) %S", e.curfnSym(n), n)
}
}
e.escassignDereference(&e.theSink, n.List.First(), e.stepAssignWhere(n, n.List.First(), "appendee slice", n)) // The original elements are now leaked, too
@ -952,7 +952,7 @@ func (e *EscState) esc(n *Node, parent *Node) {
a := v.Name.Defn
if !v.Name.Byval {
a = nod(OADDR, a, nil)
a.Lineno = v.Lineno
a.Pos = v.Pos
e.nodeEscState(a).Loopdepth = e.loopdepth
a = typecheck(a, Erv)
}
@ -1145,7 +1145,7 @@ func (e *EscState) escassign(dst, src *Node, step *EscStep) {
// OCLOSURE is lowered to OPTRLIT,
// insert OADDR to account for the additional indirection.
a := nod(OADDR, src, nil)
a.Lineno = src.Lineno
a.Pos = src.Pos
e.nodeEscState(a).Loopdepth = e.nodeEscState(src).Loopdepth
a.Type = ptrto(src.Type)
e.escflows(dst, a, e.stepAssign(nil, originalDst, src, dstwhy))
@ -1383,7 +1383,7 @@ func (e *EscState) escassignDereference(dst *Node, src *Node, step *EscStep) {
func (e *EscState) addDereference(n *Node) *Node {
ind := nod(OIND, n, nil)
e.nodeEscState(ind).Loopdepth = e.nodeEscState(n).Loopdepth
ind.Lineno = n.Lineno
ind.Pos = n.Pos
t := n.Type
if t.IsKind(Tptr) {
// This should model our own sloppy use of OIND to encode
@ -1441,7 +1441,7 @@ func (e *EscState) initEscRetval(call *Node, fntype *Type) {
ret.Name.Curfn = Curfn
e.nodeEscState(ret).Loopdepth = e.loopdepth
ret.Used = true
ret.Lineno = call.Lineno
ret.Pos = call.Pos
cE.Retval.Append(ret)
}
}
@ -1546,7 +1546,7 @@ func (e *EscState) esccall(call *Node, parent *Node) {
arg = nod(ODDDARG, nil, nil)
arr := typArray(n.Type.Elem(), int64(len(args)))
arg.Type = ptrto(arr) // make pointer so it will be tracked
arg.Lineno = call.Lineno
arg.Pos = call.Pos
e.track(arg)
call.Right = arg
}
@ -1607,7 +1607,7 @@ func (e *EscState) esccall(call *Node, parent *Node) {
if param.Isddd && !call.Isddd {
// Introduce ODDDARG node to represent ... allocation.
arg = nod(ODDDARG, nil, nil)
arg.Lineno = call.Lineno
arg.Pos = call.Pos
arr := typArray(param.Type.Elem(), int64(len(args)-i))
arg.Type = ptrto(arr) // make pointer so it will be tracked
e.track(arg)
@ -1757,7 +1757,7 @@ func (es *EscStep) describe(src *Node) {
if where == nil {
where = dst
}
Warnl(src.Lineno, "\tfrom %v (%s) at %s", dst, step.why, where.Line())
Warnl(src.Pos, "\tfrom %v (%s) at %s", dst, step.why, where.Line())
}
for step := step0; step != nil && step.busy; step = step.parent {
step.busy = false
@ -1821,10 +1821,10 @@ func (e *EscState) escwalkBody(level Level, dst *Node, src *Node, step *EscStep,
// 4. return *in
if Debug['m'] != 0 {
if Debug['m'] <= 2 {
Warnl(src.Lineno, "leaking param: %S to result %v level=%v", src, dst.Sym, level.int())
Warnl(src.Pos, "leaking param: %S to result %v level=%v", src, dst.Sym, level.int())
step.describe(src)
} else {
Warnl(src.Lineno, "leaking param: %S to result %v level=%v", src, dst.Sym, level)
Warnl(src.Pos, "leaking param: %S to result %v level=%v", src, dst.Sym, level)
}
}
if src.Esc&EscMask != EscReturn {
@ -1841,7 +1841,7 @@ func (e *EscState) escwalkBody(level Level, dst *Node, src *Node, step *EscStep,
level.int() > 0 {
src.Esc = escMax(EscContentEscapes|src.Esc, EscNone)
if Debug['m'] != 0 {
Warnl(src.Lineno, "mark escaped content: %S", src)
Warnl(src.Pos, "mark escaped content: %S", src)
step.describe(src)
}
}
@ -1858,11 +1858,11 @@ func (e *EscState) escwalkBody(level Level, dst *Node, src *Node, step *EscStep,
if Debug['m'] != 0 {
if Debug['m'] <= 2 {
if osrcesc != src.Esc {
Warnl(src.Lineno, "leaking param content: %S", src)
Warnl(src.Pos, "leaking param content: %S", src)
step.describe(src)
}
} else {
Warnl(src.Lineno, "leaking param content: %S level=%v dst.eld=%v src.eld=%v dst=%S",
Warnl(src.Pos, "leaking param content: %S level=%v dst.eld=%v src.eld=%v dst=%S",
src, level, dstE.Loopdepth, modSrcLoopdepth, dst)
}
}
@ -1870,10 +1870,10 @@ func (e *EscState) escwalkBody(level Level, dst *Node, src *Node, step *EscStep,
src.Esc = EscHeap
if Debug['m'] != 0 {
if Debug['m'] <= 2 {
Warnl(src.Lineno, "leaking param: %S", src)
Warnl(src.Pos, "leaking param: %S", src)
step.describe(src)
} else {
Warnl(src.Lineno, "leaking param: %S level=%v dst.eld=%v src.eld=%v dst=%S",
Warnl(src.Pos, "leaking param: %S level=%v dst.eld=%v src.eld=%v dst=%S",
src, level, dstE.Loopdepth, modSrcLoopdepth, dst)
}
}
@ -1884,7 +1884,7 @@ func (e *EscState) escwalkBody(level Level, dst *Node, src *Node, step *EscStep,
// original variable.
if src.isClosureVar() {
if leaks && Debug['m'] != 0 {
Warnl(src.Lineno, "leaking closure reference %S", src)
Warnl(src.Pos, "leaking closure reference %S", src)
step.describe(src)
}
e.escwalk(level, dst, src.Name.Defn, e.stepWalk(dst, src.Name.Defn, "closure-var", step))
@ -1903,10 +1903,10 @@ func (e *EscState) escwalkBody(level Level, dst *Node, src *Node, step *EscStep,
p = p.Left // merely to satisfy error messages in tests
}
if Debug['m'] > 2 {
Warnl(src.Lineno, "%S escapes to heap, level=%v, dst=%v dst.eld=%v, src.eld=%v",
Warnl(src.Pos, "%S escapes to heap, level=%v, dst=%v dst.eld=%v, src.eld=%v",
p, level, dst, dstE.Loopdepth, modSrcLoopdepth)
} else {
Warnl(src.Lineno, "%S escapes to heap", p)
Warnl(src.Pos, "%S escapes to heap", p)
step.describe(src)
}
}
@ -1924,7 +1924,7 @@ func (e *EscState) escwalkBody(level Level, dst *Node, src *Node, step *EscStep,
if leaks {
src.Esc = EscHeap
if Debug['m'] != 0 && osrcesc != src.Esc {
Warnl(src.Lineno, "%S escapes to heap", src)
Warnl(src.Pos, "%S escapes to heap", src)
step.describe(src)
}
extraloopdepth = modSrcLoopdepth
@ -1959,7 +1959,7 @@ func (e *EscState) escwalkBody(level Level, dst *Node, src *Node, step *EscStep,
if leaks {
src.Esc = EscHeap
if Debug['m'] != 0 && osrcesc != src.Esc {
Warnl(src.Lineno, "%S escapes to heap", src)
Warnl(src.Pos, "%S escapes to heap", src)
step.describe(src)
}
extraloopdepth = modSrcLoopdepth
@ -2064,7 +2064,7 @@ func (e *EscState) esctag(fn *Node) {
narg++
if f.Type.Etype == TUINTPTR {
if Debug['m'] != 0 {
Warnl(fn.Lineno, "%v assuming %v is unsafe uintptr", funcSym(fn), name(f.Sym, narg))
Warnl(fn.Pos, "%v assuming %v is unsafe uintptr", funcSym(fn), name(f.Sym, narg))
}
f.Note = unsafeUintptrTag
}
@ -2079,7 +2079,7 @@ func (e *EscState) esctag(fn *Node) {
narg++
if f.Type.Etype == TUINTPTR {
if Debug['m'] != 0 {
Warnl(fn.Lineno, "%v marking %v as escaping uintptr", funcSym(fn), name(f.Sym, narg))
Warnl(fn.Pos, "%v marking %v as escaping uintptr", funcSym(fn), name(f.Sym, narg))
}
f.Note = uintptrEscapesTag
}
@ -2087,7 +2087,7 @@ func (e *EscState) esctag(fn *Node) {
if f.Isddd && f.Type.Elem().Etype == TUINTPTR {
// final argument is ...uintptr.
if Debug['m'] != 0 {
Warnl(fn.Lineno, "%v marking %v as escaping ...uintptr", funcSym(fn), name(f.Sym, narg))
Warnl(fn.Pos, "%v marking %v as escaping ...uintptr", funcSym(fn), name(f.Sym, narg))
}
f.Note = uintptrEscapesTag
}

View file

@ -283,8 +283,8 @@ func (n *Node) jconv(s fmt.State, flag FmtFlag) {
fmt.Fprintf(s, " g(%d)", n.Name.Vargen)
}
if n.Lineno != 0 {
fmt.Fprintf(s, " l(%d)", n.Lineno)
if n.Pos.IsKnown() {
fmt.Fprintf(s, " l(%d)", n.Pos.Line())
}
if c == 0 && n.Xoffset != BADWIDTH {

View file

@ -64,7 +64,7 @@ func addrescapes(n *Node) {
Curfn = Curfn.Func.Closure
}
ln := lineno
lineno = Curfn.Lineno
lineno = Curfn.Pos
moveToHeap(n)
Curfn = oldfn
lineno = ln

View file

@ -8,6 +8,7 @@ import (
"cmd/compile/internal/ssa"
"cmd/internal/bio"
"cmd/internal/obj"
"cmd/internal/src"
)
const (
@ -42,10 +43,10 @@ type Sym struct {
// saved and restored by dcopy
Pkg *Pkg
Name string // object name
Def *Node // definition: ONAME OTYPE OPACK or OLITERAL
Block int32 // blocknumber to catch redeclaration
Lastlineno int32 // last declaration for diagnostic
Name string // object name
Def *Node // definition: ONAME OTYPE OPACK or OLITERAL
Block int32 // blocknumber to catch redeclaration
Lastlineno src.XPos // last declaration for diagnostic
Label *Node // corresponding label (ephemeral)
Origpkg *Pkg // original package for . import
@ -115,8 +116,6 @@ var sizeof_String int // runtime sizeof(String)
var pragcgobuf string
var infile string
var outfile string
var linkobj string

View file

@ -40,12 +40,12 @@ func Prog(as obj.As) *obj.Prog {
Clearp(pc)
p.Link = pc
if lineno == 0 && Debug['K'] != 0 {
Warn("prog: line 0")
if !lineno.IsKnown() && Debug['K'] != 0 {
Warn("prog: unknown position (line 0)")
}
p.As = as
p.Lineno = lineno
p.Pos = lineno
return p
}
@ -60,7 +60,7 @@ func Appendpp(p *obj.Prog, as obj.As, ftype obj.AddrType, freg int16, foffset in
q := Ctxt.NewProg()
Clearp(q)
q.As = as
q.Lineno = p.Lineno
q.Pos = p.Pos
q.From.Type = ftype
q.From.Reg = freg
q.From.Offset = foffset

View file

@ -75,6 +75,9 @@ func anyinit(n []*Node) bool {
}
func fninit(n []*Node) {
// This code is using the last value of lineno for position information
// (see comment in noder.go, noder.file method, for details).
nf := initfix(n)
if !anyinit(nf) {
return

View file

@ -27,7 +27,10 @@
package gc
import "fmt"
import (
"cmd/internal/src"
"fmt"
)
// Get the function's package. For ordinary functions it's on the ->sym, but for imported methods
// the ->sym can be re-used in the local package, so peel it off the receiver's type.
@ -837,7 +840,7 @@ func mkinlcall1(n *Node, fn *Node, isddd bool) *Node {
args := as.Rlist
as.Rlist.Set(nil)
setlno(call, n.Lineno)
setlno(call, n.Pos)
as.Rlist.Set(args.Slice())
@ -1014,20 +1017,20 @@ func (subst *inlsubst) node(n *Node) *Node {
}
// Plaster over linenumbers
func setlnolist(ll Nodes, lno int32) {
func setlnolist(ll Nodes, lno src.XPos) {
for _, n := range ll.Slice() {
setlno(n, lno)
}
}
func setlno(n *Node, lno int32) {
func setlno(n *Node, lno src.XPos) {
if n == nil {
return
}
// don't clobber names, unless they're freshly synthesized
if n.Op != ONAME || n.Lineno == 0 {
n.Lineno = lno
if n.Op != ONAME || !n.Pos.IsKnown() {
n.Pos = lno
}
setlno(n.Left, lno)

View file

@ -7,16 +7,18 @@ package gc
import (
"cmd/compile/internal/syntax"
"cmd/internal/obj"
"cmd/internal/src"
"fmt"
"strings"
)
// lexlineno is the line number _after_ the most recently read rune.
// In particular, it's advanced (or rewound) as newlines are read (or unread).
var lexlineno int32
// lineno is the source position at the start of the most recently lexed token.
// TODO(gri) rename and eventually remove
var lineno src.XPos
// lineno is the line number at the start of the most recently lexed token.
var lineno int32
func MakePos(base *src.PosBase, line, col uint) src.XPos {
return Ctxt.PosTable.XPos(src.MakePos(base, line, col))
}
func isSpace(c rune) bool {
return c == ' ' || c == '\t' || c == '\n' || c == '\r'
@ -38,17 +40,15 @@ func plan9quote(s string) string {
return s
}
type Pragma syntax.Pragma
const (
// Func pragmas.
Nointerface Pragma = 1 << iota
Noescape // func parameters don't escape
Norace // func must not have race detector annotations
Nosplit // func should not execute on separate stack
Noinline // func should not be inlined
CgoUnsafeArgs // treat a pointer to one arg as a pointer to them all
UintptrEscapes // pointers converted to uintptr escape
Nointerface syntax.Pragma = 1 << iota
Noescape // func parameters don't escape
Norace // func must not have race detector annotations
Nosplit // func should not execute on separate stack
Noinline // func should not be inlined
CgoUnsafeArgs // treat a pointer to one arg as a pointer to them all
UintptrEscapes // pointers converted to uintptr escape
// Runtime-only func pragmas.
// See ../../../../runtime/README.md for detailed descriptions.
@ -61,7 +61,7 @@ const (
NotInHeap // values of this type must not be heap allocated
)
func pragmaValue(verb string) Pragma {
func pragmaValue(verb string) syntax.Pragma {
switch verb {
case "go:nointerface":
if obj.Fieldtrack_enabled != 0 {
@ -76,24 +76,12 @@ func pragmaValue(verb string) Pragma {
case "go:noinline":
return Noinline
case "go:systemstack":
if !compiling_runtime {
yyerror("//go:systemstack only allowed in runtime")
}
return Systemstack
case "go:nowritebarrier":
if !compiling_runtime {
yyerror("//go:nowritebarrier only allowed in runtime")
}
return Nowritebarrier
case "go:nowritebarrierrec":
if !compiling_runtime {
yyerror("//go:nowritebarrierrec only allowed in runtime")
}
return Nowritebarrierrec | Nowritebarrier // implies Nowritebarrier
case "go:yeswritebarrierrec":
if !compiling_runtime {
yyerror("//go:yeswritebarrierrec only allowed in runtime")
}
return Yeswritebarrierrec
case "go:cgo_unsafe_args":
return CgoUnsafeArgs

View file

@ -11,6 +11,7 @@ import (
"bytes"
"cmd/compile/internal/ssa"
"cmd/internal/obj"
"cmd/internal/src"
"cmd/internal/sys"
"flag"
"fmt"
@ -187,7 +188,7 @@ func Main() {
obj.Flagcount("r", "debug generated wrappers", &Debug['r'])
flag.BoolVar(&flag_race, "race", false, "enable race detector")
obj.Flagcount("s", "warn about composite literals that can be simplified", &Debug['s'])
flag.StringVar(&Ctxt.LineHist.TrimPathPrefix, "trimpath", "", "remove `prefix` from recorded source file paths")
flag.StringVar(&pathPrefix, "trimpath", "", "remove `prefix` from recorded source file paths")
flag.BoolVar(&safemode, "u", false, "reject unsafe code")
obj.Flagcount("v", "increase debug verbosity", &Debug['v'])
obj.Flagcount("w", "debug type checking", &Debug['w'])
@ -219,6 +220,26 @@ func Main() {
usage()
}
if outfile == "" {
p := flag.Arg(0)
if i := strings.LastIndex(p, "/"); i >= 0 {
p = p[i+1:]
}
if runtime.GOOS == "windows" {
if i := strings.LastIndex(p, `\`); i >= 0 {
p = p[i+1:]
}
}
if i := strings.LastIndex(p, "."); i >= 0 {
p = p[:i]
}
suffix := ".o"
if writearchive {
suffix = ".a"
}
outfile = p + suffix
}
startProfile()
if flag_race {
@ -301,33 +322,15 @@ func Main() {
blockgen = 1
dclcontext = PEXTERN
nerrors = 0
lexlineno = 1
timings.Start("fe", "loadsys")
loadsys()
timings.Start("fe", "parse")
lexlineno0 := lexlineno
for _, infile = range flag.Args() {
linehistpush(infile)
block = 1
iota_ = -1000000
imported_unsafe = false
parseFile(infile)
if nsyntaxerrors != 0 {
errorexit()
}
// Instead of converting EOF into '\n' in getc and count it as an extra line
// for the line history to work, and which then has to be corrected elsewhere,
// just add a line here.
lexlineno++
linehistpop()
}
lines := parseFiles(flag.Args())
timings.Stop()
timings.AddEvent(int64(lexlineno-lexlineno0), "lines")
timings.AddEvent(int64(lines), "lines")
mkpackage(localpkg.Name) // final import not used checks
finishUniverse()
typecheckok = true
@ -792,7 +795,8 @@ func importfile(f *Val, indent []byte) {
defer impf.Close()
imp := bufio.NewReader(impf)
if strings.HasSuffix(file, ".a") {
const pkgSuffix = ".a"
if strings.HasSuffix(file, pkgSuffix) {
if !skiptopkgdef(imp) {
yyerror("import %s: not a package file", file)
errorexit()
@ -840,9 +844,9 @@ func importfile(f *Val, indent []byte) {
yyerror("cannot import unsafe package %q", importpkg.Path)
}
// assume files move (get installed)
// so don't record the full path.
linehistpragma(file[len(file)-len(path_)-2:]) // acts as #pragma lib
// assume files move (get installed) so don't record the full path
// (e.g., for file "/Users/foo/go/pkg/darwin_amd64/math.a" record "math.a")
Ctxt.AddImport(file[len(file)-len(path_)-len(pkgSuffix):])
// In the importfile, if we find:
// $$\n (textual format): not supported anymore
@ -885,7 +889,7 @@ func importfile(f *Val, indent []byte) {
}
}
func pkgnotused(lineno int32, path string, name string) {
func pkgnotused(lineno src.XPos, path string, name string) {
// If the package was imported with a name other than the final
// import path element, show it explicitly in the error message.
// Note that this handles both renamed imports and imports of
@ -913,54 +917,37 @@ func mkpackage(pkgname string) {
if pkgname != localpkg.Name {
yyerror("package %s; expected %s", pkgname, localpkg.Name)
}
for _, s := range localpkg.Syms {
if s.Def == nil {
continue
}
if s.Def.Op == OPACK {
// throw away top-level package name leftover
// from previous file.
// leave s->block set to cause redeclaration
// errors if a conflicting top-level name is
// introduced by a different file.
if !s.Def.Used && nsyntaxerrors == 0 {
pkgnotused(s.Def.Lineno, s.Def.Name.Pkg.Path, s.Name)
}
s.Def = nil
continue
}
if s.isAlias() {
// throw away top-level name left over
// from previous import . "x"
if s.Def.Name != nil && s.Def.Name.Pack != nil && !s.Def.Name.Pack.Used && nsyntaxerrors == 0 {
pkgnotused(s.Def.Name.Pack.Lineno, s.Def.Name.Pack.Name.Pkg.Path, "")
s.Def.Name.Pack.Used = true
}
s.Def = nil
continue
}
}
}
if outfile == "" {
p := infile
if i := strings.LastIndex(p, "/"); i >= 0 {
p = p[i+1:]
}
if runtime.GOOS == "windows" {
if i := strings.LastIndex(p, `\`); i >= 0 {
p = p[i+1:]
}
}
if i := strings.LastIndex(p, "."); i >= 0 {
p = p[:i]
}
suffix := ".o"
if writearchive {
suffix = ".a"
}
outfile = p + suffix
}
}
func clearImports() {
for _, s := range localpkg.Syms {
if s.Def == nil {
continue
}
if s.Def.Op == OPACK {
// throw away top-level package name leftover
// from previous file.
// leave s->block set to cause redeclaration
// errors if a conflicting top-level name is
// introduced by a different file.
if !s.Def.Used && nsyntaxerrors == 0 {
pkgnotused(s.Def.Pos, s.Def.Name.Pkg.Path, s.Name)
}
s.Def = nil
continue
}
if s.isAlias() {
// throw away top-level name left over
// from previous import . "x"
if s.Def.Name != nil && s.Def.Name.Pack != nil && !s.Def.Name.Pack.Used && nsyntaxerrors == 0 {
pkgnotused(s.Def.Name.Pack.Pos, s.Def.Name.Pack.Name.Pkg.Path, "")
s.Def.Name.Pack.Used = true
}
s.Def = nil
continue
}
}
}

View file

@ -12,47 +12,109 @@ import (
"unicode/utf8"
"cmd/compile/internal/syntax"
"cmd/internal/obj"
"cmd/internal/src"
)
func parseFile(filename string) {
src, err := os.Open(filename)
if err != nil {
fmt.Println(err)
errorexit()
func parseFiles(filenames []string) uint {
var lines uint
var noders []*noder
for _, filename := range filenames {
p := &noder{err: make(chan syntax.Error)}
noders = append(noders, p)
go func(filename string) {
defer close(p.err)
base := src.NewFileBase(filename, absFilename(filename))
f, err := os.Open(filename)
if err != nil {
p.error(syntax.Error{Pos: src.MakePos(base, 0, 0), Msg: err.Error()})
return
}
defer f.Close()
p.file, _ = syntax.Parse(base, f, p.error, p.pragma, 0) // errors are tracked via p.error
}(filename)
}
defer src.Close()
p := noder{baseline: lexlineno}
file, _ := syntax.Parse(src, p.error, p.pragma, 0) // errors are tracked via p.error
p.file(file)
if !imported_unsafe {
for _, x := range p.linknames {
p.error(syntax.Error{Line: x, Msg: "//go:linkname only allowed in Go files that import \"unsafe\""})
for _, p := range noders {
for e := range p.err {
yyerrorpos(e.Pos, "%s", e.Msg)
}
}
if nsyntaxerrors == 0 {
p.node()
lines += p.file.Lines
p.file = nil // release memory
if nsyntaxerrors != 0 {
errorexit()
}
// Always run testdclstack here, even when debug_dclstack is not set, as a sanity measure.
testdclstack()
}
return lines
}
// noder transforms package syntax's AST into a Nod tree.
func yyerrorpos(pos src.Pos, format string, args ...interface{}) {
yyerrorl(Ctxt.PosTable.XPos(pos), format, args...)
}
var pathPrefix string
func absFilename(name string) string {
return obj.AbsFile(Ctxt.Pathname, name, pathPrefix)
}
// noder transforms package syntax's AST into a Node tree.
type noder struct {
baseline int32
linknames []int // tracks //go:linkname lines
file *syntax.File
linknames []linkname
pragcgobuf string
err chan syntax.Error
}
func (p *noder) file(file *syntax.File) {
p.lineno(file.PkgName)
mkpackage(file.PkgName.Value)
// linkname records a //go:linkname directive.
type linkname struct {
pos src.Pos
local string
remote string
}
xtop = append(xtop, p.decls(file.DeclList)...)
func (p *noder) node() {
block = 1
iota_ = -1000000
imported_unsafe = false
lexlineno = p.baseline + int32(file.Lines) - 1
lineno = lexlineno
p.lineno(p.file.PkgName)
mkpackage(p.file.PkgName.Value)
xtop = append(xtop, p.decls(p.file.DeclList)...)
for _, n := range p.linknames {
if imported_unsafe {
lookup(n.local).Linkname = n.remote
} else {
yyerrorpos(n.pos, "//go:linkname only allowed in Go files that import \"unsafe\"")
}
}
pragcgobuf += p.pragcgobuf
// For compatibility with old code only (comparisons w/ toolstash):
// The old line number tracking simply continued incrementing the
// virtual line number (lexlineno) and using it also for lineno.
// After processing the last function, the lineno was used for the
// line number information of the initialization code (fninit).
// It would be better to use an explicit "<autogenerated>" filename
// for fninit and set lineno to NoPos here.
// TODO(gri) fix this once we switched permanently to the new
// position information.
lineno = MakePos(p.file.Pos().Base(), uint(p.file.Lines), 0)
clearImports()
}
func (p *noder) decls(decls []syntax.Decl) (l []*Node) {
@ -137,18 +199,18 @@ func (p *noder) importDecl(imp *syntax.ImportDecl) {
return
}
if my.Name == "init" {
yyerrorl(pack.Lineno, "cannot import package as init - init must be a func")
yyerrorl(pack.Pos, "cannot import package as init - init must be a func")
return
}
if my.Name == "_" {
return
}
if my.Def != nil {
lineno = pack.Lineno
lineno = pack.Pos
redeclare(my, "as imported package name")
}
my.Def = pack
my.Lastlineno = pack.Lineno
my.Lastlineno = pack.Pos
my.Block = 1 // at top level
}
@ -183,7 +245,7 @@ func (p *noder) typeDecl(decl *syntax.TypeDecl) *Node {
// decl.Type may be nil but in that case we got a syntax error during parsing
typ := p.typeExprOrNil(decl.Type)
return typedcl1(name, typ, Pragma(decl.Pragma), decl.Alias)
return typedcl1(name, typ, syntax.Pragma(decl.Pragma), decl.Alias)
}
func (p *noder) declNames(names []*syntax.Name) []*Node {
@ -213,7 +275,7 @@ func (p *noder) funcDecl(fun *syntax.FuncDecl) *Node {
}
}
pragma := Pragma(fun.Pragma)
pragma := fun.Pragma
f.Nbody.Set(body)
f.Noescape = pragma&Noescape != 0
@ -221,7 +283,7 @@ func (p *noder) funcDecl(fun *syntax.FuncDecl) *Node {
yyerror("can only use //go:noescape with external func implementations")
}
f.Func.Pragma = pragma
lineno = p.baseline + int32(fun.EndLine) - 1
lineno = MakePos(fun.Pos().Base(), fun.EndLine, 0)
f.Func.Endlineno = lineno
funcbody(f)
@ -347,14 +409,14 @@ func (p *noder) expr(expr syntax.Expr) *Node {
l[i] = p.wrapname(expr.ElemList[i], e)
}
n.List.Set(l)
lineno = p.baseline + int32(expr.EndLine) - 1
lineno = MakePos(expr.Pos().Base(), expr.EndLine, 0)
return n
case *syntax.KeyValueExpr:
return p.nod(expr, OKEY, p.expr(expr.Key), p.wrapname(expr.Value, p.expr(expr.Value)))
case *syntax.FuncLit:
closurehdr(p.typeExpr(expr.Type))
body := p.stmts(expr.Body)
lineno = p.baseline + int32(expr.EndLine) - 1
lineno = MakePos(expr.Pos().Base(), expr.EndLine, 0)
return p.setlineno(expr, closurebody(body))
case *syntax.ParenExpr:
return p.nod(expr, OPAREN, p.expr(expr.X), nil)
@ -982,13 +1044,13 @@ func (p *noder) nod(orig syntax.Node, op Op, left, right *Node) *Node {
return p.setlineno(orig, nod(op, left, right))
}
func (p *noder) setlineno(src syntax.Node, dst *Node) *Node {
l := int32(src.Line())
if l == 0 {
func (p *noder) setlineno(src_ syntax.Node, dst *Node) *Node {
pos := src_.Pos()
if !pos.IsKnown() {
// TODO(mdempsky): Shouldn't happen. Fix package syntax.
return dst
}
dst.Lineno = p.baseline + l - 1
dst.Pos = Ctxt.PosTable.XPos(pos)
return dst
}
@ -996,72 +1058,47 @@ func (p *noder) lineno(n syntax.Node) {
if n == nil {
return
}
l := int32(n.Line())
if l == 0 {
pos := n.Pos()
if !pos.IsKnown() {
// TODO(mdempsky): Shouldn't happen. Fix package syntax.
return
}
lineno = p.baseline + l - 1
lineno = Ctxt.PosTable.XPos(pos)
}
func (p *noder) error(err error) {
line := p.baseline
var msg string
if err, ok := err.(syntax.Error); ok {
line += int32(err.Line) - 1
msg = err.Msg
} else {
msg = err.Error()
}
yyerrorl(line, "%s", msg)
p.err <- err.(syntax.Error)
}
func (p *noder) pragma(pos, line int, text string) syntax.Pragma {
func (p *noder) pragma(pos src.Pos, text string) syntax.Pragma {
switch {
case strings.HasPrefix(text, "line "):
// Want to use LastIndexByte below but it's not defined in Go1.4 and bootstrap fails.
i := strings.LastIndex(text, ":") // look from right (Windows filenames may contain ':')
if i < 0 {
break
}
n, err := strconv.Atoi(text[i+1:])
if err != nil {
// TODO: make this an error instead? it is almost certainly a bug.
break
}
if n > 1e8 {
p.error(syntax.Error{Pos: pos, Line: line, Msg: "line number out of range"})
errorexit()
}
if n <= 0 {
break
}
lexlineno = p.baseline + int32(line)
linehistupdate(text[5:i], n)
// line directives are handled by syntax package
panic("unreachable")
case strings.HasPrefix(text, "go:linkname "):
// Record line number so we can emit an error later if
// the file doesn't import package unsafe.
p.linknames = append(p.linknames, line)
f := strings.Fields(text)
if len(f) != 3 {
p.error(syntax.Error{Pos: pos, Line: line, Msg: "usage: //go:linkname localname linkname"})
p.error(syntax.Error{Pos: pos, Msg: "usage: //go:linkname localname linkname"})
break
}
lookup(f[1]).Linkname = f[2]
p.linknames = append(p.linknames, linkname{pos, f[1], f[2]})
case strings.HasPrefix(text, "go:cgo_"):
lineno = p.baseline + int32(line) - 1 // pragcgo may call yyerror
pragcgobuf += pragcgo(text)
// TODO(gri): lineno = p.baseline + int32(line) - 1 // pragcgo may call yyerror
p.pragcgobuf += pragcgo(text)
fallthrough // because of //go:cgo_unsafe_args
default:
verb := text
if i := strings.Index(text, " "); i >= 0 {
verb = verb[:i]
}
lineno = p.baseline + int32(line) - 1 // pragmaValue may call yyerror
return syntax.Pragma(pragmaValue(verb))
prag := pragmaValue(verb)
const runtimePragmas = Systemstack | Nowritebarrier | Nowritebarrierrec | Yeswritebarrierrec
if !compiling_runtime && prag&runtimePragmas != 0 {
p.error(syntax.Error{Pos: pos, Msg: fmt.Sprintf("//go:%s only allowed in runtime", verb)})
}
return prag
}
return 0

View file

@ -5,6 +5,7 @@
package gc
import (
"cmd/internal/src"
"fmt"
)
@ -510,7 +511,7 @@ func orderstmt(n *Node, order *Order) {
n.Left = orderexpr(n.Left, order, nil)
n.Left = ordersafeexpr(n.Left, order)
tmp1 := treecopy(n.Left, 0)
tmp1 := treecopy(n.Left, src.NoXPos)
if tmp1.Op == OINDEXMAP {
tmp1.Etype = 0 // now an rvalue not an lvalue
}

View file

@ -7,6 +7,7 @@ package gc
import (
"cmd/compile/internal/ssa"
"cmd/internal/obj"
"cmd/internal/src"
"cmd/internal/sys"
"fmt"
"sort"
@ -311,7 +312,7 @@ func compile(fn *Node) {
assertI2I2 = Sysfunc("assertI2I2")
}
defer func(lno int32) {
defer func(lno src.XPos) {
lineno = lno
}(setlineno(fn))

View file

@ -6,6 +6,7 @@ package gc
import (
"cmd/compile/internal/ssa"
"cmd/internal/src"
"container/heap"
"fmt"
)
@ -233,7 +234,7 @@ func (s *phiState) insertVarPhis(n int, var_ *Node, defs []*ssa.Block, typ ssa.T
if !hasPhi.contains(c.ID) {
// Add a phi to block c for variable n.
hasPhi.add(c.ID)
v := c.NewValue0I(currentRoot.Line, ssa.OpPhi, typ, int64(n)) // TODO: line number right?
v := c.NewValue0I(currentRoot.Pos, ssa.OpPhi, typ, int64(n)) // TODO: line number right?
// Note: we store the variable number in the phi's AuxInt field. Used temporarily by phi building.
s.s.addNamedValue(var_, v)
for i := 0; i < len(c.Preds); i++ {
@ -466,7 +467,7 @@ loop:
// Find variable value on each predecessor.
args = args[:0]
for _, e := range b.Preds {
args = append(args, s.lookupVarOutgoing(e.Block(), v.Type, var_, v.Line))
args = append(args, s.lookupVarOutgoing(e.Block(), v.Type, var_, v.Pos))
}
// Decide if we need a phi or not. We need a phi if there
@ -499,7 +500,7 @@ loop:
}
// lookupVarOutgoing finds the variable's value at the end of block b.
func (s *simplePhiState) lookupVarOutgoing(b *ssa.Block, t ssa.Type, var_ *Node, line int32) *ssa.Value {
func (s *simplePhiState) lookupVarOutgoing(b *ssa.Block, t ssa.Type, var_ *Node, line src.XPos) *ssa.Value {
for {
if v := s.defvars[b.ID][var_]; v != nil {
return v

View file

@ -1014,7 +1014,7 @@ func unlinkedprog(as obj.As) *obj.Prog {
// covering an existing instruction.
func newpcdataprog(prog *obj.Prog, index int32) *obj.Prog {
pcdata := unlinkedprog(obj.APCDATA)
pcdata.Lineno = prog.Lineno
pcdata.Pos = prog.Pos
pcdata.From.Type = obj.TYPE_CONST
pcdata.From.Offset = obj.PCDATA_StackMapIndex
pcdata.To.Type = obj.TYPE_CONST
@ -1253,7 +1253,7 @@ func livenessepilogue(lv *Liveness) {
if !n.Name.Needzero {
n.Name.Needzero = true
if debuglive >= 1 {
Warnl(p.Lineno, "%v: %L is ambiguously live", Curfn.Func.Nname, n)
Warnl(p.Pos, "%v: %L is ambiguously live", Curfn.Func.Nname, n)
}
}
}
@ -1344,7 +1344,7 @@ func livenessepilogue(lv *Liveness) {
}
n := lv.vars[j]
if n.Class != PPARAM {
yyerrorl(p.Lineno, "internal error: %v %L recorded as live on entry, p.Pc=%v", Curfn.Func.Nname, n, p.Pc)
yyerrorl(p.Pos, "internal error: %v %L recorded as live on entry, p.Pc=%v", Curfn.Func.Nname, n, p.Pc)
}
}
}

View file

@ -5,6 +5,7 @@
package gc
import (
"cmd/internal/src"
"fmt"
"strings"
)
@ -495,7 +496,7 @@ func callinstr(np **Node, init *Nodes, wr int, skip int) bool {
*np = n
}
n = treecopy(n, 0)
n = treecopy(n, src.NoXPos)
makeaddable(n)
var f *Node
if flag_msan {

View file

@ -258,7 +258,7 @@ func staticinit(n *Node, out *[]*Node) bool {
Fatalf("staticinit")
}
lineno = n.Lineno
lineno = n.Pos
l := n.Name.Defn.Left
r := n.Name.Defn.Right
return staticassign(l, r, out)
@ -469,7 +469,7 @@ func staticassign(l *Node, r *Node, out *[]*Node) bool {
case OCLOSURE:
if hasemptycvars(r) {
if Debug_closure > 0 {
Warnl(r.Lineno, "closure converted to global")
Warnl(r.Pos, "closure converted to global")
}
// Closures with no captured variables are globals,
// so the assignment can be done at link time.

View file

@ -22,14 +22,14 @@ func TestSizeof(t *testing.T) {
_32bit uintptr // size on 32bit platforms
_64bit uintptr // size on 64bit platforms
}{
{Func{}, 92, 160},
{Func{}, 100, 168},
{Name{}, 44, 72},
{Param{}, 24, 48},
{Node{}, 92, 144},
{Sym{}, 60, 112},
{Type{}, 60, 96},
{Node{}, 96, 152},
{Sym{}, 64, 120},
{Type{}, 64, 104},
{MapType{}, 20, 40},
{ForwardType{}, 16, 32},
{ForwardType{}, 20, 32},
{FuncType{}, 28, 48},
{StructType{}, 12, 24},
{InterType{}, 4, 8},

View file

@ -14,6 +14,7 @@ import (
"cmd/compile/internal/ssa"
"cmd/internal/obj"
"cmd/internal/src"
"cmd/internal/sys"
)
@ -43,7 +44,7 @@ func buildssa(fn *Node) *ssa.Func {
}
var s state
s.pushLine(fn.Lineno)
s.pushLine(fn.Pos)
defer s.popLine()
if fn.Func.Pragma&CgoUnsafeArgs != 0 {
@ -53,8 +54,8 @@ func buildssa(fn *Node) *ssa.Func {
s.noWB = true
}
defer func() {
if s.WBLineno != 0 {
fn.Func.WBLineno = s.WBLineno
if s.WBPos.IsKnown() {
fn.Func.WBPos = s.WBPos
}
}()
// TODO(khr): build config just once at the start of the compiler binary
@ -148,11 +149,11 @@ func buildssa(fn *Node) *ssa.Func {
// Check that we used all labels
for name, lab := range s.labels {
if !lab.used() && !lab.reported && !lab.defNode.Used {
yyerrorl(lab.defNode.Lineno, "label %v defined and not used", name)
yyerrorl(lab.defNode.Pos, "label %v defined and not used", name)
lab.reported = true
}
if lab.used() && !lab.defined() && !lab.reported {
yyerrorl(lab.useNode.Lineno, "label %v not defined", name)
yyerrorl(lab.useNode.Pos, "label %v not defined", name)
lab.reported = true
}
}
@ -231,7 +232,7 @@ type state struct {
sb *ssa.Value
// line number stack. The current line number is top of stack
line []int32
line []src.XPos
// list of panic calls by function name and line number.
// Used to deduplicate panic calls.
@ -245,12 +246,12 @@ type state struct {
cgoUnsafeArgs bool
noWB bool
WBLineno int32 // line number of first write barrier. 0=no write barriers
WBPos src.XPos // line number of first write barrier. 0=no write barriers
}
type funcLine struct {
f *Node
line int32
line src.XPos
}
type ssaLabel struct {
@ -281,11 +282,13 @@ func (s *state) label(sym *Sym) *ssaLabel {
return lab
}
func (s *state) Logf(msg string, args ...interface{}) { s.config.Logf(msg, args...) }
func (s *state) Log() bool { return s.config.Log() }
func (s *state) Fatalf(msg string, args ...interface{}) { s.config.Fatalf(s.peekLine(), msg, args...) }
func (s *state) Warnl(line int32, msg string, args ...interface{}) { s.config.Warnl(line, msg, args...) }
func (s *state) Debug_checknil() bool { return s.config.Debug_checknil() }
func (s *state) Logf(msg string, args ...interface{}) { s.config.Logf(msg, args...) }
func (s *state) Log() bool { return s.config.Log() }
func (s *state) Fatalf(msg string, args ...interface{}) { s.config.Fatalf(s.peekPos(), msg, args...) }
func (s *state) Warnl(pos src.XPos, msg string, args ...interface{}) {
s.config.Warnl(pos, msg, args...)
}
func (s *state) Debug_checknil() bool { return s.config.Debug_checknil() }
var (
// dummy node for the memory variable
@ -326,18 +329,18 @@ func (s *state) endBlock() *ssa.Block {
s.defvars[b.ID] = s.vars
s.curBlock = nil
s.vars = nil
b.Line = s.peekLine()
b.Pos = s.peekPos()
return b
}
// pushLine pushes a line number on the line number stack.
func (s *state) pushLine(line int32) {
if line == 0 {
func (s *state) pushLine(line src.XPos) {
if !line.IsKnown() {
// the frontend may emit node with line number missing,
// use the parent line number in this case.
line = s.peekLine()
line = s.peekPos()
if Debug['K'] != 0 {
Warn("buildssa: line 0")
Warn("buildssa: unknown position (line 0)")
}
}
s.line = append(s.line, line)
@ -348,130 +351,130 @@ func (s *state) popLine() {
s.line = s.line[:len(s.line)-1]
}
// peekLine peek the top of the line number stack.
func (s *state) peekLine() int32 {
// peekPos peeks the top of the line number stack.
func (s *state) peekPos() src.XPos {
return s.line[len(s.line)-1]
}
func (s *state) Error(msg string, args ...interface{}) {
yyerrorl(s.peekLine(), msg, args...)
yyerrorl(s.peekPos(), msg, args...)
}
// newValue0 adds a new value with no arguments to the current block.
func (s *state) newValue0(op ssa.Op, t ssa.Type) *ssa.Value {
return s.curBlock.NewValue0(s.peekLine(), op, t)
return s.curBlock.NewValue0(s.peekPos(), op, t)
}
// newValue0A adds a new value with no arguments and an aux value to the current block.
func (s *state) newValue0A(op ssa.Op, t ssa.Type, aux interface{}) *ssa.Value {
return s.curBlock.NewValue0A(s.peekLine(), op, t, aux)
return s.curBlock.NewValue0A(s.peekPos(), op, t, aux)
}
// newValue0I adds a new value with no arguments and an auxint value to the current block.
func (s *state) newValue0I(op ssa.Op, t ssa.Type, auxint int64) *ssa.Value {
return s.curBlock.NewValue0I(s.peekLine(), op, t, auxint)
return s.curBlock.NewValue0I(s.peekPos(), op, t, auxint)
}
// newValue1 adds a new value with one argument to the current block.
func (s *state) newValue1(op ssa.Op, t ssa.Type, arg *ssa.Value) *ssa.Value {
return s.curBlock.NewValue1(s.peekLine(), op, t, arg)
return s.curBlock.NewValue1(s.peekPos(), op, t, arg)
}
// newValue1A adds a new value with one argument and an aux value to the current block.
func (s *state) newValue1A(op ssa.Op, t ssa.Type, aux interface{}, arg *ssa.Value) *ssa.Value {
return s.curBlock.NewValue1A(s.peekLine(), op, t, aux, arg)
return s.curBlock.NewValue1A(s.peekPos(), op, t, aux, arg)
}
// newValue1I adds a new value with one argument and an auxint value to the current block.
func (s *state) newValue1I(op ssa.Op, t ssa.Type, aux int64, arg *ssa.Value) *ssa.Value {
return s.curBlock.NewValue1I(s.peekLine(), op, t, aux, arg)
return s.curBlock.NewValue1I(s.peekPos(), op, t, aux, arg)
}
// newValue2 adds a new value with two arguments to the current block.
func (s *state) newValue2(op ssa.Op, t ssa.Type, arg0, arg1 *ssa.Value) *ssa.Value {
return s.curBlock.NewValue2(s.peekLine(), op, t, arg0, arg1)
return s.curBlock.NewValue2(s.peekPos(), op, t, arg0, arg1)
}
// newValue2I adds a new value with two arguments and an auxint value to the current block.
func (s *state) newValue2I(op ssa.Op, t ssa.Type, aux int64, arg0, arg1 *ssa.Value) *ssa.Value {
return s.curBlock.NewValue2I(s.peekLine(), op, t, aux, arg0, arg1)
return s.curBlock.NewValue2I(s.peekPos(), op, t, aux, arg0, arg1)
}
// newValue3 adds a new value with three arguments to the current block.
func (s *state) newValue3(op ssa.Op, t ssa.Type, arg0, arg1, arg2 *ssa.Value) *ssa.Value {
return s.curBlock.NewValue3(s.peekLine(), op, t, arg0, arg1, arg2)
return s.curBlock.NewValue3(s.peekPos(), op, t, arg0, arg1, arg2)
}
// newValue3I adds a new value with three arguments and an auxint value to the current block.
func (s *state) newValue3I(op ssa.Op, t ssa.Type, aux int64, arg0, arg1, arg2 *ssa.Value) *ssa.Value {
return s.curBlock.NewValue3I(s.peekLine(), op, t, aux, arg0, arg1, arg2)
return s.curBlock.NewValue3I(s.peekPos(), op, t, aux, arg0, arg1, arg2)
}
// newValue4 adds a new value with four arguments to the current block.
func (s *state) newValue4(op ssa.Op, t ssa.Type, arg0, arg1, arg2, arg3 *ssa.Value) *ssa.Value {
return s.curBlock.NewValue4(s.peekLine(), op, t, arg0, arg1, arg2, arg3)
return s.curBlock.NewValue4(s.peekPos(), op, t, arg0, arg1, arg2, arg3)
}
// entryNewValue0 adds a new value with no arguments to the entry block.
func (s *state) entryNewValue0(op ssa.Op, t ssa.Type) *ssa.Value {
return s.f.Entry.NewValue0(s.peekLine(), op, t)
return s.f.Entry.NewValue0(s.peekPos(), op, t)
}
// entryNewValue0A adds a new value with no arguments and an aux value to the entry block.
func (s *state) entryNewValue0A(op ssa.Op, t ssa.Type, aux interface{}) *ssa.Value {
return s.f.Entry.NewValue0A(s.peekLine(), op, t, aux)
return s.f.Entry.NewValue0A(s.peekPos(), op, t, aux)
}
// entryNewValue0I adds a new value with no arguments and an auxint value to the entry block.
func (s *state) entryNewValue0I(op ssa.Op, t ssa.Type, auxint int64) *ssa.Value {
return s.f.Entry.NewValue0I(s.peekLine(), op, t, auxint)
return s.f.Entry.NewValue0I(s.peekPos(), op, t, auxint)
}
// entryNewValue1 adds a new value with one argument to the entry block.
func (s *state) entryNewValue1(op ssa.Op, t ssa.Type, arg *ssa.Value) *ssa.Value {
return s.f.Entry.NewValue1(s.peekLine(), op, t, arg)
return s.f.Entry.NewValue1(s.peekPos(), op, t, arg)
}
// entryNewValue1 adds a new value with one argument and an auxint value to the entry block.
func (s *state) entryNewValue1I(op ssa.Op, t ssa.Type, auxint int64, arg *ssa.Value) *ssa.Value {
return s.f.Entry.NewValue1I(s.peekLine(), op, t, auxint, arg)
return s.f.Entry.NewValue1I(s.peekPos(), op, t, auxint, arg)
}
// entryNewValue1A adds a new value with one argument and an aux value to the entry block.
func (s *state) entryNewValue1A(op ssa.Op, t ssa.Type, aux interface{}, arg *ssa.Value) *ssa.Value {
return s.f.Entry.NewValue1A(s.peekLine(), op, t, aux, arg)
return s.f.Entry.NewValue1A(s.peekPos(), op, t, aux, arg)
}
// entryNewValue2 adds a new value with two arguments to the entry block.
func (s *state) entryNewValue2(op ssa.Op, t ssa.Type, arg0, arg1 *ssa.Value) *ssa.Value {
return s.f.Entry.NewValue2(s.peekLine(), op, t, arg0, arg1)
return s.f.Entry.NewValue2(s.peekPos(), op, t, arg0, arg1)
}
// const* routines add a new const value to the entry block.
func (s *state) constSlice(t ssa.Type) *ssa.Value { return s.f.ConstSlice(s.peekLine(), t) }
func (s *state) constInterface(t ssa.Type) *ssa.Value { return s.f.ConstInterface(s.peekLine(), t) }
func (s *state) constNil(t ssa.Type) *ssa.Value { return s.f.ConstNil(s.peekLine(), t) }
func (s *state) constEmptyString(t ssa.Type) *ssa.Value { return s.f.ConstEmptyString(s.peekLine(), t) }
func (s *state) constSlice(t ssa.Type) *ssa.Value { return s.f.ConstSlice(s.peekPos(), t) }
func (s *state) constInterface(t ssa.Type) *ssa.Value { return s.f.ConstInterface(s.peekPos(), t) }
func (s *state) constNil(t ssa.Type) *ssa.Value { return s.f.ConstNil(s.peekPos(), t) }
func (s *state) constEmptyString(t ssa.Type) *ssa.Value { return s.f.ConstEmptyString(s.peekPos(), t) }
func (s *state) constBool(c bool) *ssa.Value {
return s.f.ConstBool(s.peekLine(), Types[TBOOL], c)
return s.f.ConstBool(s.peekPos(), Types[TBOOL], c)
}
func (s *state) constInt8(t ssa.Type, c int8) *ssa.Value {
return s.f.ConstInt8(s.peekLine(), t, c)
return s.f.ConstInt8(s.peekPos(), t, c)
}
func (s *state) constInt16(t ssa.Type, c int16) *ssa.Value {
return s.f.ConstInt16(s.peekLine(), t, c)
return s.f.ConstInt16(s.peekPos(), t, c)
}
func (s *state) constInt32(t ssa.Type, c int32) *ssa.Value {
return s.f.ConstInt32(s.peekLine(), t, c)
return s.f.ConstInt32(s.peekPos(), t, c)
}
func (s *state) constInt64(t ssa.Type, c int64) *ssa.Value {
return s.f.ConstInt64(s.peekLine(), t, c)
return s.f.ConstInt64(s.peekPos(), t, c)
}
func (s *state) constFloat32(t ssa.Type, c float64) *ssa.Value {
return s.f.ConstFloat32(s.peekLine(), t, c)
return s.f.ConstFloat32(s.peekPos(), t, c)
}
func (s *state) constFloat64(t ssa.Type, c float64) *ssa.Value {
return s.f.ConstFloat64(s.peekLine(), t, c)
return s.f.ConstFloat64(s.peekPos(), t, c)
}
func (s *state) constInt(t ssa.Type, c int64) *ssa.Value {
if s.config.IntSize == 8 {
@ -492,7 +495,7 @@ func (s *state) stmtList(l Nodes) {
// stmt converts the statement n to SSA and adds it to s.
func (s *state) stmt(n *Node) {
s.pushLine(n.Lineno)
s.pushLine(n.Pos)
defer s.popLine()
// If s.curBlock is nil, then we're about to generate dead code.
@ -558,8 +561,8 @@ func (s *state) stmt(n *Node) {
deref = true
res = res.Args[0]
}
s.assign(n.List.First(), res, needwritebarrier(n.List.First(), n.Rlist.First()), deref, n.Lineno, 0, false)
s.assign(n.List.Second(), resok, false, false, n.Lineno, 0, false)
s.assign(n.List.First(), res, needwritebarrier(n.List.First(), n.Rlist.First()), deref, n.Pos, 0, false)
s.assign(n.List.Second(), resok, false, false, n.Pos, 0, false)
return
case OAS2FUNC:
@ -574,8 +577,8 @@ func (s *state) stmt(n *Node) {
// This is future-proofing against non-scalar 2-result intrinsics.
// Currently we only have scalar ones, which result in no write barrier.
fakeret := &Node{Op: OINDREGSP}
s.assign(n.List.First(), v1, needwritebarrier(n.List.First(), fakeret), false, n.Lineno, 0, false)
s.assign(n.List.Second(), v2, needwritebarrier(n.List.Second(), fakeret), false, n.Lineno, 0, false)
s.assign(n.List.First(), v1, needwritebarrier(n.List.First(), fakeret), false, n.Pos, 0, false)
s.assign(n.List.Second(), v2, needwritebarrier(n.List.Second(), fakeret), false, n.Pos, 0, false)
return
case ODCL:
@ -605,7 +608,7 @@ func (s *state) stmt(n *Node) {
if !lab.defined() {
lab.defNode = n
} else {
s.Error("label %v already defined at %v", sym, linestr(lab.defNode.Lineno))
s.Error("label %v already defined at %v", sym, linestr(lab.defNode.Pos))
lab.reported = true
}
// The label might already have a target block via a goto.
@ -690,13 +693,13 @@ func (s *state) stmt(n *Node) {
if samesafeexpr(n.Left, rhs.List.First()) {
if !s.canSSA(n.Left) {
if Debug_append > 0 {
Warnl(n.Lineno, "append: len-only update")
Warnl(n.Pos, "append: len-only update")
}
s.append(rhs, true)
return
} else {
if Debug_append > 0 { // replicating old diagnostic message
Warnl(n.Lineno, "append: len-only update (in local slice)")
Warnl(n.Pos, "append: len-only update (in local slice)")
}
}
}
@ -759,7 +762,7 @@ func (s *state) stmt(n *Node) {
}
}
s.assign(n.Left, r, needwb, deref, n.Lineno, skip, isVolatile)
s.assign(n.Left, r, needwb, deref, n.Pos, skip, isVolatile)
case OIF:
bThen := s.f.NewBlock(ssa.BlockPlain)
@ -1435,7 +1438,7 @@ func (s *state) expr(n *Node) *ssa.Value {
if !(n.Op == ONAME || n.Op == OLITERAL && n.Sym != nil) {
// ONAMEs and named OLITERALs have the line number
// of the decl, not the use. See issue 14742.
s.pushLine(n.Lineno)
s.pushLine(n.Pos)
defer s.popLine()
}
@ -1969,7 +1972,7 @@ func (s *state) expr(n *Node) *ssa.Value {
return s.newValue2(ssa.OpLoad, n.Type, addr, s.mem())
case OIND:
p := s.exprPtr(n.Left, false, n.Lineno)
p := s.exprPtr(n.Left, false, n.Pos)
return s.newValue2(ssa.OpLoad, n.Type, p, s.mem())
case ODOT:
@ -1982,7 +1985,7 @@ func (s *state) expr(n *Node) *ssa.Value {
return s.newValue2(ssa.OpLoad, n.Type, p, s.mem())
case ODOTPTR:
p := s.exprPtr(n.Left, false, n.Lineno)
p := s.exprPtr(n.Left, false, n.Pos)
p = s.newValue1I(ssa.OpOffPtr, p.Type, n.Xoffset, p)
return s.newValue2(ssa.OpLoad, n.Type, p, s.mem())
@ -2223,7 +2226,7 @@ func (s *state) append(n *Node, inplace bool) *ssa.Value {
if ssa.IsStackAddr(addr) {
s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, pt.Size(), addr, r[0], s.mem())
} else {
s.insertWBstore(pt, addr, r[0], n.Lineno, 0)
s.insertWBstore(pt, addr, r[0], n.Pos, 0)
}
// load the value we just stored to avoid having to spill it
s.vars[&ptrVar] = s.newValue2(ssa.OpLoad, pt, addr, s.mem())
@ -2278,13 +2281,13 @@ func (s *state) append(n *Node, inplace bool) *ssa.Value {
addr := s.newValue2(ssa.OpPtrIndex, pt, p2, s.constInt(Types[TINT], int64(i)))
if arg.store {
if haspointers(et) {
s.insertWBstore(et, addr, arg.v, n.Lineno, 0)
s.insertWBstore(et, addr, arg.v, n.Pos, 0)
} else {
s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, et.Size(), addr, arg.v, s.mem())
}
} else {
if haspointers(et) {
s.insertWBmove(et, addr, arg.v, n.Lineno, arg.isVolatile)
s.insertWBmove(et, addr, arg.v, n.Pos, arg.isVolatile)
} else {
s.vars[&memVar] = s.newValue3I(ssa.OpMove, ssa.TypeMem, sizeAlignAuxInt(et), addr, arg.v, s.mem())
}
@ -2361,7 +2364,7 @@ const (
// If deref is true, rightIsVolatile reports whether right points to volatile (clobbered by a call) storage.
// Include a write barrier if wb is true.
// skip indicates assignments (at the top level) that can be avoided.
func (s *state) assign(left *Node, right *ssa.Value, wb, deref bool, line int32, skip skipMask, rightIsVolatile bool) {
func (s *state) assign(left *Node, right *ssa.Value, wb, deref bool, line src.XPos, skip skipMask, rightIsVolatile bool) {
if left.Op == ONAME && isblank(left) {
return
}
@ -2855,7 +2858,7 @@ func (s *state) intrinsicCall(n *Node) *ssa.Value {
if x.Op == ssa.OpSelect0 || x.Op == ssa.OpSelect1 {
x = x.Args[0]
}
Warnl(n.Lineno, "intrinsic substitution for %v with %s", n.Left.Sym.Name, x.LongString())
Warnl(n.Pos, "intrinsic substitution for %v with %s", n.Left.Sym.Name, x.LongString())
}
return v
}
@ -2945,7 +2948,7 @@ func (s *state) call(n *Node, k callKind) *ssa.Value {
// We can then pass that to defer or go.
n2 := newname(fn.Sym)
n2.Class = PFUNC
n2.Lineno = fn.Lineno
n2.Pos = fn.Pos
n2.Type = Types[TUINT8] // dummy type for a static closure. Could use runtime.funcval if we had it.
closure = s.expr(n2)
// Note: receiver is already assigned in n.List, so we don't
@ -3146,12 +3149,12 @@ func (s *state) addr(n *Node, bounded bool) (*ssa.Value, bool) {
return s.newValue2(ssa.OpPtrIndex, ptrto(n.Left.Type.Elem()), a, i), isVolatile
}
case OIND:
return s.exprPtr(n.Left, bounded, n.Lineno), false
return s.exprPtr(n.Left, bounded, n.Pos), false
case ODOT:
p, isVolatile := s.addr(n.Left, bounded)
return s.newValue1I(ssa.OpOffPtr, t, n.Xoffset, p), isVolatile
case ODOTPTR:
p := s.exprPtr(n.Left, bounded, n.Lineno)
p := s.exprPtr(n.Left, bounded, n.Pos)
return s.newValue1I(ssa.OpOffPtr, t, n.Xoffset, p), false
case OCLOSUREVAR:
return s.newValue1I(ssa.OpOffPtr, t, n.Xoffset,
@ -3260,10 +3263,10 @@ func canSSAType(t *Type) bool {
}
// exprPtr evaluates n to a pointer and nil-checks it.
func (s *state) exprPtr(n *Node, bounded bool, lineno int32) *ssa.Value {
func (s *state) exprPtr(n *Node, bounded bool, lineno src.XPos) *ssa.Value {
p := s.expr(n)
if bounded || n.NonNil {
if s.f.Config.Debug_checknil() && lineno > 1 {
if s.f.Config.Debug_checknil() && lineno.Line() > 1 {
s.f.Config.Warnl(lineno, "removed nil check")
}
return p
@ -3315,7 +3318,7 @@ func (s *state) check(cmp *ssa.Value, fn *Node) {
b.SetControl(cmp)
b.Likely = ssa.BranchLikely
bNext := s.f.NewBlock(ssa.BlockPlain)
line := s.peekLine()
line := s.peekPos()
bPanic := s.panics[funcLine{fn, line}]
if bPanic == nil {
bPanic = s.f.NewBlock(ssa.BlockPlain)
@ -3408,7 +3411,7 @@ func (s *state) rtcall(fn *Node, returns bool, results []*Type, args ...*ssa.Val
// insertWBmove inserts the assignment *left = *right including a write barrier.
// t is the type being assigned.
// If right == nil, then we're zeroing *left.
func (s *state) insertWBmove(t *Type, left, right *ssa.Value, line int32, rightIsVolatile bool) {
func (s *state) insertWBmove(t *Type, left, right *ssa.Value, line src.XPos, rightIsVolatile bool) {
// if writeBarrier.enabled {
// typedmemmove(&t, left, right)
// } else {
@ -3426,8 +3429,8 @@ func (s *state) insertWBmove(t *Type, left, right *ssa.Value, line int32, rightI
if s.noWB {
s.Error("write barrier prohibited")
}
if s.WBLineno == 0 {
s.WBLineno = left.Line
if !s.WBPos.IsKnown() {
s.WBPos = left.Pos
}
var val *ssa.Value
@ -3456,7 +3459,7 @@ func (s *state) insertWBmove(t *Type, left, right *ssa.Value, line int32, rightI
// insertWBstore inserts the assignment *left = right including a write barrier.
// t is the type being assigned.
func (s *state) insertWBstore(t *Type, left, right *ssa.Value, line int32, skip skipMask) {
func (s *state) insertWBstore(t *Type, left, right *ssa.Value, line src.XPos, skip skipMask) {
// store scalar fields
// if writeBarrier.enabled {
// writebarrierptr for pointer fields
@ -3467,8 +3470,8 @@ func (s *state) insertWBstore(t *Type, left, right *ssa.Value, line int32, skip
if s.noWB {
s.Error("write barrier prohibited")
}
if s.WBLineno == 0 {
s.WBLineno = left.Line
if !s.WBPos.IsKnown() {
s.WBPos = left.Pos
}
s.storeTypeScalars(t, left, right, skip)
s.storeTypePtrsWB(t, left, right)
@ -4062,7 +4065,7 @@ func (s *state) dottype(n *Node, commaok bool) (res, resok *ssa.Value) {
// Converting to an empty interface.
// Input could be an empty or nonempty interface.
if Debug_typeassert > 0 {
Warnl(n.Lineno, "type assertion inlined")
Warnl(n.Pos, "type assertion inlined")
}
// Get itab/type field from input.
@ -4129,7 +4132,7 @@ func (s *state) dottype(n *Node, commaok bool) (res, resok *ssa.Value) {
}
// converting to a nonempty interface needs a runtime call.
if Debug_typeassert > 0 {
Warnl(n.Lineno, "type assertion not inlined")
Warnl(n.Pos, "type assertion not inlined")
}
if n.Left.Type.IsEmptyInterface() {
if commaok {
@ -4146,7 +4149,7 @@ func (s *state) dottype(n *Node, commaok bool) (res, resok *ssa.Value) {
}
if Debug_typeassert > 0 {
Warnl(n.Lineno, "type assertion inlined")
Warnl(n.Pos, "type assertion inlined")
}
// Converting to a concrete type.
@ -4154,7 +4157,7 @@ func (s *state) dottype(n *Node, commaok bool) (res, resok *ssa.Value) {
typ := s.ifaceType(n.Left.Type, iface) // actual concrete type of input interface
if Debug_typeassert > 0 {
Warnl(n.Lineno, "type assertion inlined")
Warnl(n.Pos, "type assertion inlined")
}
var tmp *Node // temporary for use with large types
@ -4293,7 +4296,7 @@ func (s *state) checkgoto(from *Node, to *Node) {
fs = fs.Link
}
lno := from.Left.Lineno
lno := from.Left.Pos
if block != nil {
yyerrorl(lno, "goto %v jumps into block starting at %v", from.Left.Sym, linestr(block.Lastlineno))
} else {
@ -4380,9 +4383,9 @@ func (s *SSAGenState) Pc() *obj.Prog {
return pc
}
// SetLineno sets the current source line number.
func (s *SSAGenState) SetLineno(l int32) {
lineno = l
// SetPos sets the current source position.
func (s *SSAGenState) SetPos(pos src.XPos) {
lineno = pos
}
// genssa appends entries to ptxt for each instruction in f.
@ -4462,8 +4465,11 @@ func genssa(f *ssa.Func, ptxt *obj.Prog, gcargs, gclocals *Sym) {
f.Logf("%s\t%s\n", s, p)
}
if f.Config.HTML != nil {
saved := ptxt.Ctxt.LineHist.PrintFilenameOnly
ptxt.Ctxt.LineHist.PrintFilenameOnly = true
// LineHist is defunct now - this code won't do
// anything.
// TODO: fix this (ideally without a global variable)
// saved := ptxt.Ctxt.LineHist.PrintFilenameOnly
// ptxt.Ctxt.LineHist.PrintFilenameOnly = true
var buf bytes.Buffer
buf.WriteString("<code>")
buf.WriteString("<dl class=\"ssa-gen\">")
@ -4483,7 +4489,7 @@ func genssa(f *ssa.Func, ptxt *obj.Prog, gcargs, gclocals *Sym) {
buf.WriteString("</dl>")
buf.WriteString("</code>")
f.Config.HTML.WriteColumn("genssa", buf.String())
ptxt.Ctxt.LineHist.PrintFilenameOnly = saved
// ptxt.Ctxt.LineHist.PrintFilenameOnly = saved
}
}
@ -4958,8 +4964,8 @@ func (e *ssaExport) CanSSA(t ssa.Type) bool {
return canSSAType(t.(*Type))
}
func (e *ssaExport) Line(line int32) string {
return linestr(line)
func (e *ssaExport) Line(pos src.XPos) string {
return linestr(pos)
}
// Log logs a message from the compiler.
@ -4974,15 +4980,15 @@ func (e *ssaExport) Log() bool {
}
// Fatal reports a compiler error and exits.
func (e *ssaExport) Fatalf(line int32, msg string, args ...interface{}) {
lineno = line
func (e *ssaExport) Fatalf(pos src.XPos, msg string, args ...interface{}) {
lineno = pos
Fatalf(msg, args...)
}
// Warnl reports a "warning", which is usually flag-triggered
// logging output for the benefit of tests.
func (e *ssaExport) Warnl(line int32, fmt_ string, args ...interface{}) {
Warnl(line, fmt_, args...)
func (e *ssaExport) Warnl(pos src.XPos, fmt_ string, args ...interface{}) {
Warnl(pos, fmt_, args...)
}
func (e *ssaExport) Debug_checknil() bool {

View file

@ -7,6 +7,7 @@ package gc
import (
"bytes"
"cmd/internal/obj"
"cmd/internal/src"
"crypto/md5"
"encoding/binary"
"fmt"
@ -20,8 +21,8 @@ import (
)
type Error struct {
lineno int32
msg string
pos src.XPos
msg string
}
var errors []Error
@ -39,24 +40,24 @@ func adderrorname(n *Node) {
return
}
old := fmt.Sprintf("%v: undefined: %v\n", n.Line(), n.Left)
if len(errors) > 0 && errors[len(errors)-1].lineno == n.Lineno && errors[len(errors)-1].msg == old {
if len(errors) > 0 && errors[len(errors)-1].pos.Line() == n.Pos.Line() && errors[len(errors)-1].msg == old {
errors[len(errors)-1].msg = fmt.Sprintf("%v: undefined: %v in %v\n", n.Line(), n.Left, n)
}
}
func adderr(line int32, format string, args ...interface{}) {
func adderr(pos src.XPos, format string, args ...interface{}) {
errors = append(errors, Error{
lineno: line,
msg: fmt.Sprintf("%v: %s\n", linestr(line), fmt.Sprintf(format, args...)),
pos: pos,
msg: fmt.Sprintf("%v: %s\n", linestr(pos), fmt.Sprintf(format, args...)),
})
}
// byLineno sorts errors by lineno.
type byLineno []Error
// byPos sorts errors by source position.
type byPos []Error
func (x byLineno) Len() int { return len(x) }
func (x byLineno) Less(i, j int) bool { return x[i].lineno < x[j].lineno }
func (x byLineno) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
func (x byPos) Len() int { return len(x) }
func (x byPos) Less(i, j int) bool { return x[i].pos.Before(x[j].pos) }
func (x byPos) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
// flusherrors sorts errors seen so far by line number, prints them to stdout,
// and empties the errors array.
@ -65,7 +66,7 @@ func flusherrors() {
if len(errors) == 0 {
return
}
sort.Stable(byLineno(errors))
sort.Stable(byPos(errors))
for i := 0; i < len(errors); i++ {
if i == 0 || errors[i].msg != errors[i-1].msg {
fmt.Printf("%s", errors[i].msg)
@ -85,49 +86,56 @@ func hcrash() {
}
}
func linestr(line int32) string {
return Ctxt.Line(int(line))
func linestr(pos src.XPos) string {
return Ctxt.PosTable.Pos(pos).String()
}
// lasterror keeps track of the most recently issued error.
// It is used to avoid multiple error messages on the same
// line.
var lasterror struct {
syntax int32 // line of last syntax error
other int32 // line of last non-syntax error
msg string // error message of last non-syntax error
syntax src.XPos // source position of last syntax error
other src.XPos // source position of last non-syntax error
msg string // error message of last non-syntax error
}
func yyerrorl(line int32, format string, args ...interface{}) {
// sameline reports whether two positions a, b are on the same line.
func sameline(a, b src.XPos) bool {
p := Ctxt.PosTable.Pos(a)
q := Ctxt.PosTable.Pos(b)
return p.Base() == q.Base() && p.Line() == q.Line()
}
func yyerrorl(pos src.XPos, format string, args ...interface{}) {
msg := fmt.Sprintf(format, args...)
if strings.HasPrefix(msg, "syntax error") {
nsyntaxerrors++
// only one syntax error per line, no matter what error
if lasterror.syntax == line {
if sameline(lasterror.syntax, pos) {
return
}
lasterror.syntax = line
lasterror.syntax = pos
} else {
// only one of multiple equal non-syntax errors per line
// (flusherrors shows only one of them, so we filter them
// here as best as we can (they may not appear in order)
// so that we don't count them here and exit early, and
// then have nothing to show for.)
if lasterror.other == line && lasterror.msg == msg {
if sameline(lasterror.other, pos) && lasterror.msg == msg {
return
}
lasterror.other = line
lasterror.other = pos
lasterror.msg = msg
}
adderr(line, "%s", msg)
adderr(pos, "%s", msg)
hcrash()
nerrors++
if nsavederrors+nerrors >= 10 && Debug['e'] == 0 {
flusherrors()
fmt.Printf("%v: too many errors\n", linestr(line))
fmt.Printf("%v: too many errors\n", linestr(pos))
errorexit()
}
}
@ -142,7 +150,7 @@ func Warn(fmt_ string, args ...interface{}) {
hcrash()
}
func Warnl(line int32, fmt_ string, args ...interface{}) {
func Warnl(line src.XPos, fmt_ string, args ...interface{}) {
adderr(line, fmt_, args...)
if Debug['m'] != 0 {
flusherrors()
@ -172,35 +180,7 @@ func Fatalf(fmt_ string, args ...interface{}) {
errorexit()
}
func linehistpragma(file string) {
if Debug['i'] != 0 {
fmt.Printf("pragma %s at line %v\n", file, linestr(lexlineno))
}
Ctxt.AddImport(file)
}
func linehistpush(file string) {
if Debug['i'] != 0 {
fmt.Printf("import %s at line %v\n", file, linestr(lexlineno))
}
Ctxt.LineHist.Push(int(lexlineno), file)
}
func linehistpop() {
if Debug['i'] != 0 {
fmt.Printf("end of import at line %v\n", linestr(lexlineno))
}
Ctxt.LineHist.Pop(int(lexlineno))
}
func linehistupdate(file string, off int) {
if Debug['i'] != 0 {
fmt.Printf("line %s at line %v\n", file, linestr(lexlineno))
}
Ctxt.LineHist.Update(int(lexlineno), file, off)
}
func setlineno(n *Node) int32 {
func setlineno(n *Node) src.XPos {
lno := lineno
if n != nil {
switch n.Op {
@ -214,10 +194,10 @@ func setlineno(n *Node) int32 {
fallthrough
default:
lineno = n.Lineno
if lineno == 0 {
lineno = n.Pos
if !lineno.IsKnown() {
if Debug['K'] != 0 {
Warn("setlineno: line 0")
Warn("setlineno: unknown position (line 0)")
}
lineno = lno
}
@ -348,7 +328,7 @@ func importdot(opkg *Pkg, pack *Node) {
if n == 0 {
// can't possibly be used - there were no symbols
yyerrorl(pack.Lineno, "imported and not used: %q", opkg.Path)
yyerrorl(pack.Pos, "imported and not used: %q", opkg.Path)
}
}
@ -357,7 +337,7 @@ func nod(op Op, nleft *Node, nright *Node) *Node {
n.Op = op
n.Left = nleft
n.Right = nright
n.Lineno = lineno
n.Pos = lineno
n.Xoffset = BADWIDTH
n.Orig = n
switch op {
@ -473,9 +453,9 @@ func nodbool(b bool) *Node {
// treecopy recursively copies n, with the exception of
// ONAME, OLITERAL, OTYPE, and non-iota ONONAME leaves.
// Copies of iota ONONAME nodes are assigned the current
// value of iota_. If lineno != 0, it sets the line number
// of newly allocated nodes to lineno.
func treecopy(n *Node, lineno int32) *Node {
// value of iota_. If pos.IsKnown(), it sets the source
// position of newly allocated nodes to pos.
func treecopy(n *Node, pos src.XPos) *Node {
if n == nil {
return nil
}
@ -484,11 +464,11 @@ func treecopy(n *Node, lineno int32) *Node {
default:
m := *n
m.Orig = &m
m.Left = treecopy(n.Left, lineno)
m.Right = treecopy(n.Right, lineno)
m.List.Set(listtreecopy(n.List.Slice(), lineno))
if lineno != 0 {
m.Lineno = lineno
m.Left = treecopy(n.Left, pos)
m.Right = treecopy(n.Right, pos)
m.List.Set(listtreecopy(n.List.Slice(), pos))
if pos.IsKnown() {
m.Pos = pos
}
if m.Name != nil && n.Op != ODCLFIELD {
Dump("treecopy", n)
@ -503,8 +483,8 @@ func treecopy(n *Node, lineno int32) *Node {
// so that all the copies of this const definition
// don't have the same iota value.
m := *n
if lineno != 0 {
m.Lineno = lineno
if pos.IsKnown() {
m.Pos = pos
}
m.SetIota(iota_)
return &m
@ -1706,21 +1686,12 @@ func structargs(tl *Type, mustname bool) []*Node {
// method - M func (t T)(), a TFIELD type struct
// newnam - the eventual mangled name of this function
var genwrapper_linehistdone int = 0
func genwrapper(rcvr *Type, method *Field, newnam *Sym, iface int) {
if false && Debug['r'] != 0 {
fmt.Printf("genwrapper rcvrtype=%v method=%v newnam=%v\n", rcvr, method, newnam)
}
lexlineno++
lineno = lexlineno
if genwrapper_linehistdone == 0 {
// All the wrappers can share the same linehist entry.
linehistpush("<autogenerated>")
genwrapper_linehistdone = 1
}
lineno = MakePos(src.NewFileBase("<autogenerated>", "<autogenerated>"), 1, 0)
dclcontext = PEXTERN
markdcl()
@ -1993,10 +1964,10 @@ func Simsimtype(t *Type) EType {
return et
}
func listtreecopy(l []*Node, lineno int32) []*Node {
func listtreecopy(l []*Node, pos src.XPos) []*Node {
var out []*Node
for _, n := range l {
out = append(out, treecopy(n, lineno))
out = append(out, treecopy(n, pos))
}
return out
}
@ -2005,7 +1976,7 @@ func liststmt(l []*Node) *Node {
n := nod(OBLOCK, nil, nil)
n.List.Set(l)
if len(l) != 0 {
n.Lineno = l[0].Lineno
n.Pos = l[0].Pos
}
return n
}

View file

@ -578,7 +578,7 @@ Outer:
}
for _, n := range prev {
if eqtype(n.Left.Type, c.node.Left.Type) {
yyerrorl(c.node.Lineno, "duplicate case %v in type switch\n\tprevious case at %v", c.node.Left.Type, n.Line())
yyerrorl(c.node.Pos, "duplicate case %v in type switch\n\tprevious case at %v", c.node.Left.Type, n.Line())
// avoid double-reporting errors
continue Outer
}

View file

@ -6,6 +6,11 @@
package gc
import (
"cmd/compile/internal/syntax"
"cmd/internal/src"
)
// A Node is a single node in the syntax tree.
// Actually the syntax tree is a syntax DAG, because there is only one
// node with Op=ONAME for a given instance of a variable x.
@ -42,7 +47,7 @@ type Node struct {
// Possibly still more uses. If you find any, document them.
Xoffset int64
Lineno int32
Pos src.XPos
Esc uint16 // EscXXX
@ -283,7 +288,7 @@ type Param struct {
// OTYPE
//
// TODO: Should Func pragmas also be stored on the Name?
Pragma Pragma
Pragma syntax.Pragma
Alias bool // node is alias for Ntype (only used when type-checking ODCLTYPE)
}
@ -309,14 +314,14 @@ type Func struct {
Label int32 // largest auto-generated label in this function
Endlineno int32
WBLineno int32 // line number of first write barrier
Endlineno src.XPos
WBPos src.XPos // position of first write barrier
Pragma Pragma // go:xxx function annotations
Dupok bool // duplicate definitions ok
Wrapper bool // is method wrapper
Needctxt bool // function uses context register (has closure variables)
ReflectMethod bool // function calls reflect.Type.Method or MethodByName
Pragma syntax.Pragma // go:xxx function annotations
Dupok bool // duplicate definitions ok
Wrapper bool // is method wrapper
Needctxt bool // function uses context register (has closure variables)
ReflectMethod bool // function calls reflect.Type.Method or MethodByName
IsHiddenClosure bool
NoFramePointer bool // Must not use a frame pointer for this function
}

View file

@ -11,6 +11,7 @@ package gc
import (
"cmd/compile/internal/ssa"
"cmd/internal/src"
"fmt"
)
@ -149,9 +150,9 @@ type Type struct {
sliceOf *Type
ptrTo *Type
Sym *Sym // symbol containing name, for named types
Vargen int32 // unique name for OTYPE/ONAME
Lineno int32 // line at which this type was declared, implicitly or explicitly
Sym *Sym // symbol containing name, for named types
Vargen int32 // unique name for OTYPE/ONAME
Pos src.XPos // position at which this type was declared, implicitly or explicitly
Etype EType // kind of type
Noalg bool // suppress hash and eq algorithm generation
@ -181,8 +182,8 @@ func (t *Type) MapType() *MapType {
// ForwardType contains Type fields specific to forward types.
type ForwardType struct {
Copyto []*Node // where to copy the eventual value to
Embedlineno int32 // first use of this type as an embedded type
Copyto []*Node // where to copy the eventual value to
Embedlineno src.XPos // first use of this type as an embedded type
}
// ForwardType returns t's extra forward-type-specific fields.
@ -375,9 +376,9 @@ func (f *Fields) Append(s ...*Field) {
// typ returns a new Type of the specified kind.
func typ(et EType) *Type {
t := &Type{
Etype: et,
Width: BADWIDTH,
Lineno: lineno,
Etype: et,
Width: BADWIDTH,
Pos: lineno,
}
t.Orig = t
// TODO(josharian): lazily initialize some of these?

View file

@ -6,6 +6,7 @@ package gc
import (
"cmd/internal/obj"
"cmd/internal/src"
"fmt"
"math"
"strings"
@ -163,7 +164,7 @@ func typecheck(n *Node, top int) *Node {
if top&Etype == Etype {
var trace string
sprint_depchain(&trace, typecheck_tcstack, n, n)
yyerrorl(n.Lineno, "invalid recursive type alias %v%s", n, trace)
yyerrorl(n.Pos, "invalid recursive type alias %v%s", n, trace)
}
case OLITERAL:
@ -173,7 +174,7 @@ func typecheck(n *Node, top int) *Node {
}
var trace string
sprint_depchain(&trace, typecheck_tcstack, n, n)
yyerrorl(n.Lineno, "constant definition loop%s", trace)
yyerrorl(n.Pos, "constant definition loop%s", trace)
}
if nsavederrors+nerrors == 0 {
@ -421,7 +422,7 @@ OpSwitch:
if alg == ANOEQ {
if bad.Etype == TFORW {
// queue check for map until all the types are done settling.
mapqueue = append(mapqueue, mapqueueval{l, n.Lineno})
mapqueue = append(mapqueue, mapqueueval{l, n.Pos})
} else if bad.Etype != TANY {
// no need to queue, key is already bad
yyerror("invalid map key type %v", l.Type)
@ -3513,7 +3514,7 @@ func domethod(n *Node) {
type mapqueueval struct {
n *Node
lno int32
lno src.XPos
}
// tracks the line numbers at which forward types are first used as map keys
@ -3561,7 +3562,7 @@ func copytype(n *Node, t *Type) {
// Double-check use of type as embedded type.
lno := lineno
if embedlineno != 0 {
if embedlineno.IsKnown() {
lineno = embedlineno
if t.IsPtr() || t.IsUnsafePtr() {
yyerror("embedded type cannot be a pointer")
@ -3640,8 +3641,8 @@ func typecheckdef(n *Node) *Node {
if n.Op == ONONAME {
if !n.Diag {
n.Diag = true
if n.Lineno != 0 {
lineno = n.Lineno
if n.Pos.IsKnown() {
lineno = n.Pos
}
// Note: adderrorname looks for this string and
@ -3695,7 +3696,7 @@ func typecheckdef(n *Node) *Node {
e := n.Name.Defn
n.Name.Defn = nil
if e == nil {
lineno = n.Lineno
lineno = n.Pos
Dump("typecheckdef nil defn", n)
yyerror("xxx")
}

View file

@ -11,7 +11,7 @@ import (
)
func (n *Node) Line() string {
return Ctxt.LineHist.LineString(int(n.Lineno))
return linestr(n.Pos)
}
var atExitFuncs []func()

View file

@ -49,11 +49,11 @@ func walk(fn *Node) {
if defn.Left.Used {
continue
}
lineno = defn.Left.Lineno
lineno = defn.Left.Pos
yyerror("%v declared and not used", ln.Sym)
defn.Left.Used = true // suppress repeats
} else {
lineno = ln.Lineno
lineno = ln.Pos
yyerror("%v declared and not used", ln.Sym)
}
}
@ -2137,7 +2137,7 @@ func needwritebarrier(l *Node, r *Node) bool {
func applywritebarrier(n *Node) *Node {
if n.Left != nil && n.Right != nil && needwritebarrier(n.Left, n.Right) {
if Debug_wb > 1 {
Warnl(n.Lineno, "marking %v for barrier", n.Left)
Warnl(n.Pos, "marking %v for barrier", n.Left)
}
n.Op = OASWB
return n
@ -2592,7 +2592,7 @@ func returnsfromheap(params *Type) []*Node {
// Enter and Exit lists.
func heapmoves() {
lno := lineno
lineno = Curfn.Lineno
lineno = Curfn.Pos
nn := paramstoheap(Curfn.Type.Recvs())
nn = append(nn, paramstoheap(Curfn.Type.Params())...)
nn = append(nn, paramstoheap(Curfn.Type.Results())...)
@ -3418,7 +3418,7 @@ func walkinrange(n *Node, init *Nodes) *Node {
opr = brcom(opr)
}
cmp := nod(opr, lhs, rhs)
cmp.Lineno = n.Lineno
cmp.Pos = n.Pos
cmp = addinit(cmp, l.Ninit.Slice())
cmp = addinit(cmp, r.Ninit.Slice())
// Typecheck the AST rooted at cmp...

View file

@ -74,7 +74,7 @@ func storeByType(t ssa.Type, r int16) obj.As {
}
func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
s.SetLineno(v.Line)
s.SetPos(v.Pos)
switch v.Op {
case ssa.OpInitMem:
// memory arg needs no code
@ -796,8 +796,8 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
gc.AddAux(&p.From, v)
p.To.Type = obj.TYPE_REG
p.To.Reg = mips.REGTMP
if gc.Debug_checknil != 0 && v.Line > 1 { // v.Line==1 in generated wrappers
gc.Warnl(v.Line, "generated nil check")
if gc.Debug_checknil != 0 && v.Pos.Line() > 1 { // v.Pos.Line()==1 in generated wrappers
gc.Warnl(v.Pos, "generated nil check")
}
case ssa.OpMIPSFPFlagTrue,
ssa.OpMIPSFPFlagFalse:
@ -841,7 +841,7 @@ var blockJump = map[ssa.BlockKind]struct {
}
func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
s.SetLineno(b.Line)
s.SetPos(b.Pos)
switch b.Kind {
case ssa.BlockPlain:

View file

@ -82,7 +82,7 @@ func storeByType(t ssa.Type, r int16) obj.As {
}
func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
s.SetLineno(v.Line)
s.SetPos(v.Pos)
switch v.Op {
case ssa.OpInitMem:
// memory arg needs no code
@ -548,8 +548,8 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
gc.AddAux(&p.From, v)
p.To.Type = obj.TYPE_REG
p.To.Reg = mips.REGTMP
if gc.Debug_checknil != 0 && v.Line > 1 { // v.Line==1 in generated wrappers
gc.Warnl(v.Line, "generated nil check")
if gc.Debug_checknil != 0 && v.Pos.Line() > 1 { // v.Pos.Line()==1 in generated wrappers
gc.Warnl(v.Pos, "generated nil check")
}
case ssa.OpVarDef:
gc.Gvardef(v.Aux.(*gc.Node))
@ -606,7 +606,7 @@ var blockJump = map[ssa.BlockKind]struct {
}
func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
s.SetLineno(b.Line)
s.SetPos(b.Pos)
switch b.Kind {
case ssa.BlockPlain:

View file

@ -143,7 +143,7 @@ func ssaGenISEL(v *ssa.Value, cr int64, r1, r2 int16) {
}
func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
s.SetLineno(v.Line)
s.SetPos(v.Pos)
switch v.Op {
case ssa.OpInitMem:
// memory arg needs no code
@ -803,8 +803,8 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
gc.AddAux(&p.From, v)
p.To.Type = obj.TYPE_REG
p.To.Reg = ppc64.REGTMP
if gc.Debug_checknil != 0 && v.Line > 1 { // v.Line==1 in generated wrappers
gc.Warnl(v.Line, "generated nil check")
if gc.Debug_checknil != 0 && v.Pos.Line() > 1 { // v.Pos.Line()==1 in generated wrappers
gc.Warnl(v.Pos, "generated nil check")
}
case ssa.OpPPC64InvertFlags:
@ -837,7 +837,7 @@ var blockJump = [...]struct {
}
func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
s.SetLineno(b.Line)
s.SetPos(b.Pos)
switch b.Kind {

View file

@ -156,7 +156,7 @@ func opregregimm(op obj.As, dest, src int16, off int64) *obj.Prog {
}
func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
s.SetLineno(v.Line)
s.SetPos(v.Pos)
switch v.Op {
case ssa.OpS390XSLD, ssa.OpS390XSLW,
ssa.OpS390XSRD, ssa.OpS390XSRW,
@ -570,8 +570,8 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
gc.AddAux(&p.From, v)
p.To.Type = obj.TYPE_REG
p.To.Reg = s390x.REGTMP
if gc.Debug_checknil != 0 && v.Line > 1 { // v.Line==1 in generated wrappers
gc.Warnl(v.Line, "generated nil check")
if gc.Debug_checknil != 0 && v.Pos.Line() > 1 { // v.Pos.Line()==1 in generated wrappers
gc.Warnl(v.Pos, "generated nil check")
}
case ssa.OpS390XMVC:
vo := v.AuxValAndOff()
@ -796,7 +796,7 @@ var blockJump = [...]struct {
}
func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
s.SetLineno(b.Line)
s.SetPos(b.Pos)
switch b.Kind {
case ssa.BlockPlain:

View file

@ -4,7 +4,10 @@
package ssa
import "fmt"
import (
"cmd/internal/src"
"fmt"
)
// Block represents a basic block in the control flow graph of a function.
type Block struct {
@ -12,8 +15,8 @@ type Block struct {
// these IDs densely, but no guarantees.
ID ID
// Line number for block's control operation
Line int32
// Source position for block's control operation
Pos src.XPos
// The kind of block this is.
Kind BlockKind

View file

@ -16,7 +16,7 @@ func checkbce(f *Func) {
for _, b := range f.Blocks {
for _, v := range b.Values {
if v.Op == OpIsInBounds || v.Op == OpIsSliceInBounds {
f.Config.Warnl(v.Line, "Found %v", v.Op)
f.Config.Warnl(v.Pos, "Found %v", v.Op)
}
}
}

View file

@ -6,6 +6,7 @@ package ssa
import (
"cmd/internal/obj"
"cmd/internal/src"
"fmt"
"log"
"os"
@ -129,7 +130,7 @@ func (f *Func) dumpFile(phaseName string) {
fi, err := os.Create(fname)
if err != nil {
f.Config.Warnl(0, "Unable to create after-phase dump file %s", fname)
f.Config.Warnl(src.NoXPos, "Unable to create after-phase dump file %s", fname)
return
}

View file

@ -6,6 +6,7 @@ package ssa
import (
"cmd/internal/obj"
"cmd/internal/src"
"crypto/sha1"
"fmt"
"os"
@ -88,10 +89,10 @@ type Logger interface {
Log() bool
// Fatal reports a compiler error and exits.
Fatalf(line int32, msg string, args ...interface{})
Fatalf(pos src.XPos, msg string, args ...interface{})
// Warnl writes compiler messages in the form expected by "errorcheck" tests
Warnl(line int32, fmt_ string, args ...interface{})
Warnl(pos src.XPos, fmt_ string, args ...interface{})
// Forwards the Debug flags from gc
Debug_checknil() bool
@ -119,8 +120,8 @@ type Frontend interface {
SplitArray(LocalSlot) LocalSlot // array must be length 1
SplitInt64(LocalSlot) (LocalSlot, LocalSlot) // returns (hi, lo)
// Line returns a string describing the given line number.
Line(int32) string
// Line returns a string describing the given position.
Line(src.XPos) string
// AllocFrame assigns frame offsets to all live auto variables.
AllocFrame(f *Func)
@ -269,7 +270,7 @@ func NewConfig(arch string, fe Frontend, ctxt *obj.Link, optimize bool) *Config
c.hasGReg = true
c.noDuffDevice = true
default:
fe.Fatalf(0, "arch %s not implemented", arch)
fe.Fatalf(src.NoXPos, "arch %s not implemented", arch)
}
c.ctxt = ctxt
c.optimize = optimize
@ -309,7 +310,7 @@ func NewConfig(arch string, fe Frontend, ctxt *obj.Link, optimize bool) *Config
if ev != "" {
v, err := strconv.ParseInt(ev, 10, 64)
if err != nil {
fe.Fatalf(0, "Environment variable GO_SSA_PHI_LOC_CUTOFF (value '%s') did not parse as a number", ev)
fe.Fatalf(src.NoXPos, "Environment variable GO_SSA_PHI_LOC_CUTOFF (value '%s') did not parse as a number", ev)
}
c.sparsePhiCutoff = uint64(v) // convert -1 to maxint, for never use sparse
}
@ -331,19 +332,19 @@ func (c *Config) Ctxt() *obj.Link { return c.ctxt }
func (c *Config) NewFunc() *Func {
// TODO(khr): should this function take name, type, etc. as arguments?
if c.curFunc != nil {
c.Fatalf(0, "NewFunc called without previous Free")
c.Fatalf(src.NoXPos, "NewFunc called without previous Free")
}
f := &Func{Config: c, NamedValues: map[LocalSlot][]*Value{}}
c.curFunc = f
return f
}
func (c *Config) Logf(msg string, args ...interface{}) { c.fe.Logf(msg, args...) }
func (c *Config) Log() bool { return c.fe.Log() }
func (c *Config) Fatalf(line int32, msg string, args ...interface{}) { c.fe.Fatalf(line, msg, args...) }
func (c *Config) Warnl(line int32, msg string, args ...interface{}) { c.fe.Warnl(line, msg, args...) }
func (c *Config) Debug_checknil() bool { return c.fe.Debug_checknil() }
func (c *Config) Debug_wb() bool { return c.fe.Debug_wb() }
func (c *Config) Logf(msg string, args ...interface{}) { c.fe.Logf(msg, args...) }
func (c *Config) Log() bool { return c.fe.Log() }
func (c *Config) Fatalf(pos src.XPos, msg string, args ...interface{}) { c.fe.Fatalf(pos, msg, args...) }
func (c *Config) Warnl(pos src.XPos, msg string, args ...interface{}) { c.fe.Warnl(pos, msg, args...) }
func (c *Config) Debug_checknil() bool { return c.fe.Debug_checknil() }
func (c *Config) Debug_wb() bool { return c.fe.Debug_wb() }
func (c *Config) logDebugHashMatch(evname, name string) {
file := c.logfiles[evname]
@ -354,7 +355,7 @@ func (c *Config) logDebugHashMatch(evname, name string) {
var ok error
file, ok = os.Create(tmpfile)
if ok != nil {
c.Fatalf(0, "Could not open hash-testing logfile %s", tmpfile)
c.Fatalf(src.NoXPos, "Could not open hash-testing logfile %s", tmpfile)
}
}
c.logfiles[evname] = file

View file

@ -60,10 +60,10 @@ func critical(f *Func) {
// since we're iterating over len(f.Blocks) above, this forces
// the new blocks to be re-examined.
d = f.NewBlock(BlockPlain)
d.Line = p.Line
d.Pos = p.Pos
blocks[argID] = d
if f.pass.debug > 0 {
f.Config.Warnl(p.Line, "split critical edge")
f.Config.Warnl(p.Pos, "split critical edge")
}
} else {
reusedBlock = true
@ -72,9 +72,9 @@ func critical(f *Func) {
// no existing block, so allocate a new block
// to place on the edge
d = f.NewBlock(BlockPlain)
d.Line = p.Line
d.Pos = p.Pos
if f.pass.debug > 0 {
f.Config.Warnl(p.Line, "split critical edge")
f.Config.Warnl(p.Pos, "split critical edge")
}
}

View file

@ -4,6 +4,8 @@
package ssa
import "cmd/internal/src"
// dse does dead-store elimination on the Function.
// Dead stores are those which are unconditionally followed by
// another store to the same location, with no intervening load.
@ -111,7 +113,7 @@ func dse(f *Func) {
if sz > 0x7fffffff { // work around sparseMap's int32 value type
sz = 0x7fffffff
}
shadowed.set(v.Args[0].ID, int32(sz), 0)
shadowed.set(v.Args[0].ID, int32(sz), src.NoXPos)
}
}
// walk to previous store

View file

@ -35,8 +35,8 @@ func decomposeBuiltIn(f *Func) {
hiName, loName := f.Config.fe.SplitInt64(name)
newNames = append(newNames, hiName, loName)
for _, v := range f.NamedValues[name] {
hi := v.Block.NewValue1(v.Line, OpInt64Hi, elemType, v)
lo := v.Block.NewValue1(v.Line, OpInt64Lo, f.Config.fe.TypeUInt32(), v)
hi := v.Block.NewValue1(v.Pos, OpInt64Hi, elemType, v)
lo := v.Block.NewValue1(v.Pos, OpInt64Lo, f.Config.fe.TypeUInt32(), v)
f.NamedValues[hiName] = append(f.NamedValues[hiName], hi)
f.NamedValues[loName] = append(f.NamedValues[loName], lo)
}
@ -51,8 +51,8 @@ func decomposeBuiltIn(f *Func) {
rName, iName := f.Config.fe.SplitComplex(name)
newNames = append(newNames, rName, iName)
for _, v := range f.NamedValues[name] {
r := v.Block.NewValue1(v.Line, OpComplexReal, elemType, v)
i := v.Block.NewValue1(v.Line, OpComplexImag, elemType, v)
r := v.Block.NewValue1(v.Pos, OpComplexReal, elemType, v)
i := v.Block.NewValue1(v.Pos, OpComplexImag, elemType, v)
f.NamedValues[rName] = append(f.NamedValues[rName], r)
f.NamedValues[iName] = append(f.NamedValues[iName], i)
}
@ -63,8 +63,8 @@ func decomposeBuiltIn(f *Func) {
ptrName, lenName := f.Config.fe.SplitString(name)
newNames = append(newNames, ptrName, lenName)
for _, v := range f.NamedValues[name] {
ptr := v.Block.NewValue1(v.Line, OpStringPtr, ptrType, v)
len := v.Block.NewValue1(v.Line, OpStringLen, lenType, v)
ptr := v.Block.NewValue1(v.Pos, OpStringPtr, ptrType, v)
len := v.Block.NewValue1(v.Pos, OpStringLen, lenType, v)
f.NamedValues[ptrName] = append(f.NamedValues[ptrName], ptr)
f.NamedValues[lenName] = append(f.NamedValues[lenName], len)
}
@ -75,9 +75,9 @@ func decomposeBuiltIn(f *Func) {
ptrName, lenName, capName := f.Config.fe.SplitSlice(name)
newNames = append(newNames, ptrName, lenName, capName)
for _, v := range f.NamedValues[name] {
ptr := v.Block.NewValue1(v.Line, OpSlicePtr, ptrType, v)
len := v.Block.NewValue1(v.Line, OpSliceLen, lenType, v)
cap := v.Block.NewValue1(v.Line, OpSliceCap, lenType, v)
ptr := v.Block.NewValue1(v.Pos, OpSlicePtr, ptrType, v)
len := v.Block.NewValue1(v.Pos, OpSliceLen, lenType, v)
cap := v.Block.NewValue1(v.Pos, OpSliceCap, lenType, v)
f.NamedValues[ptrName] = append(f.NamedValues[ptrName], ptr)
f.NamedValues[lenName] = append(f.NamedValues[lenName], len)
f.NamedValues[capName] = append(f.NamedValues[capName], cap)
@ -88,8 +88,8 @@ func decomposeBuiltIn(f *Func) {
typeName, dataName := f.Config.fe.SplitInterface(name)
newNames = append(newNames, typeName, dataName)
for _, v := range f.NamedValues[name] {
typ := v.Block.NewValue1(v.Line, OpITab, ptrType, v)
data := v.Block.NewValue1(v.Line, OpIData, ptrType, v)
typ := v.Block.NewValue1(v.Pos, OpITab, ptrType, v)
data := v.Block.NewValue1(v.Pos, OpIData, ptrType, v)
f.NamedValues[typeName] = append(f.NamedValues[typeName], typ)
f.NamedValues[dataName] = append(f.NamedValues[dataName], data)
}
@ -133,11 +133,11 @@ func decomposeStringPhi(v *Value) {
ptrType := fe.TypeBytePtr()
lenType := fe.TypeInt()
ptr := v.Block.NewValue0(v.Line, OpPhi, ptrType)
len := v.Block.NewValue0(v.Line, OpPhi, lenType)
ptr := v.Block.NewValue0(v.Pos, OpPhi, ptrType)
len := v.Block.NewValue0(v.Pos, OpPhi, lenType)
for _, a := range v.Args {
ptr.AddArg(a.Block.NewValue1(v.Line, OpStringPtr, ptrType, a))
len.AddArg(a.Block.NewValue1(v.Line, OpStringLen, lenType, a))
ptr.AddArg(a.Block.NewValue1(v.Pos, OpStringPtr, ptrType, a))
len.AddArg(a.Block.NewValue1(v.Pos, OpStringLen, lenType, a))
}
v.reset(OpStringMake)
v.AddArg(ptr)
@ -149,13 +149,13 @@ func decomposeSlicePhi(v *Value) {
ptrType := fe.TypeBytePtr()
lenType := fe.TypeInt()
ptr := v.Block.NewValue0(v.Line, OpPhi, ptrType)
len := v.Block.NewValue0(v.Line, OpPhi, lenType)
cap := v.Block.NewValue0(v.Line, OpPhi, lenType)
ptr := v.Block.NewValue0(v.Pos, OpPhi, ptrType)
len := v.Block.NewValue0(v.Pos, OpPhi, lenType)
cap := v.Block.NewValue0(v.Pos, OpPhi, lenType)
for _, a := range v.Args {
ptr.AddArg(a.Block.NewValue1(v.Line, OpSlicePtr, ptrType, a))
len.AddArg(a.Block.NewValue1(v.Line, OpSliceLen, lenType, a))
cap.AddArg(a.Block.NewValue1(v.Line, OpSliceCap, lenType, a))
ptr.AddArg(a.Block.NewValue1(v.Pos, OpSlicePtr, ptrType, a))
len.AddArg(a.Block.NewValue1(v.Pos, OpSliceLen, lenType, a))
cap.AddArg(a.Block.NewValue1(v.Pos, OpSliceCap, lenType, a))
}
v.reset(OpSliceMake)
v.AddArg(ptr)
@ -172,11 +172,11 @@ func decomposeInt64Phi(v *Value) {
partType = fe.TypeUInt32()
}
hi := v.Block.NewValue0(v.Line, OpPhi, partType)
lo := v.Block.NewValue0(v.Line, OpPhi, fe.TypeUInt32())
hi := v.Block.NewValue0(v.Pos, OpPhi, partType)
lo := v.Block.NewValue0(v.Pos, OpPhi, fe.TypeUInt32())
for _, a := range v.Args {
hi.AddArg(a.Block.NewValue1(v.Line, OpInt64Hi, partType, a))
lo.AddArg(a.Block.NewValue1(v.Line, OpInt64Lo, fe.TypeUInt32(), a))
hi.AddArg(a.Block.NewValue1(v.Pos, OpInt64Hi, partType, a))
lo.AddArg(a.Block.NewValue1(v.Pos, OpInt64Lo, fe.TypeUInt32(), a))
}
v.reset(OpInt64Make)
v.AddArg(hi)
@ -195,11 +195,11 @@ func decomposeComplexPhi(v *Value) {
v.Fatalf("decomposeComplexPhi: bad complex size %d", z)
}
real := v.Block.NewValue0(v.Line, OpPhi, partType)
imag := v.Block.NewValue0(v.Line, OpPhi, partType)
real := v.Block.NewValue0(v.Pos, OpPhi, partType)
imag := v.Block.NewValue0(v.Pos, OpPhi, partType)
for _, a := range v.Args {
real.AddArg(a.Block.NewValue1(v.Line, OpComplexReal, partType, a))
imag.AddArg(a.Block.NewValue1(v.Line, OpComplexImag, partType, a))
real.AddArg(a.Block.NewValue1(v.Pos, OpComplexReal, partType, a))
imag.AddArg(a.Block.NewValue1(v.Pos, OpComplexImag, partType, a))
}
v.reset(OpComplexMake)
v.AddArg(real)
@ -209,11 +209,11 @@ func decomposeComplexPhi(v *Value) {
func decomposeInterfacePhi(v *Value) {
ptrType := v.Block.Func.Config.fe.TypeBytePtr()
itab := v.Block.NewValue0(v.Line, OpPhi, ptrType)
data := v.Block.NewValue0(v.Line, OpPhi, ptrType)
itab := v.Block.NewValue0(v.Pos, OpPhi, ptrType)
data := v.Block.NewValue0(v.Pos, OpPhi, ptrType)
for _, a := range v.Args {
itab.AddArg(a.Block.NewValue1(v.Line, OpITab, ptrType, a))
data.AddArg(a.Block.NewValue1(v.Line, OpIData, ptrType, a))
itab.AddArg(a.Block.NewValue1(v.Pos, OpITab, ptrType, a))
data.AddArg(a.Block.NewValue1(v.Pos, OpIData, ptrType, a))
}
v.reset(OpIMake)
v.AddArg(itab)
@ -247,7 +247,7 @@ func decomposeUser(f *Func) {
}
for _, v := range f.NamedValues[name] {
for i := 0; i < n; i++ {
x := v.Block.NewValue1I(v.Line, OpStructSelect, t.FieldType(i), int64(i), v)
x := v.Block.NewValue1I(v.Pos, OpStructSelect, t.FieldType(i), int64(i), v)
f.NamedValues[fnames[i]] = append(f.NamedValues[fnames[i]], x)
}
}
@ -264,7 +264,7 @@ func decomposeUser(f *Func) {
}
elemName := f.Config.fe.SplitArray(name)
for _, v := range f.NamedValues[name] {
e := v.Block.NewValue1I(v.Line, OpArraySelect, t.ElemType(), 0, v)
e := v.Block.NewValue1I(v.Pos, OpArraySelect, t.ElemType(), 0, v)
f.NamedValues[elemName] = append(f.NamedValues[elemName], e)
}
@ -293,11 +293,11 @@ func decomposeStructPhi(v *Value) {
n := t.NumFields()
var fields [MaxStruct]*Value
for i := 0; i < n; i++ {
fields[i] = v.Block.NewValue0(v.Line, OpPhi, t.FieldType(i))
fields[i] = v.Block.NewValue0(v.Pos, OpPhi, t.FieldType(i))
}
for _, a := range v.Args {
for i := 0; i < n; i++ {
fields[i].AddArg(a.Block.NewValue1I(v.Line, OpStructSelect, t.FieldType(i), int64(i), a))
fields[i].AddArg(a.Block.NewValue1I(v.Pos, OpStructSelect, t.FieldType(i), int64(i), a))
}
}
v.reset(StructMakeOp(n))
@ -320,9 +320,9 @@ func decomposeArrayPhi(v *Value) {
if t.NumElem() != 1 {
v.Fatalf("SSAable array must have no more than 1 element")
}
elem := v.Block.NewValue0(v.Line, OpPhi, t.ElemType())
elem := v.Block.NewValue0(v.Pos, OpPhi, t.ElemType())
for _, a := range v.Args {
elem.AddArg(a.Block.NewValue1I(v.Line, OpArraySelect, t.ElemType(), 0, a))
elem.AddArg(a.Block.NewValue1I(v.Pos, OpArraySelect, t.ElemType(), 0, a))
}
v.reset(OpArrayMake1)
v.AddArg(elem)

View file

@ -7,6 +7,7 @@ package ssa
import (
"cmd/internal/obj"
"cmd/internal/obj/x86"
"cmd/internal/src"
"testing"
)
@ -62,7 +63,7 @@ func (d DummyFrontend) SplitStruct(s LocalSlot, i int) LocalSlot {
func (d DummyFrontend) SplitArray(s LocalSlot) LocalSlot {
return LocalSlot{s.N, s.Type.ElemType(), s.Off}
}
func (DummyFrontend) Line(line int32) string {
func (DummyFrontend) Line(_ src.XPos) string {
return "unknown.go:0"
}
func (DummyFrontend) AllocFrame(f *Func) {
@ -74,8 +75,8 @@ func (DummyFrontend) Syslook(s string) interface{} {
func (d DummyFrontend) Logf(msg string, args ...interface{}) { d.t.Logf(msg, args...) }
func (d DummyFrontend) Log() bool { return true }
func (d DummyFrontend) Fatalf(line int32, msg string, args ...interface{}) { d.t.Fatalf(msg, args...) }
func (d DummyFrontend) Warnl(line int32, msg string, args ...interface{}) { d.t.Logf(msg, args...) }
func (d DummyFrontend) Fatalf(_ src.XPos, msg string, args ...interface{}) { d.t.Fatalf(msg, args...) }
func (d DummyFrontend) Warnl(_ src.XPos, msg string, args ...interface{}) { d.t.Logf(msg, args...) }
func (d DummyFrontend) Debug_checknil() bool { return false }
func (d DummyFrontend) Debug_wb() bool { return false }

View file

@ -5,6 +5,7 @@
package ssa
import (
"cmd/internal/src"
"fmt"
"math"
"strings"
@ -80,7 +81,7 @@ func (f *Func) retSparseSet(ss *sparseSet) {
}
// newValue allocates a new Value with the given fields and places it at the end of b.Values.
func (f *Func) newValue(op Op, t Type, b *Block, line int32) *Value {
func (f *Func) newValue(op Op, t Type, b *Block, pos src.XPos) *Value {
var v *Value
if f.freeValues != nil {
v = f.freeValues
@ -97,7 +98,7 @@ func (f *Func) newValue(op Op, t Type, b *Block, line int32) *Value {
v.Op = op
v.Type = t
v.Block = b
v.Line = line
v.Pos = pos
b.Values = append(b.Values, v)
return v
}
@ -117,7 +118,7 @@ func (f *Func) LogStat(key string, args ...interface{}) {
if f.pass != nil {
n = strings.Replace(f.pass.name, " ", "_", -1)
}
f.Config.Warnl(f.Entry.Line, "\t%s\t%s%s\t%s", n, key, value, f.Name)
f.Config.Warnl(f.Entry.Pos, "\t%s\t%s%s\t%s", n, key, value, f.Name)
}
// freeValue frees a value. It must no longer be referenced.
@ -187,30 +188,30 @@ func (f *Func) freeBlock(b *Block) {
}
// NewValue0 returns a new value in the block with no arguments and zero aux values.
func (b *Block) NewValue0(line int32, op Op, t Type) *Value {
v := b.Func.newValue(op, t, b, line)
func (b *Block) NewValue0(pos src.XPos, op Op, t Type) *Value {
v := b.Func.newValue(op, t, b, pos)
v.AuxInt = 0
v.Args = v.argstorage[:0]
return v
}
// NewValue returns a new value in the block with no arguments and an auxint value.
func (b *Block) NewValue0I(line int32, op Op, t Type, auxint int64) *Value {
v := b.Func.newValue(op, t, b, line)
func (b *Block) NewValue0I(pos src.XPos, op Op, t Type, auxint int64) *Value {
v := b.Func.newValue(op, t, b, pos)
v.AuxInt = auxint
v.Args = v.argstorage[:0]
return v
}
// NewValue returns a new value in the block with no arguments and an aux value.
func (b *Block) NewValue0A(line int32, op Op, t Type, aux interface{}) *Value {
func (b *Block) NewValue0A(pos src.XPos, op Op, t Type, aux interface{}) *Value {
if _, ok := aux.(int64); ok {
// Disallow int64 aux values. They should be in the auxint field instead.
// Maybe we want to allow this at some point, but for now we disallow it
// to prevent errors like using NewValue1A instead of NewValue1I.
b.Fatalf("aux field has int64 type op=%s type=%s aux=%v", op, t, aux)
}
v := b.Func.newValue(op, t, b, line)
v := b.Func.newValue(op, t, b, pos)
v.AuxInt = 0
v.Aux = aux
v.Args = v.argstorage[:0]
@ -218,8 +219,8 @@ func (b *Block) NewValue0A(line int32, op Op, t Type, aux interface{}) *Value {
}
// NewValue returns a new value in the block with no arguments and both an auxint and aux values.
func (b *Block) NewValue0IA(line int32, op Op, t Type, auxint int64, aux interface{}) *Value {
v := b.Func.newValue(op, t, b, line)
func (b *Block) NewValue0IA(pos src.XPos, op Op, t Type, auxint int64, aux interface{}) *Value {
v := b.Func.newValue(op, t, b, pos)
v.AuxInt = auxint
v.Aux = aux
v.Args = v.argstorage[:0]
@ -227,8 +228,8 @@ func (b *Block) NewValue0IA(line int32, op Op, t Type, auxint int64, aux interfa
}
// NewValue1 returns a new value in the block with one argument and zero aux values.
func (b *Block) NewValue1(line int32, op Op, t Type, arg *Value) *Value {
v := b.Func.newValue(op, t, b, line)
func (b *Block) NewValue1(pos src.XPos, op Op, t Type, arg *Value) *Value {
v := b.Func.newValue(op, t, b, pos)
v.AuxInt = 0
v.Args = v.argstorage[:1]
v.argstorage[0] = arg
@ -237,8 +238,8 @@ func (b *Block) NewValue1(line int32, op Op, t Type, arg *Value) *Value {
}
// NewValue1I returns a new value in the block with one argument and an auxint value.
func (b *Block) NewValue1I(line int32, op Op, t Type, auxint int64, arg *Value) *Value {
v := b.Func.newValue(op, t, b, line)
func (b *Block) NewValue1I(pos src.XPos, op Op, t Type, auxint int64, arg *Value) *Value {
v := b.Func.newValue(op, t, b, pos)
v.AuxInt = auxint
v.Args = v.argstorage[:1]
v.argstorage[0] = arg
@ -247,8 +248,8 @@ func (b *Block) NewValue1I(line int32, op Op, t Type, auxint int64, arg *Value)
}
// NewValue1A returns a new value in the block with one argument and an aux value.
func (b *Block) NewValue1A(line int32, op Op, t Type, aux interface{}, arg *Value) *Value {
v := b.Func.newValue(op, t, b, line)
func (b *Block) NewValue1A(pos src.XPos, op Op, t Type, aux interface{}, arg *Value) *Value {
v := b.Func.newValue(op, t, b, pos)
v.AuxInt = 0
v.Aux = aux
v.Args = v.argstorage[:1]
@ -258,8 +259,8 @@ func (b *Block) NewValue1A(line int32, op Op, t Type, aux interface{}, arg *Valu
}
// NewValue1IA returns a new value in the block with one argument and both an auxint and aux values.
func (b *Block) NewValue1IA(line int32, op Op, t Type, auxint int64, aux interface{}, arg *Value) *Value {
v := b.Func.newValue(op, t, b, line)
func (b *Block) NewValue1IA(pos src.XPos, op Op, t Type, auxint int64, aux interface{}, arg *Value) *Value {
v := b.Func.newValue(op, t, b, pos)
v.AuxInt = auxint
v.Aux = aux
v.Args = v.argstorage[:1]
@ -269,8 +270,8 @@ func (b *Block) NewValue1IA(line int32, op Op, t Type, auxint int64, aux interfa
}
// NewValue2 returns a new value in the block with two arguments and zero aux values.
func (b *Block) NewValue2(line int32, op Op, t Type, arg0, arg1 *Value) *Value {
v := b.Func.newValue(op, t, b, line)
func (b *Block) NewValue2(pos src.XPos, op Op, t Type, arg0, arg1 *Value) *Value {
v := b.Func.newValue(op, t, b, pos)
v.AuxInt = 0
v.Args = v.argstorage[:2]
v.argstorage[0] = arg0
@ -281,8 +282,8 @@ func (b *Block) NewValue2(line int32, op Op, t Type, arg0, arg1 *Value) *Value {
}
// NewValue2I returns a new value in the block with two arguments and an auxint value.
func (b *Block) NewValue2I(line int32, op Op, t Type, auxint int64, arg0, arg1 *Value) *Value {
v := b.Func.newValue(op, t, b, line)
func (b *Block) NewValue2I(pos src.XPos, op Op, t Type, auxint int64, arg0, arg1 *Value) *Value {
v := b.Func.newValue(op, t, b, pos)
v.AuxInt = auxint
v.Args = v.argstorage[:2]
v.argstorage[0] = arg0
@ -293,8 +294,8 @@ func (b *Block) NewValue2I(line int32, op Op, t Type, auxint int64, arg0, arg1 *
}
// NewValue3 returns a new value in the block with three arguments and zero aux values.
func (b *Block) NewValue3(line int32, op Op, t Type, arg0, arg1, arg2 *Value) *Value {
v := b.Func.newValue(op, t, b, line)
func (b *Block) NewValue3(pos src.XPos, op Op, t Type, arg0, arg1, arg2 *Value) *Value {
v := b.Func.newValue(op, t, b, pos)
v.AuxInt = 0
v.Args = v.argstorage[:3]
v.argstorage[0] = arg0
@ -307,8 +308,8 @@ func (b *Block) NewValue3(line int32, op Op, t Type, arg0, arg1, arg2 *Value) *V
}
// NewValue3I returns a new value in the block with three arguments and an auxint value.
func (b *Block) NewValue3I(line int32, op Op, t Type, auxint int64, arg0, arg1, arg2 *Value) *Value {
v := b.Func.newValue(op, t, b, line)
func (b *Block) NewValue3I(pos src.XPos, op Op, t Type, auxint int64, arg0, arg1, arg2 *Value) *Value {
v := b.Func.newValue(op, t, b, pos)
v.AuxInt = auxint
v.Args = v.argstorage[:3]
v.argstorage[0] = arg0
@ -321,8 +322,8 @@ func (b *Block) NewValue3I(line int32, op Op, t Type, auxint int64, arg0, arg1,
}
// NewValue4 returns a new value in the block with four arguments and zero aux values.
func (b *Block) NewValue4(line int32, op Op, t Type, arg0, arg1, arg2, arg3 *Value) *Value {
v := b.Func.newValue(op, t, b, line)
func (b *Block) NewValue4(pos src.XPos, op Op, t Type, arg0, arg1, arg2, arg3 *Value) *Value {
v := b.Func.newValue(op, t, b, pos)
v.AuxInt = 0
v.Args = []*Value{arg0, arg1, arg2, arg3}
arg0.Uses++
@ -333,7 +334,7 @@ func (b *Block) NewValue4(line int32, op Op, t Type, arg0, arg1, arg2, arg3 *Val
}
// constVal returns a constant value for c.
func (f *Func) constVal(line int32, op Op, t Type, c int64, setAux bool) *Value {
func (f *Func) constVal(pos src.XPos, op Op, t Type, c int64, setAux bool) *Value {
if f.constants == nil {
f.constants = make(map[int64][]*Value)
}
@ -348,9 +349,9 @@ func (f *Func) constVal(line int32, op Op, t Type, c int64, setAux bool) *Value
}
var v *Value
if setAux {
v = f.Entry.NewValue0I(line, op, t, c)
v = f.Entry.NewValue0I(pos, op, t, c)
} else {
v = f.Entry.NewValue0(line, op, t)
v = f.Entry.NewValue0(pos, op, t)
}
f.constants[c] = append(vv, v)
return v
@ -368,50 +369,50 @@ const (
)
// ConstInt returns an int constant representing its argument.
func (f *Func) ConstBool(line int32, t Type, c bool) *Value {
func (f *Func) ConstBool(pos src.XPos, t Type, c bool) *Value {
i := int64(0)
if c {
i = 1
}
return f.constVal(line, OpConstBool, t, i, true)
return f.constVal(pos, OpConstBool, t, i, true)
}
func (f *Func) ConstInt8(line int32, t Type, c int8) *Value {
return f.constVal(line, OpConst8, t, int64(c), true)
func (f *Func) ConstInt8(pos src.XPos, t Type, c int8) *Value {
return f.constVal(pos, OpConst8, t, int64(c), true)
}
func (f *Func) ConstInt16(line int32, t Type, c int16) *Value {
return f.constVal(line, OpConst16, t, int64(c), true)
func (f *Func) ConstInt16(pos src.XPos, t Type, c int16) *Value {
return f.constVal(pos, OpConst16, t, int64(c), true)
}
func (f *Func) ConstInt32(line int32, t Type, c int32) *Value {
return f.constVal(line, OpConst32, t, int64(c), true)
func (f *Func) ConstInt32(pos src.XPos, t Type, c int32) *Value {
return f.constVal(pos, OpConst32, t, int64(c), true)
}
func (f *Func) ConstInt64(line int32, t Type, c int64) *Value {
return f.constVal(line, OpConst64, t, c, true)
func (f *Func) ConstInt64(pos src.XPos, t Type, c int64) *Value {
return f.constVal(pos, OpConst64, t, c, true)
}
func (f *Func) ConstFloat32(line int32, t Type, c float64) *Value {
return f.constVal(line, OpConst32F, t, int64(math.Float64bits(float64(float32(c)))), true)
func (f *Func) ConstFloat32(pos src.XPos, t Type, c float64) *Value {
return f.constVal(pos, OpConst32F, t, int64(math.Float64bits(float64(float32(c)))), true)
}
func (f *Func) ConstFloat64(line int32, t Type, c float64) *Value {
return f.constVal(line, OpConst64F, t, int64(math.Float64bits(c)), true)
func (f *Func) ConstFloat64(pos src.XPos, t Type, c float64) *Value {
return f.constVal(pos, OpConst64F, t, int64(math.Float64bits(c)), true)
}
func (f *Func) ConstSlice(line int32, t Type) *Value {
return f.constVal(line, OpConstSlice, t, constSliceMagic, false)
func (f *Func) ConstSlice(pos src.XPos, t Type) *Value {
return f.constVal(pos, OpConstSlice, t, constSliceMagic, false)
}
func (f *Func) ConstInterface(line int32, t Type) *Value {
return f.constVal(line, OpConstInterface, t, constInterfaceMagic, false)
func (f *Func) ConstInterface(pos src.XPos, t Type) *Value {
return f.constVal(pos, OpConstInterface, t, constInterfaceMagic, false)
}
func (f *Func) ConstNil(line int32, t Type) *Value {
return f.constVal(line, OpConstNil, t, constNilMagic, false)
func (f *Func) ConstNil(pos src.XPos, t Type) *Value {
return f.constVal(pos, OpConstNil, t, constNilMagic, false)
}
func (f *Func) ConstEmptyString(line int32, t Type) *Value {
v := f.constVal(line, OpConstString, t, constEmptyStringMagic, false)
func (f *Func) ConstEmptyString(pos src.XPos, t Type) *Value {
v := f.constVal(pos, OpConstString, t, constEmptyStringMagic, false)
v.Aux = ""
return v
}
func (f *Func) Logf(msg string, args ...interface{}) { f.Config.Logf(msg, args...) }
func (f *Func) Log() bool { return f.Config.Log() }
func (f *Func) Fatalf(msg string, args ...interface{}) { f.Config.Fatalf(f.Entry.Line, msg, args...) }
func (f *Func) Fatalf(msg string, args ...interface{}) { f.Config.Fatalf(f.Entry.Pos, msg, args...) }
func (f *Func) Free() {
// Clear cached CFG info.

View file

@ -37,6 +37,7 @@ package ssa
// the parser can be used instead of Fun.
import (
"cmd/internal/src"
"fmt"
"reflect"
"testing"
@ -154,7 +155,7 @@ func Fun(c *Config, entry string, blocs ...bloc) fun {
blocks[bloc.name] = b
for _, valu := range bloc.valus {
// args are filled in the second pass.
values[valu.name] = b.NewValue0IA(0, valu.op, valu.t, valu.auxint, valu.aux)
values[valu.name] = b.NewValue0IA(src.NoXPos, valu.op, valu.t, valu.auxint, valu.aux)
}
}
// Connect the blocks together and specify control values.
@ -428,12 +429,12 @@ func TestConstCache(t *testing.T) {
Bloc("entry",
Valu("mem", OpInitMem, TypeMem, 0, nil),
Exit("mem")))
v1 := f.f.ConstBool(0, TypeBool, false)
v2 := f.f.ConstBool(0, TypeBool, true)
v1 := f.f.ConstBool(src.NoXPos, TypeBool, false)
v2 := f.f.ConstBool(src.NoXPos, TypeBool, true)
f.f.freeValue(v1)
f.f.freeValue(v2)
v3 := f.f.ConstBool(0, TypeBool, false)
v4 := f.f.ConstBool(0, TypeBool, true)
v3 := f.f.ConstBool(src.NoXPos, TypeBool, false)
v4 := f.f.ConstBool(src.NoXPos, TypeBool, true)
if v3.AuxInt != 0 {
t.Errorf("expected %s to have auxint of 0\n", v3.LongString())
}

View file

@ -1009,11 +1009,11 @@
&& mem.Op == OpStaticCall
&& isSameSym(mem.Aux, "runtime.newobject")
&& c == config.ctxt.FixedFrameSize() + config.RegSize // offset of return value
&& warnRule(config.Debug_checknil() && int(v.Line) > 1, v, "removed nil check")
&& warnRule(config.Debug_checknil() && int(v.Pos) > 1, v, "removed nil check")
-> (Invalid)
(NilCheck (OffPtr (Load (OffPtr [c] (SP)) mem)) mem)
&& mem.Op == OpStaticCall
&& isSameSym(mem.Aux, "runtime.newobject")
&& c == config.ctxt.FixedFrameSize() + config.RegSize // offset of return value
&& warnRule(config.Debug_checknil() && int(v.Line) > 1, v, "removed nil check")
&& warnRule(config.Debug_checknil() && int(v.Pos) > 1, v, "removed nil check")
-> (Invalid)

View file

@ -491,7 +491,7 @@ func genResult0(w io.Writer, arch arch, result string, alloc *int, top, move boo
}
v = fmt.Sprintf("v%d", *alloc)
*alloc++
fmt.Fprintf(w, "%s := b.NewValue0(v.Line, Op%s%s, %s)\n", v, oparch, op.name, typ)
fmt.Fprintf(w, "%s := b.NewValue0(v.Pos, Op%s%s, %s)\n", v, oparch, op.name, typ)
if move && top {
// Rewrite original into a copy
fmt.Fprintf(w, "v.reset(OpCopy)\n")

View file

@ -6,6 +6,7 @@ package ssa
import (
"bytes"
"cmd/internal/src"
"fmt"
"html"
"io"
@ -20,7 +21,7 @@ type HTMLWriter struct {
func NewHTMLWriter(path string, logger Logger, funcname string) *HTMLWriter {
out, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
if err != nil {
logger.Fatalf(0, "%v", err)
logger.Fatalf(src.NoXPos, "%v", err)
}
html := HTMLWriter{File: out, Logger: logger}
html.start(funcname)
@ -328,13 +329,13 @@ func (w *HTMLWriter) WriteColumn(title string, html string) {
func (w *HTMLWriter) Printf(msg string, v ...interface{}) {
if _, err := fmt.Fprintf(w.File, msg, v...); err != nil {
w.Fatalf(0, "%v", err)
w.Fatalf(src.NoXPos, "%v", err)
}
}
func (w *HTMLWriter) WriteString(s string) {
if _, err := w.File.WriteString(s); err != nil {
w.Fatalf(0, "%v", err)
w.Fatalf(src.NoXPos, "%v", err)
}
}

View file

@ -108,7 +108,7 @@ func describePredictionAgrees(b *Block, prediction BranchPrediction) string {
}
func describeBranchPrediction(f *Func, b *Block, likely, not int8, prediction BranchPrediction) {
f.Config.Warnl(b.Line, "Branch prediction rule %s < %s%s",
f.Config.Warnl(b.Pos, "Branch prediction rule %s < %s%s",
bllikelies[likely-blMin], bllikelies[not-blMin], describePredictionAgrees(b, prediction))
}
@ -183,7 +183,7 @@ func likelyadjust(f *Func) {
noprediction = true
}
if f.pass.debug > 0 && !noprediction {
f.Config.Warnl(b.Line, "Branch prediction rule stay in loop%s",
f.Config.Warnl(b.Pos, "Branch prediction rule stay in loop%s",
describePredictionAgrees(b, prediction))
}
@ -226,7 +226,7 @@ func likelyadjust(f *Func) {
}
}
if f.pass.debug > 2 {
f.Config.Warnl(b.Line, "BP: Block %s, local=%s, certain=%s", b, bllikelies[local[b.ID]-blMin], bllikelies[certain[b.ID]-blMin])
f.Config.Warnl(b.Pos, "BP: Block %s, local=%s, certain=%s", b, bllikelies[local[b.ID]-blMin], bllikelies[certain[b.ID]-blMin])
}
}

View file

@ -139,9 +139,9 @@ nextb:
if f.pass.debug > 1 {
if min.Op == OpConst64 {
b.Func.Config.Warnl(b.Line, "Induction variable with minimum %d and increment %d", min.AuxInt, inc.AuxInt)
b.Func.Config.Warnl(b.Pos, "Induction variable with minimum %d and increment %d", min.AuxInt, inc.AuxInt)
} else {
b.Func.Config.Warnl(b.Line, "Induction variable with non-const minimum and increment %d", inc.AuxInt)
b.Func.Config.Warnl(b.Pos, "Induction variable with non-const minimum and increment %d", inc.AuxInt)
}
}
@ -205,7 +205,7 @@ func removeBoundsChecks(f *Func, m map[*Value]indVar) {
if iv, has := m[ind]; has && sdom.isAncestorEq(iv.entry, b) && isNonNegative(iv.min) {
if v.Args[1] == iv.max {
if f.pass.debug > 0 {
f.Config.Warnl(b.Line, "Found redundant %s", v.Op)
f.Config.Warnl(b.Pos, "Found redundant %s", v.Op)
}
goto simplify
}
@ -232,7 +232,7 @@ func removeBoundsChecks(f *Func, m map[*Value]indVar) {
if iv, has := m[ind]; has && sdom.isAncestorEq(iv.entry, b) && isNonNegative(iv.min) {
if v.Args[1].Op == OpSliceCap && iv.max.Op == OpSliceLen && v.Args[1].Args[0] == iv.max.Args[0] {
if f.pass.debug > 0 {
f.Config.Warnl(b.Line, "Found redundant %s (len promoted to cap)", v.Op)
f.Config.Warnl(b.Pos, "Found redundant %s (len promoted to cap)", v.Op)
}
goto simplify
}
@ -263,7 +263,7 @@ func removeBoundsChecks(f *Func, m map[*Value]indVar) {
if max := iv.max.AuxInt + add; 0 <= max && max <= limit { // handle overflow
if f.pass.debug > 0 {
f.Config.Warnl(b.Line, "Found redundant (%s ind %d), ind < %d", v.Op, v.Args[1].AuxInt, iv.max.AuxInt+add)
f.Config.Warnl(b.Pos, "Found redundant (%s ind %d), ind < %d", v.Op, v.Args[1].AuxInt, iv.max.AuxInt+add)
}
goto simplify
}

View file

@ -91,7 +91,7 @@ func insertLoopReschedChecks(f *Func) {
// It's possible that there is no memory state (no global/pointer loads/stores or calls)
if lastMems[f.Entry.ID] == nil {
lastMems[f.Entry.ID] = f.Entry.NewValue0(f.Entry.Line, OpInitMem, TypeMem)
lastMems[f.Entry.ID] = f.Entry.NewValue0(f.Entry.Pos, OpInitMem, TypeMem)
}
memDefsAtBlockEnds := make([]*Value, f.NumBlocks()) // For each block, the mem def seen at its bottom. Could be from earlier block.
@ -109,7 +109,7 @@ func insertLoopReschedChecks(f *Func) {
}
// Set up counter. There are no phis etc pre-existing for it.
counter0 := f.Entry.NewValue0I(f.Entry.Line, OpConst32, f.Config.fe.TypeInt32(), initialRescheduleCounterValue)
counter0 := f.Entry.NewValue0I(f.Entry.Pos, OpConst32, f.Config.fe.TypeInt32(), initialRescheduleCounterValue)
ctrDefsAtBlockEnds := make([]*Value, f.NumBlocks()) // For each block, def visible at its end, if that def will be used.
// There's a minor difference between memDefsAtBlockEnds and ctrDefsAtBlockEnds;
@ -205,8 +205,8 @@ func insertLoopReschedChecks(f *Func) {
}
}
zero := f.Entry.NewValue0I(f.Entry.Line, OpConst32, f.Config.fe.TypeInt32(), 0)
one := f.Entry.NewValue0I(f.Entry.Line, OpConst32, f.Config.fe.TypeInt32(), 1)
zero := f.Entry.NewValue0I(f.Entry.Pos, OpConst32, f.Config.fe.TypeInt32(), 0)
one := f.Entry.NewValue0I(f.Entry.Pos, OpConst32, f.Config.fe.TypeInt32(), 1)
// Rewrite backedges to include reschedule checks.
for _, emc := range tofixBackedges {
@ -258,14 +258,14 @@ func insertLoopReschedChecks(f *Func) {
test := f.NewBlock(BlockIf)
sched := f.NewBlock(BlockPlain)
test.Line = bb.Line
sched.Line = bb.Line
test.Pos = bb.Pos
sched.Pos = bb.Pos
// ctr1 := ctr0 - 1
// if ctr1 <= 0 { goto sched }
// goto header
ctr1 := test.NewValue2(bb.Line, OpSub32, f.Config.fe.TypeInt32(), ctr0, one)
cmp := test.NewValue2(bb.Line, OpLeq32, f.Config.fe.TypeBool(), ctr1, zero)
ctr1 := test.NewValue2(bb.Pos, OpSub32, f.Config.fe.TypeInt32(), ctr0, one)
cmp := test.NewValue2(bb.Pos, OpLeq32, f.Config.fe.TypeBool(), ctr1, zero)
test.SetControl(cmp)
test.AddEdgeTo(sched) // if true
// if false -- rewrite edge to header.
@ -282,7 +282,7 @@ func insertLoopReschedChecks(f *Func) {
// mem1 := call resched (mem0)
// goto header
resched := f.Config.fe.Syslook("goschedguarded")
mem1 := sched.NewValue1A(bb.Line, OpStaticCall, TypeMem, resched, mem0)
mem1 := sched.NewValue1A(bb.Pos, OpStaticCall, TypeMem, resched, mem0)
sched.AddEdgeTo(h)
headerMemPhi.AddArg(mem1)
headerCtrPhi.AddArg(counter0)
@ -313,7 +313,7 @@ func insertLoopReschedChecks(f *Func) {
// newPhiFor inserts a new Phi function into b,
// with all inputs set to v.
func newPhiFor(b *Block, v *Value) *Value {
phiV := b.NewValue0(b.Line, OpPhi, v.Type)
phiV := b.NewValue0(b.Pos, OpPhi, v.Type)
for range b.Preds {
phiV.AddArg(v)

View file

@ -101,8 +101,8 @@ func nilcheckelim(f *Func) {
// This is a redundant implicit nil check.
// Logging in the style of the former compiler -- and omit line 1,
// which is usually in generated code.
if f.Config.Debug_checknil() && v.Line > 1 {
f.Config.Warnl(v.Line, "removed nil check")
if f.Config.Debug_checknil() && v.Pos.Line() > 1 {
f.Config.Warnl(v.Pos, "removed nil check")
}
v.reset(OpUnknown)
// TODO: f.freeValue(v)
@ -161,8 +161,8 @@ func nilcheckelim2(f *Func) {
for i := len(b.Values) - 1; i >= 0; i-- {
v := b.Values[i]
if opcodeTable[v.Op].nilCheck && unnecessary.contains(v.Args[0].ID) {
if f.Config.Debug_checknil() && int(v.Line) > 1 {
f.Config.Warnl(v.Line, "removed nil check")
if f.Config.Debug_checknil() && v.Pos.Line() > 1 {
f.Config.Warnl(v.Pos, "removed nil check")
}
v.reset(OpUnknown)
continue

View file

@ -63,7 +63,7 @@ func phielimValue(v *Value) bool {
v.SetArgs1(w)
f := v.Block.Func
if f.pass.debug > 0 {
f.Config.Warnl(v.Line, "eliminated phi")
f.Config.Warnl(v.Pos, "eliminated phi")
}
return true
}

View file

@ -81,7 +81,7 @@ func phiopt(f *Func) {
v.reset(ops[v.Args[reverse].AuxInt])
v.AddArg(b0.Control)
if f.pass.debug > 0 {
f.Config.Warnl(b.Line, "converted OpPhi to %v", v.Op)
f.Config.Warnl(b.Pos, "converted OpPhi to %v", v.Op)
}
continue
}
@ -97,7 +97,7 @@ func phiopt(f *Func) {
v.reset(OpOrB)
v.SetArgs2(b0.Control, tmp)
if f.pass.debug > 0 {
f.Config.Warnl(b.Line, "converted OpPhi to %v", v.Op)
f.Config.Warnl(b.Pos, "converted OpPhi to %v", v.Op)
}
continue
}
@ -113,7 +113,7 @@ func phiopt(f *Func) {
v.reset(OpAndB)
v.SetArgs2(b0.Control, tmp)
if f.pass.debug > 0 {
f.Config.Warnl(b.Line, "converted OpPhi to %v", v.Op)
f.Config.Warnl(b.Pos, "converted OpPhi to %v", v.Op)
}
continue
}
@ -163,12 +163,12 @@ func phioptint(v *Value, b0 *Block, reverse int) {
a := b0.Control
if negate {
a = v.Block.NewValue1(v.Line, OpNot, a.Type, a)
a = v.Block.NewValue1(v.Pos, OpNot, a.Type, a)
}
v.AddArg(a)
f := b0.Func
if f.pass.debug > 0 {
f.Config.Warnl(v.Block.Line, "converted OpPhi bool -> int%d", v.Type.Size()*8)
f.Config.Warnl(v.Block.Pos, "converted OpPhi bool -> int%d", v.Type.Size()*8)
}
}

View file

@ -62,7 +62,7 @@ func (p stringFuncPrinter) endBlock(b *Block) {
func (p stringFuncPrinter) value(v *Value, live bool) {
fmt.Fprint(p.w, " ")
//fmt.Fprint(p.w, v.Block.Func.Config.fe.Line(v.Line))
//fmt.Fprint(p.w, v.Block.Func.Config.fe.Pos(v.Pos))
//fmt.Fprint(p.w, ": ")
fmt.Fprint(p.w, v.LongString())
if !live {

View file

@ -301,7 +301,7 @@ func (ft *factsTable) update(parent *Block, v, w *Value, d domain, r relation) {
ft.limitStack = append(ft.limitStack, limitFact{v.ID, old})
ft.limits[v.ID] = lim
if v.Block.Func.pass.debug > 2 {
v.Block.Func.Config.Warnl(parent.Line, "parent=%s, new limits %s %s %s", parent, v, w, lim.String())
v.Block.Func.Config.Warnl(parent.Pos, "parent=%s, new limits %s %s %s", parent, v, w, lim.String())
}
}
}
@ -600,7 +600,7 @@ func simplifyBlock(ft *factsTable, b *Block) branch {
v.reset(OpConst32)
}
if b.Func.pass.debug > 0 {
b.Func.Config.Warnl(v.Line, "Proved slicemask not needed")
b.Func.Config.Warnl(v.Pos, "Proved slicemask not needed")
}
v.AuxInt = -1
}
@ -615,9 +615,9 @@ func simplifyBlock(ft *factsTable, b *Block) branch {
if m == lt|gt {
if b.Func.pass.debug > 0 {
if b.Func.pass.debug > 1 {
b.Func.Config.Warnl(b.Line, "Proved boolean %s (%s)", b.Control.Op, b.Control)
b.Func.Config.Warnl(b.Pos, "Proved boolean %s (%s)", b.Control.Op, b.Control)
} else {
b.Func.Config.Warnl(b.Line, "Proved boolean %s", b.Control.Op)
b.Func.Config.Warnl(b.Pos, "Proved boolean %s", b.Control.Op)
}
}
return positive
@ -625,9 +625,9 @@ func simplifyBlock(ft *factsTable, b *Block) branch {
if m == eq {
if b.Func.pass.debug > 0 {
if b.Func.pass.debug > 1 {
b.Func.Config.Warnl(b.Line, "Disproved boolean %s (%s)", b.Control.Op, b.Control)
b.Func.Config.Warnl(b.Pos, "Disproved boolean %s (%s)", b.Control.Op, b.Control)
} else {
b.Func.Config.Warnl(b.Line, "Disproved boolean %s", b.Control.Op)
b.Func.Config.Warnl(b.Pos, "Disproved boolean %s", b.Control.Op)
}
}
return negative
@ -656,9 +656,9 @@ func simplifyBlock(ft *factsTable, b *Block) branch {
if m != 0 && tr.r&m == m {
if b.Func.pass.debug > 0 {
if b.Func.pass.debug > 1 {
b.Func.Config.Warnl(b.Line, "Proved %s (%s)", c.Op, c)
b.Func.Config.Warnl(b.Pos, "Proved %s (%s)", c.Op, c)
} else {
b.Func.Config.Warnl(b.Line, "Proved %s", c.Op)
b.Func.Config.Warnl(b.Pos, "Proved %s", c.Op)
}
}
return positive
@ -666,9 +666,9 @@ func simplifyBlock(ft *factsTable, b *Block) branch {
if m != 0 && ((lt|eq|gt)^tr.r)&m == m {
if b.Func.pass.debug > 0 {
if b.Func.pass.debug > 1 {
b.Func.Config.Warnl(b.Line, "Disproved %s (%s)", c.Op, c)
b.Func.Config.Warnl(b.Pos, "Disproved %s (%s)", c.Op, c)
} else {
b.Func.Config.Warnl(b.Line, "Disproved %s", c.Op)
b.Func.Config.Warnl(b.Pos, "Disproved %s", c.Op)
}
}
return negative
@ -685,9 +685,9 @@ func simplifyBlock(ft *factsTable, b *Block) branch {
if m != 0 && tr.r&m == m {
if b.Func.pass.debug > 0 {
if b.Func.pass.debug > 1 {
b.Func.Config.Warnl(b.Line, "Proved non-negative bounds %s (%s)", c.Op, c)
b.Func.Config.Warnl(b.Pos, "Proved non-negative bounds %s (%s)", c.Op, c)
} else {
b.Func.Config.Warnl(b.Line, "Proved non-negative bounds %s", c.Op)
b.Func.Config.Warnl(b.Pos, "Proved non-negative bounds %s", c.Op)
}
}
return positive

View file

@ -107,6 +107,7 @@ package ssa
import (
"cmd/internal/obj"
"cmd/internal/src"
"fmt"
"unsafe"
)
@ -180,9 +181,9 @@ func pickReg(r regMask) register {
}
type use struct {
dist int32 // distance from start of the block to a use of a value
line int32 // line number of the use
next *use // linked list of uses of a value in nondecreasing dist order
dist int32 // distance from start of the block to a use of a value
pos src.XPos // source position of the use
next *use // linked list of uses of a value in nondecreasing dist order
}
type valState struct {
@ -286,9 +287,9 @@ type endReg struct {
}
type startReg struct {
r register
vid ID // pre-regalloc value needed in this register
line int32 // line number of use of this register
r register
vid ID // pre-regalloc value needed in this register
pos src.XPos // source position of use of this register
}
// freeReg frees up register r. Any current user of r is kicked out.
@ -392,7 +393,7 @@ func (s *regAllocState) allocReg(mask regMask, v *Value) register {
m := s.compatRegs(v2.Type) &^ s.used &^ s.tmpused &^ (regMask(1) << r)
if m != 0 && !s.values[v2.ID].rematerializeable && countRegs(s.values[v2.ID].regs) == 1 {
r2 := pickReg(m)
c := s.curBlock.NewValue1(v2.Line, OpCopy, v2.Type, s.regs[r].c)
c := s.curBlock.NewValue1(v2.Pos, OpCopy, v2.Type, s.regs[r].c)
s.copies[c] = false
if s.f.pass.debug > regDebug {
fmt.Printf("copy %s to %s : %s\n", v2, c, s.registers[r2].Name())
@ -410,7 +411,7 @@ func (s *regAllocState) allocReg(mask regMask, v *Value) register {
// allocated register is marked nospill so the assignment cannot be
// undone until the caller allows it by clearing nospill. Returns a
// *Value which is either v or a copy of v allocated to the chosen register.
func (s *regAllocState) allocValToReg(v *Value, mask regMask, nospill bool, line int32) *Value {
func (s *regAllocState) allocValToReg(v *Value, mask regMask, nospill bool, pos src.XPos) *Value {
vi := &s.values[v.ID]
// Check if v is already in a requested register.
@ -436,7 +437,7 @@ func (s *regAllocState) allocValToReg(v *Value, mask regMask, nospill bool, line
if s.regs[r2].v != v {
panic("bad register state")
}
c = s.curBlock.NewValue1(line, OpCopy, v.Type, s.regs[r2].c)
c = s.curBlock.NewValue1(pos, OpCopy, v.Type, s.regs[r2].c)
} else if v.rematerializeable() {
// Rematerialize instead of loading from the spill location.
c = v.copyInto(s.curBlock)
@ -445,9 +446,9 @@ func (s *regAllocState) allocValToReg(v *Value, mask regMask, nospill bool, line
// Load v from its spill location.
case vi.spill != nil:
if s.f.pass.debug > logSpills {
s.f.Config.Warnl(vi.spill.Line, "load spill for %v from %v", v, vi.spill)
s.f.Config.Warnl(vi.spill.Pos, "load spill for %v from %v", v, vi.spill)
}
c = s.curBlock.NewValue1(line, OpLoadReg, v.Type, vi.spill)
c = s.curBlock.NewValue1(pos, OpLoadReg, v.Type, vi.spill)
vi.spillUsed = true
default:
s.f.Fatalf("attempt to load unspilled value %v", v.LongString())
@ -554,7 +555,7 @@ func (s *regAllocState) init(f *Func) {
case "s390x":
// nothing to do, R10 & R11 already reserved
default:
s.f.Config.fe.Fatalf(0, "arch %s not implemented", s.f.Config.arch)
s.f.Config.fe.Fatalf(src.NoXPos, "arch %s not implemented", s.f.Config.arch)
}
}
if s.f.Config.nacl {
@ -617,7 +618,7 @@ func (s *regAllocState) init(f *Func) {
// Adds a use record for id at distance dist from the start of the block.
// All calls to addUse must happen with nonincreasing dist.
func (s *regAllocState) addUse(id ID, dist int32, line int32) {
func (s *regAllocState) addUse(id ID, dist int32, pos src.XPos) {
r := s.freeUseRecords
if r != nil {
s.freeUseRecords = r.next
@ -625,7 +626,7 @@ func (s *regAllocState) addUse(id ID, dist int32, line int32) {
r = &use{}
}
r.dist = dist
r.line = line
r.pos = pos
r.next = s.values[id].uses
s.values[id].uses = r
if r.next != nil && dist > r.next.dist {
@ -755,11 +756,11 @@ func (s *regAllocState) regalloc(f *Func) {
// Walk backwards through the block doing liveness analysis.
liveSet.clear()
for _, e := range s.live[b.ID] {
s.addUse(e.ID, int32(len(b.Values))+e.dist, e.line) // pseudo-uses from beyond end of block
s.addUse(e.ID, int32(len(b.Values))+e.dist, e.pos) // pseudo-uses from beyond end of block
liveSet.add(e.ID)
}
if v := b.Control; v != nil && s.values[v.ID].needReg {
s.addUse(v.ID, int32(len(b.Values)), b.Line) // pseudo-use by control value
s.addUse(v.ID, int32(len(b.Values)), b.Pos) // pseudo-use by control value
liveSet.add(v.ID)
}
for i := len(b.Values) - 1; i >= 0; i-- {
@ -775,7 +776,7 @@ func (s *regAllocState) regalloc(f *Func) {
if !s.values[a.ID].needReg {
continue
}
s.addUse(a.ID, int32(i), v.Line)
s.addUse(a.ID, int32(i), v.Pos)
liveSet.add(a.ID)
}
}
@ -901,7 +902,7 @@ func (s *regAllocState) regalloc(f *Func) {
m := s.compatRegs(a.Type) &^ s.used &^ phiUsed
if m != 0 && !s.values[a.ID].rematerializeable && countRegs(s.values[a.ID].regs) == 1 {
r2 := pickReg(m)
c := p.NewValue1(a.Line, OpCopy, a.Type, s.regs[r].c)
c := p.NewValue1(a.Pos, OpCopy, a.Type, s.regs[r].c)
s.copies[c] = false
if s.f.pass.debug > regDebug {
fmt.Printf("copy %s to %s : %s\n", a, c, s.registers[r2].Name())
@ -950,7 +951,7 @@ func (s *regAllocState) regalloc(f *Func) {
// register-based phi
s.assignReg(r, v, v)
// Spill the phi in case we need to restore it later.
spill := b.NewValue1(v.Line, OpStoreReg, v.Type, v)
spill := b.NewValue1(v.Pos, OpStoreReg, v.Type, v)
s.setOrig(spill, v)
s.values[v.ID].spill = spill
s.values[v.ID].spillUsed = false
@ -973,7 +974,7 @@ func (s *regAllocState) regalloc(f *Func) {
// specially during merge edge processing.
continue
}
regList = append(regList, startReg{r, v.ID, s.values[v.ID].uses.line})
regList = append(regList, startReg{r, v.ID, s.values[v.ID].uses.pos})
}
s.startRegs[b.ID] = regList
@ -1183,7 +1184,7 @@ func (s *regAllocState) regalloc(f *Func) {
mask &^= desired.avoid
}
}
args[i.idx] = s.allocValToReg(args[i.idx], mask, true, v.Line)
args[i.idx] = s.allocValToReg(args[i.idx], mask, true, v.Pos)
}
// If the output clobbers the input register, make sure we have
@ -1235,7 +1236,7 @@ func (s *regAllocState) regalloc(f *Func) {
for _, r := range dinfo[idx].out {
if r != noRegister && m>>r&1 != 0 {
m = regMask(1) << r
args[0] = s.allocValToReg(v.Args[0], m, true, v.Line)
args[0] = s.allocValToReg(v.Args[0], m, true, v.Pos)
// Note: we update args[0] so the instruction will
// use the register copy we just made.
goto ok
@ -1246,7 +1247,7 @@ func (s *regAllocState) regalloc(f *Func) {
for _, r := range dinfo[idx].in[0] {
if r != noRegister && m>>r&1 != 0 {
m = regMask(1) << r
c := s.allocValToReg(v.Args[0], m, true, v.Line)
c := s.allocValToReg(v.Args[0], m, true, v.Pos)
s.copies[c] = false
// Note: no update to args[0] so the instruction will
// use the original copy.
@ -1257,7 +1258,7 @@ func (s *regAllocState) regalloc(f *Func) {
for _, r := range dinfo[idx].in[1] {
if r != noRegister && m>>r&1 != 0 {
m = regMask(1) << r
c := s.allocValToReg(v.Args[1], m, true, v.Line)
c := s.allocValToReg(v.Args[1], m, true, v.Pos)
s.copies[c] = false
args[0], args[1] = args[1], args[0]
goto ok
@ -1269,7 +1270,7 @@ func (s *regAllocState) regalloc(f *Func) {
m &^= desired.avoid
}
// Save input 0 to a new register so we can clobber it.
c := s.allocValToReg(v.Args[0], m, true, v.Line)
c := s.allocValToReg(v.Args[0], m, true, v.Pos)
s.copies[c] = false
}
@ -1383,7 +1384,7 @@ func (s *regAllocState) regalloc(f *Func) {
// It would be good to have both spill and restore inside the IF.
issueSpill:
if s.values[v.ID].needReg {
spill := b.NewValue1(v.Line, OpStoreReg, v.Type, v)
spill := b.NewValue1(v.Pos, OpStoreReg, v.Type, v)
s.setOrig(spill, v)
s.values[v.ID].spill = spill
s.values[v.ID].spillUsed = false
@ -1403,7 +1404,7 @@ func (s *regAllocState) regalloc(f *Func) {
// We assume that a control input can be passed in any
// type-compatible register. If this turns out not to be true,
// we'll need to introduce a regspec for a block's control value.
b.Control = s.allocValToReg(v, s.compatRegs(v.Type), false, b.Line)
b.Control = s.allocValToReg(v, s.compatRegs(v.Type), false, b.Pos)
if b.Control != v {
v.Uses--
b.Control.Uses++
@ -1458,7 +1459,7 @@ func (s *regAllocState) regalloc(f *Func) {
m &^= desired.avoid
}
if m != 0 {
s.allocValToReg(v, m, false, b.Line)
s.allocValToReg(v, m, false, b.Pos)
}
}
}
@ -1609,7 +1610,7 @@ func (s *regAllocState) regalloc(f *Func) {
vi := s.values[i]
if vi.spillUsed {
if s.f.pass.debug > logSpills && vi.spill.Op != OpArg {
s.f.Config.Warnl(vi.spill.Line, "spilled value at %v remains", vi.spill)
s.f.Config.Warnl(vi.spill.Pos, "spilled value at %v remains", vi.spill)
}
continue
}
@ -1707,7 +1708,7 @@ sinking:
}
// If here, the register assignment was lost down at least one exit and it can't be sunk
if s.f.pass.debug > moveSpills {
s.f.Config.Warnl(e.Line, "lost register assignment for spill %v in %v at exit %v to %v",
s.f.Config.Warnl(e.Pos, "lost register assignment for spill %v in %v at exit %v to %v",
vsp, b, p, d)
}
nSpillsChanged++
@ -1743,10 +1744,10 @@ sinking:
d := loop.exits[i]
vspnew := vsp // reuse original for first sunk spill, saves tracking down and renaming uses
if !first { // any sunk spills after first must make a copy
vspnew = d.NewValue1(e.Line, OpStoreReg, e.Type, e)
vspnew = d.NewValue1(e.Pos, OpStoreReg, e.Type, e)
f.setHome(vspnew, f.getHome(vsp.ID)) // copy stack home
if s.f.pass.debug > moveSpills {
s.f.Config.Warnl(e.Line, "copied spill %v in %v for %v to %v in %v",
s.f.Config.Warnl(e.Pos, "copied spill %v in %v for %v to %v in %v",
vsp, b, e, vspnew, d)
}
} else {
@ -1754,7 +1755,7 @@ sinking:
vspnew.Block = d
d.Values = append(d.Values, vspnew)
if s.f.pass.debug > moveSpills {
s.f.Config.Warnl(e.Line, "moved spill %v in %v for %v to %v in %v",
s.f.Config.Warnl(e.Pos, "moved spill %v in %v for %v to %v in %v",
vsp, b, e, vspnew, d)
}
}
@ -1878,17 +1879,17 @@ type edgeState struct {
}
type contentRecord struct {
vid ID // pre-regalloc value
c *Value // cached value
final bool // this is a satisfied destination
line int32 // line number of use of the value
vid ID // pre-regalloc value
c *Value // cached value
final bool // this is a satisfied destination
pos src.XPos // source position of use of the value
}
type dstRecord struct {
loc Location // register or stack slot
vid ID // pre-regalloc value it should contain
splice **Value // place to store reference to the generating instruction
line int32 // line number of use of this location
pos src.XPos // source position of use of this location
}
// setup initializes the edge state for shuffling.
@ -1911,19 +1912,19 @@ func (e *edgeState) setup(idx int, srcReg []endReg, dstReg []startReg, stacklive
// Live registers can be sources.
for _, x := range srcReg {
e.set(&e.s.registers[x.r], x.v.ID, x.c, false, 0) // don't care the line number of the source
e.set(&e.s.registers[x.r], x.v.ID, x.c, false, src.NoXPos) // don't care the position of the source
}
// So can all of the spill locations.
for _, spillID := range stacklive {
v := e.s.orig[spillID]
spill := e.s.values[v.ID].spill
e.set(e.s.f.getHome(spillID), v.ID, spill, false, 0) // don't care the line number of the source
e.set(e.s.f.getHome(spillID), v.ID, spill, false, src.NoXPos) // don't care the position of the source
}
// Figure out all the destinations we need.
dsts := e.destinations[:0]
for _, x := range dstReg {
dsts = append(dsts, dstRecord{&e.s.registers[x.r], x.vid, nil, x.line})
dsts = append(dsts, dstRecord{&e.s.registers[x.r], x.vid, nil, x.pos})
}
// Phis need their args to end up in a specific location.
for _, v := range e.b.Values {
@ -1934,7 +1935,7 @@ func (e *edgeState) setup(idx int, srcReg []endReg, dstReg []startReg, stacklive
if loc == nil {
continue
}
dsts = append(dsts, dstRecord{loc, v.Args[idx].ID, &v.Args[idx], v.Line})
dsts = append(dsts, dstRecord{loc, v.Args[idx].ID, &v.Args[idx], v.Pos})
}
e.destinations = dsts
@ -1959,7 +1960,7 @@ func (e *edgeState) process() {
for len(dsts) > 0 {
i := 0
for _, d := range dsts {
if !e.processDest(d.loc, d.vid, d.splice, d.line) {
if !e.processDest(d.loc, d.vid, d.splice, d.pos) {
// Failed - save for next iteration.
dsts[i] = d
i++
@ -2006,22 +2007,22 @@ func (e *edgeState) process() {
fmt.Printf("breaking cycle with v%d in %s:%s\n", vid, loc.Name(), c)
}
if _, isReg := loc.(*Register); isReg {
c = e.p.NewValue1(d.line, OpCopy, c.Type, c)
c = e.p.NewValue1(d.pos, OpCopy, c.Type, c)
} else {
e.s.lateSpillUse(vid)
c = e.p.NewValue1(d.line, OpLoadReg, c.Type, c)
c = e.p.NewValue1(d.pos, OpLoadReg, c.Type, c)
}
e.set(r, vid, c, false, d.line)
e.set(r, vid, c, false, d.pos)
}
}
// processDest generates code to put value vid into location loc. Returns true
// if progress was made.
func (e *edgeState) processDest(loc Location, vid ID, splice **Value, line int32) bool {
func (e *edgeState) processDest(loc Location, vid ID, splice **Value, pos src.XPos) bool {
occupant := e.contents[loc]
if occupant.vid == vid {
// Value is already in the correct place.
e.contents[loc] = contentRecord{vid, occupant.c, true, line}
e.contents[loc] = contentRecord{vid, occupant.c, true, pos}
if splice != nil {
(*splice).Uses--
*splice = occupant.c
@ -2087,25 +2088,25 @@ func (e *edgeState) processDest(loc Location, vid ID, splice **Value, line int32
e.erase(loc) // see pre-clobber comment below
r := e.findRegFor(v.Type)
x = v.copyInto(e.p)
e.set(r, vid, x, false, line)
e.set(r, vid, x, false, pos)
// Make sure we spill with the size of the slot, not the
// size of x (which might be wider due to our dropping
// of narrowing conversions).
x = e.p.NewValue1(line, OpStoreReg, loc.(LocalSlot).Type, x)
x = e.p.NewValue1(pos, OpStoreReg, loc.(LocalSlot).Type, x)
}
} else {
// Emit move from src to dst.
_, srcReg := src.(*Register)
if srcReg {
if dstReg {
x = e.p.NewValue1(line, OpCopy, c.Type, c)
x = e.p.NewValue1(pos, OpCopy, c.Type, c)
} else {
x = e.p.NewValue1(line, OpStoreReg, loc.(LocalSlot).Type, c)
x = e.p.NewValue1(pos, OpStoreReg, loc.(LocalSlot).Type, c)
}
} else {
if dstReg {
e.s.lateSpillUse(vid)
x = e.p.NewValue1(line, OpLoadReg, c.Type, c)
x = e.p.NewValue1(pos, OpLoadReg, c.Type, c)
} else {
// mem->mem. Use temp register.
@ -2123,13 +2124,13 @@ func (e *edgeState) processDest(loc Location, vid ID, splice **Value, line int32
r := e.findRegFor(c.Type)
e.s.lateSpillUse(vid)
t := e.p.NewValue1(line, OpLoadReg, c.Type, c)
e.set(r, vid, t, false, line)
x = e.p.NewValue1(line, OpStoreReg, loc.(LocalSlot).Type, t)
t := e.p.NewValue1(pos, OpLoadReg, c.Type, c)
e.set(r, vid, t, false, pos)
x = e.p.NewValue1(pos, OpStoreReg, loc.(LocalSlot).Type, t)
}
}
}
e.set(loc, vid, x, true, line)
e.set(loc, vid, x, true, pos)
if splice != nil {
(*splice).Uses--
*splice = x
@ -2139,10 +2140,10 @@ func (e *edgeState) processDest(loc Location, vid ID, splice **Value, line int32
}
// set changes the contents of location loc to hold the given value and its cached representative.
func (e *edgeState) set(loc Location, vid ID, c *Value, final bool, line int32) {
func (e *edgeState) set(loc Location, vid ID, c *Value, final bool, pos src.XPos) {
e.s.f.setHome(c, loc)
e.erase(loc)
e.contents[loc] = contentRecord{vid, c, final, line}
e.contents[loc] = contentRecord{vid, c, final, pos}
a := e.cache[vid]
if len(a) == 0 {
e.cachedVals = append(e.cachedVals, vid)
@ -2181,7 +2182,7 @@ func (e *edgeState) erase(loc Location) {
// Add a destination to move this value back into place.
// Make sure it gets added to the tail of the destination queue
// so we make progress on other moves first.
e.extra = append(e.extra, dstRecord{loc, cr.vid, nil, cr.line})
e.extra = append(e.extra, dstRecord{loc, cr.vid, nil, cr.pos})
}
// Remove c from the list of cached values.
@ -2250,8 +2251,8 @@ func (e *edgeState) findRegFor(typ Type) Location {
a := e.cache[vid]
for _, c := range a {
if r, ok := e.s.f.getHome(c.ID).(*Register); ok && m>>uint(r.num)&1 != 0 {
x := e.p.NewValue1(c.Line, OpStoreReg, c.Type, c)
e.set(t, vid, x, false, c.Line)
x := e.p.NewValue1(c.Pos, OpStoreReg, c.Type, c)
e.set(t, vid, x, false, c.Pos)
if e.s.f.pass.debug > regDebug {
fmt.Printf(" SPILL %s->%s %s\n", r.Name(), t.Name(), x.LongString())
}
@ -2290,9 +2291,9 @@ func (v *Value) rematerializeable() bool {
}
type liveInfo struct {
ID ID // ID of value
dist int32 // # of instructions before next use
line int32 // line number of next use
ID ID // ID of value
dist int32 // # of instructions before next use
pos src.XPos // source position of next use
}
// dblock contains information about desired & avoid registers at the end of a block.
@ -2341,12 +2342,12 @@ func (s *regAllocState) computeLive() {
// to beginning-of-block distance.
live.clear()
for _, e := range s.live[b.ID] {
live.set(e.ID, e.dist+int32(len(b.Values)), e.line)
live.set(e.ID, e.dist+int32(len(b.Values)), e.pos)
}
// Mark control value as live
if b.Control != nil && s.values[b.Control.ID].needReg {
live.set(b.Control.ID, int32(len(b.Values)), b.Line)
live.set(b.Control.ID, int32(len(b.Values)), b.Pos)
}
// Propagate backwards to the start of the block
@ -2368,7 +2369,7 @@ func (s *regAllocState) computeLive() {
}
for _, a := range v.Args {
if s.values[a.ID].needReg {
live.set(a.ID, int32(i), v.Line)
live.set(a.ID, int32(i), v.Pos)
}
}
}
@ -2427,7 +2428,7 @@ func (s *regAllocState) computeLive() {
// Start t off with the previously known live values at the end of p.
t.clear()
for _, e := range s.live[p.ID] {
t.set(e.ID, e.dist, e.line)
t.set(e.ID, e.dist, e.pos)
}
update := false
@ -2446,7 +2447,7 @@ func (s *regAllocState) computeLive() {
id := v.Args[i].ID
if s.values[id].needReg && (!t.contains(id) || delta < t.get(id)) {
update = true
t.set(id, delta, v.Line)
t.set(id, delta, v.Pos)
}
}

View file

@ -489,7 +489,7 @@ func noteRule(s string) bool {
// cond is true and the rule is fired.
func warnRule(cond bool, v *Value, s string) bool {
if cond {
v.Block.Func.Config.Warnl(v.Line, s)
v.Block.Func.Config.Warnl(v.Pos, s)
}
return true
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -123,12 +123,12 @@ func rewriteValuedec_OpLoad(v *Value, config *Config) bool {
break
}
v.reset(OpComplexMake)
v0 := b.NewValue0(v.Line, OpLoad, config.fe.TypeFloat32())
v0 := b.NewValue0(v.Pos, OpLoad, config.fe.TypeFloat32())
v0.AddArg(ptr)
v0.AddArg(mem)
v.AddArg(v0)
v1 := b.NewValue0(v.Line, OpLoad, config.fe.TypeFloat32())
v2 := b.NewValue0(v.Line, OpOffPtr, config.fe.TypeFloat32().PtrTo())
v1 := b.NewValue0(v.Pos, OpLoad, config.fe.TypeFloat32())
v2 := b.NewValue0(v.Pos, OpOffPtr, config.fe.TypeFloat32().PtrTo())
v2.AuxInt = 4
v2.AddArg(ptr)
v1.AddArg(v2)
@ -147,12 +147,12 @@ func rewriteValuedec_OpLoad(v *Value, config *Config) bool {
break
}
v.reset(OpComplexMake)
v0 := b.NewValue0(v.Line, OpLoad, config.fe.TypeFloat64())
v0 := b.NewValue0(v.Pos, OpLoad, config.fe.TypeFloat64())
v0.AddArg(ptr)
v0.AddArg(mem)
v.AddArg(v0)
v1 := b.NewValue0(v.Line, OpLoad, config.fe.TypeFloat64())
v2 := b.NewValue0(v.Line, OpOffPtr, config.fe.TypeFloat64().PtrTo())
v1 := b.NewValue0(v.Pos, OpLoad, config.fe.TypeFloat64())
v2 := b.NewValue0(v.Pos, OpOffPtr, config.fe.TypeFloat64().PtrTo())
v2.AuxInt = 8
v2.AddArg(ptr)
v1.AddArg(v2)
@ -171,12 +171,12 @@ func rewriteValuedec_OpLoad(v *Value, config *Config) bool {
break
}
v.reset(OpStringMake)
v0 := b.NewValue0(v.Line, OpLoad, config.fe.TypeBytePtr())
v0 := b.NewValue0(v.Pos, OpLoad, config.fe.TypeBytePtr())
v0.AddArg(ptr)
v0.AddArg(mem)
v.AddArg(v0)
v1 := b.NewValue0(v.Line, OpLoad, config.fe.TypeInt())
v2 := b.NewValue0(v.Line, OpOffPtr, config.fe.TypeInt().PtrTo())
v1 := b.NewValue0(v.Pos, OpLoad, config.fe.TypeInt())
v2 := b.NewValue0(v.Pos, OpOffPtr, config.fe.TypeInt().PtrTo())
v2.AuxInt = config.PtrSize
v2.AddArg(ptr)
v1.AddArg(v2)
@ -195,19 +195,19 @@ func rewriteValuedec_OpLoad(v *Value, config *Config) bool {
break
}
v.reset(OpSliceMake)
v0 := b.NewValue0(v.Line, OpLoad, t.ElemType().PtrTo())
v0 := b.NewValue0(v.Pos, OpLoad, t.ElemType().PtrTo())
v0.AddArg(ptr)
v0.AddArg(mem)
v.AddArg(v0)
v1 := b.NewValue0(v.Line, OpLoad, config.fe.TypeInt())
v2 := b.NewValue0(v.Line, OpOffPtr, config.fe.TypeInt().PtrTo())
v1 := b.NewValue0(v.Pos, OpLoad, config.fe.TypeInt())
v2 := b.NewValue0(v.Pos, OpOffPtr, config.fe.TypeInt().PtrTo())
v2.AuxInt = config.PtrSize
v2.AddArg(ptr)
v1.AddArg(v2)
v1.AddArg(mem)
v.AddArg(v1)
v3 := b.NewValue0(v.Line, OpLoad, config.fe.TypeInt())
v4 := b.NewValue0(v.Line, OpOffPtr, config.fe.TypeInt().PtrTo())
v3 := b.NewValue0(v.Pos, OpLoad, config.fe.TypeInt())
v4 := b.NewValue0(v.Pos, OpOffPtr, config.fe.TypeInt().PtrTo())
v4.AuxInt = 2 * config.PtrSize
v4.AddArg(ptr)
v3.AddArg(v4)
@ -226,12 +226,12 @@ func rewriteValuedec_OpLoad(v *Value, config *Config) bool {
break
}
v.reset(OpIMake)
v0 := b.NewValue0(v.Line, OpLoad, config.fe.TypeBytePtr())
v0 := b.NewValue0(v.Pos, OpLoad, config.fe.TypeBytePtr())
v0.AddArg(ptr)
v0.AddArg(mem)
v.AddArg(v0)
v1 := b.NewValue0(v.Line, OpLoad, config.fe.TypeBytePtr())
v2 := b.NewValue0(v.Line, OpOffPtr, config.fe.TypeBytePtr().PtrTo())
v1 := b.NewValue0(v.Pos, OpLoad, config.fe.TypeBytePtr())
v2 := b.NewValue0(v.Pos, OpOffPtr, config.fe.TypeBytePtr().PtrTo())
v2.AuxInt = config.PtrSize
v2.AddArg(ptr)
v1.AddArg(v2)
@ -318,12 +318,12 @@ func rewriteValuedec_OpStore(v *Value, config *Config) bool {
mem := v.Args[2]
v.reset(OpStore)
v.AuxInt = 4
v0 := b.NewValue0(v.Line, OpOffPtr, config.fe.TypeFloat32().PtrTo())
v0 := b.NewValue0(v.Pos, OpOffPtr, config.fe.TypeFloat32().PtrTo())
v0.AuxInt = 4
v0.AddArg(dst)
v.AddArg(v0)
v.AddArg(imag)
v1 := b.NewValue0(v.Line, OpStore, TypeMem)
v1 := b.NewValue0(v.Pos, OpStore, TypeMem)
v1.AuxInt = 4
v1.AddArg(dst)
v1.AddArg(real)
@ -348,12 +348,12 @@ func rewriteValuedec_OpStore(v *Value, config *Config) bool {
mem := v.Args[2]
v.reset(OpStore)
v.AuxInt = 8
v0 := b.NewValue0(v.Line, OpOffPtr, config.fe.TypeFloat64().PtrTo())
v0 := b.NewValue0(v.Pos, OpOffPtr, config.fe.TypeFloat64().PtrTo())
v0.AuxInt = 8
v0.AddArg(dst)
v.AddArg(v0)
v.AddArg(imag)
v1 := b.NewValue0(v.Line, OpStore, TypeMem)
v1 := b.NewValue0(v.Pos, OpStore, TypeMem)
v1.AuxInt = 8
v1.AddArg(dst)
v1.AddArg(real)
@ -378,12 +378,12 @@ func rewriteValuedec_OpStore(v *Value, config *Config) bool {
mem := v.Args[2]
v.reset(OpStore)
v.AuxInt = config.PtrSize
v0 := b.NewValue0(v.Line, OpOffPtr, config.fe.TypeInt().PtrTo())
v0 := b.NewValue0(v.Pos, OpOffPtr, config.fe.TypeInt().PtrTo())
v0.AuxInt = config.PtrSize
v0.AddArg(dst)
v.AddArg(v0)
v.AddArg(len)
v1 := b.NewValue0(v.Line, OpStore, TypeMem)
v1 := b.NewValue0(v.Pos, OpStore, TypeMem)
v1.AuxInt = config.PtrSize
v1.AddArg(dst)
v1.AddArg(ptr)
@ -409,19 +409,19 @@ func rewriteValuedec_OpStore(v *Value, config *Config) bool {
mem := v.Args[2]
v.reset(OpStore)
v.AuxInt = config.PtrSize
v0 := b.NewValue0(v.Line, OpOffPtr, config.fe.TypeInt().PtrTo())
v0 := b.NewValue0(v.Pos, OpOffPtr, config.fe.TypeInt().PtrTo())
v0.AuxInt = 2 * config.PtrSize
v0.AddArg(dst)
v.AddArg(v0)
v.AddArg(cap)
v1 := b.NewValue0(v.Line, OpStore, TypeMem)
v1 := b.NewValue0(v.Pos, OpStore, TypeMem)
v1.AuxInt = config.PtrSize
v2 := b.NewValue0(v.Line, OpOffPtr, config.fe.TypeInt().PtrTo())
v2 := b.NewValue0(v.Pos, OpOffPtr, config.fe.TypeInt().PtrTo())
v2.AuxInt = config.PtrSize
v2.AddArg(dst)
v1.AddArg(v2)
v1.AddArg(len)
v3 := b.NewValue0(v.Line, OpStore, TypeMem)
v3 := b.NewValue0(v.Pos, OpStore, TypeMem)
v3.AuxInt = config.PtrSize
v3.AddArg(dst)
v3.AddArg(ptr)
@ -447,12 +447,12 @@ func rewriteValuedec_OpStore(v *Value, config *Config) bool {
mem := v.Args[2]
v.reset(OpStore)
v.AuxInt = config.PtrSize
v0 := b.NewValue0(v.Line, OpOffPtr, config.fe.TypeBytePtr().PtrTo())
v0 := b.NewValue0(v.Pos, OpOffPtr, config.fe.TypeBytePtr().PtrTo())
v0.AuxInt = config.PtrSize
v0.AddArg(dst)
v.AddArg(v0)
v.AddArg(data)
v1 := b.NewValue0(v.Line, OpStore, TypeMem)
v1 := b.NewValue0(v.Pos, OpStore, TypeMem)
v1.AuxInt = config.PtrSize
v1.AddArg(dst)
v1.AddArg(itab)

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -46,8 +46,8 @@ func (h ValHeap) Less(i, j int) bool {
if c := sx - sy; c != 0 {
return c > 0 // higher score comes later.
}
if x.Line != y.Line { // Favor in-order line stepping
return x.Line > y.Line
if x.Pos != y.Pos { // Favor in-order line stepping
return x.Pos.After(y.Pos)
}
if x.Op != OpPhi {
if c := len(x.Args) - len(y.Args); c != 0 {

View file

@ -17,8 +17,8 @@ func shortcircuit(f *Func) {
// x = phi(a, ...)
//
// We can replace the "a" in the phi with the constant true.
ct := f.ConstBool(f.Entry.Line, f.Config.fe.TypeBool(), true)
cf := f.ConstBool(f.Entry.Line, f.Config.fe.TypeBool(), false)
ct := f.ConstBool(f.Entry.Pos, f.Config.fe.TypeBool(), true)
cf := f.ConstBool(f.Entry.Pos, f.Config.fe.TypeBool(), false)
for _, b := range f.Blocks {
for _, v := range b.Values {
if v.Op != OpPhi {

View file

@ -22,8 +22,8 @@ func TestSizeof(t *testing.T) {
_32bit uintptr // size on 32bit platforms
_64bit uintptr // size on 64bit platforms
}{
{Value{}, 68, 112},
{Block{}, 148, 288},
{Value{}, 72, 120},
{Block{}, 152, 288},
}
for _, tt := range tests {

View file

@ -4,13 +4,15 @@
package ssa
import "cmd/internal/src"
// from http://research.swtch.com/sparse
// in turn, from Briggs and Torczon
type sparseEntry struct {
key ID
val int32
aux int32
aux src.XPos
}
type sparseMap struct {
@ -43,7 +45,7 @@ func (s *sparseMap) get(k ID) int32 {
return -1
}
func (s *sparseMap) set(k ID, v, a int32) {
func (s *sparseMap) set(k ID, v int32, a src.XPos) {
i := s.sparse[k]
if i < int32(len(s.dense)) && s.dense[i].key == k {
s.dense[i].val = v
@ -64,7 +66,7 @@ func (s *sparseMap) setBit(k ID, v uint) {
s.dense[i].val |= 1 << v
return
}
s.dense = append(s.dense, sparseEntry{k, 1 << v, 0})
s.dense = append(s.dense, sparseEntry{k, 1 << v, src.NoXPos})
s.sparse[k] = int32(len(s.dense)) - 1
}

View file

@ -6,7 +6,10 @@
package ssa
import "fmt"
import (
"cmd/internal/src"
"fmt"
)
type stackAllocState struct {
f *Func
@ -37,7 +40,7 @@ func newStackAllocState(f *Func) *stackAllocState {
return new(stackAllocState)
}
if s.f != nil {
f.Config.Fatalf(0, "newStackAllocState called without previous free")
f.Config.Fatalf(src.NoXPos, "newStackAllocState called without previous free")
}
return s
}

View file

@ -5,6 +5,7 @@
package ssa
import (
"cmd/internal/src"
"fmt"
"math"
)
@ -36,8 +37,8 @@ type Value struct {
// Containing basic block
Block *Block
// Source line number
Line int32
// Source position
Pos src.XPos
// Use count. Each appearance in Value.Args and Block.Control counts once.
Uses int32
@ -217,7 +218,7 @@ func (v *Value) reset(op Op) {
// copyInto makes a new value identical to v and adds it to the end of b.
func (v *Value) copyInto(b *Block) *Value {
c := b.NewValue0(v.Line, v.Op, v.Type)
c := b.NewValue0(v.Pos, v.Op, v.Type)
c.Aux = v.Aux
c.AuxInt = v.AuxInt
c.AddArgs(v.Args...)
@ -232,7 +233,7 @@ func (v *Value) copyInto(b *Block) *Value {
func (v *Value) Logf(msg string, args ...interface{}) { v.Block.Logf(msg, args...) }
func (v *Value) Log() bool { return v.Block.Log() }
func (v *Value) Fatalf(msg string, args ...interface{}) {
v.Block.Func.Config.Fatalf(v.Line, msg, args...)
v.Block.Func.Config.Fatalf(v.Pos, msg, args...)
}
// isGenericIntConst returns whether v is a generic integer constant.

View file

@ -4,7 +4,10 @@
package ssa
import "fmt"
import (
"cmd/internal/src"
"fmt"
)
// writebarrier expands write barrier ops (StoreWB, MoveWB, etc.) into
// branches and runtime calls, like
@ -53,7 +56,7 @@ func writebarrier(f *Func) {
if wbaddr == nil {
// initalize global values for write barrier test and calls
// find SB and SP values in entry block
initln := f.Entry.Line
initln := f.Entry.Pos
for _, v := range f.Entry.Values {
if v.Op == OpSB {
sb = v
@ -78,7 +81,7 @@ func writebarrier(f *Func) {
defer f.retSparseSet(wbs)
}
line := v.Line
pos := v.Pos
// there may be a sequence of WB stores in the current block. find them.
storeWBs = storeWBs[:0]
@ -124,9 +127,9 @@ func writebarrier(f *Func) {
bThen := f.NewBlock(BlockPlain)
bElse := f.NewBlock(BlockPlain)
bEnd := f.NewBlock(b.Kind)
bThen.Line = line
bElse.Line = line
bEnd.Line = line
bThen.Pos = pos
bElse.Pos = pos
bEnd.Pos = pos
// set up control flow for end block
bEnd.SetControl(b.Control)
@ -138,9 +141,9 @@ func writebarrier(f *Func) {
// set up control flow for write barrier test
// load word, test word, avoiding partial register write from load byte.
flag := b.NewValue2(line, OpLoad, f.Config.fe.TypeUInt32(), wbaddr, mem)
const0 := f.ConstInt32(line, f.Config.fe.TypeUInt32(), 0)
flag = b.NewValue2(line, OpNeq32, f.Config.fe.TypeBool(), flag, const0)
flag := b.NewValue2(pos, OpLoad, f.Config.fe.TypeUInt32(), wbaddr, mem)
const0 := f.ConstInt32(pos, f.Config.fe.TypeUInt32(), 0)
flag = b.NewValue2(pos, OpNeq32, f.Config.fe.TypeBool(), flag, const0)
b.Kind = BlockIf
b.SetControl(flag)
b.Likely = BranchUnlikely
@ -175,13 +178,13 @@ func writebarrier(f *Func) {
}
// then block: emit write barrier call
memThen = wbcall(line, bThen, fn, typ, ptr, val, memThen, sp, sb, w.Op == OpMoveWBVolatile)
memThen = wbcall(pos, bThen, fn, typ, ptr, val, memThen, sp, sb, w.Op == OpMoveWBVolatile)
// else block: normal store
if op == OpZero {
memElse = bElse.NewValue2I(line, op, TypeMem, siz, ptr, memElse)
memElse = bElse.NewValue2I(pos, op, TypeMem, siz, ptr, memElse)
} else {
memElse = bElse.NewValue3I(line, op, TypeMem, siz, ptr, val, memElse)
memElse = bElse.NewValue3I(pos, op, TypeMem, siz, ptr, val, memElse)
}
}
@ -226,7 +229,7 @@ func writebarrier(f *Func) {
}
if f.Config.fe.Debug_wb() {
f.Config.Warnl(line, "write barrier")
f.Config.Warnl(pos, "write barrier")
}
break valueLoop
@ -237,7 +240,7 @@ func writebarrier(f *Func) {
// wbcall emits write barrier runtime call in b, returns memory.
// if valIsVolatile, it moves val into temp space before making the call.
func wbcall(line int32, b *Block, fn interface{}, typ interface{}, ptr, val, mem, sp, sb *Value, valIsVolatile bool) *Value {
func wbcall(pos src.XPos, b *Block, fn interface{}, typ interface{}, ptr, val, mem, sp, sb *Value, valIsVolatile bool) *Value {
config := b.Func.Config
var tmp GCNode
@ -248,10 +251,10 @@ func wbcall(line int32, b *Block, fn interface{}, typ interface{}, ptr, val, mem
t := val.Type.ElemType()
tmp = config.fe.Auto(t)
aux := &AutoSymbol{Typ: t, Node: tmp}
mem = b.NewValue1A(line, OpVarDef, TypeMem, tmp, mem)
tmpaddr := b.NewValue1A(line, OpAddr, t.PtrTo(), aux, sp)
mem = b.NewValue1A(pos, OpVarDef, TypeMem, tmp, mem)
tmpaddr := b.NewValue1A(pos, OpAddr, t.PtrTo(), aux, sp)
siz := MakeSizeAndAlign(t.Size(), t.Alignment()).Int64()
mem = b.NewValue3I(line, OpMove, TypeMem, siz, tmpaddr, val, mem)
mem = b.NewValue3I(pos, OpMove, TypeMem, siz, tmpaddr, val, mem)
val = tmpaddr
}
@ -259,32 +262,32 @@ func wbcall(line int32, b *Block, fn interface{}, typ interface{}, ptr, val, mem
off := config.ctxt.FixedFrameSize()
if typ != nil { // for typedmemmove
taddr := b.NewValue1A(line, OpAddr, config.fe.TypeUintptr(), typ, sb)
taddr := b.NewValue1A(pos, OpAddr, config.fe.TypeUintptr(), typ, sb)
off = round(off, taddr.Type.Alignment())
arg := b.NewValue1I(line, OpOffPtr, taddr.Type.PtrTo(), off, sp)
mem = b.NewValue3I(line, OpStore, TypeMem, ptr.Type.Size(), arg, taddr, mem)
arg := b.NewValue1I(pos, OpOffPtr, taddr.Type.PtrTo(), off, sp)
mem = b.NewValue3I(pos, OpStore, TypeMem, ptr.Type.Size(), arg, taddr, mem)
off += taddr.Type.Size()
}
off = round(off, ptr.Type.Alignment())
arg := b.NewValue1I(line, OpOffPtr, ptr.Type.PtrTo(), off, sp)
mem = b.NewValue3I(line, OpStore, TypeMem, ptr.Type.Size(), arg, ptr, mem)
arg := b.NewValue1I(pos, OpOffPtr, ptr.Type.PtrTo(), off, sp)
mem = b.NewValue3I(pos, OpStore, TypeMem, ptr.Type.Size(), arg, ptr, mem)
off += ptr.Type.Size()
if val != nil {
off = round(off, val.Type.Alignment())
arg = b.NewValue1I(line, OpOffPtr, val.Type.PtrTo(), off, sp)
mem = b.NewValue3I(line, OpStore, TypeMem, val.Type.Size(), arg, val, mem)
arg = b.NewValue1I(pos, OpOffPtr, val.Type.PtrTo(), off, sp)
mem = b.NewValue3I(pos, OpStore, TypeMem, val.Type.Size(), arg, val, mem)
off += val.Type.Size()
}
off = round(off, config.PtrSize)
// issue call
mem = b.NewValue1A(line, OpStaticCall, TypeMem, fn, mem)
mem = b.NewValue1A(pos, OpStaticCall, TypeMem, fn, mem)
mem.AuxInt = off - config.ctxt.FixedFrameSize()
if valIsVolatile {
mem = b.NewValue1A(line, OpVarKill, TypeMem, tmp, mem) // mark temp dead
mem = b.NewValue1A(pos, OpVarKill, TypeMem, tmp, mem) // mark temp dead
}
return mem

View file

@ -14,7 +14,7 @@ func TestDump(t *testing.T) {
t.Skip("skipping test in short mode")
}
ast, err := ParseFile(*src, nil, nil, 0)
ast, err := ParseFile(*src_, nil, nil, 0)
if err != nil {
t.Fatal(err)
}

View file

@ -4,11 +4,13 @@
package syntax
import "cmd/internal/src"
// ----------------------------------------------------------------------------
// Nodes
type Node interface {
Line() uint32
Pos() src.Pos
aNode()
init(p *parser)
}
@ -16,19 +18,18 @@ type Node interface {
type node struct {
// commented out for now since not yet used
// doc *Comment // nil means no comment(s) attached
pos uint32
line uint32
pos src.Pos
}
func (n *node) Pos() src.Pos {
return n.pos
}
func (*node) aNode() {}
func (n *node) Line() uint32 {
return n.line
}
// TODO(gri) we may be able to get rid of init here and in Node
func (n *node) init(p *parser) {
n.pos = uint32(p.pos)
n.line = uint32(p.line)
n.pos = p.pos()
}
// ----------------------------------------------------------------------------
@ -38,7 +39,7 @@ func (n *node) init(p *parser) {
type File struct {
PkgName *Name
DeclList []Decl
Lines int
Lines uint
node
}
@ -103,7 +104,7 @@ type (
Type *FuncType
Body []Stmt // nil means no body (forward declaration)
Pragma Pragma // TODO(mdempsky): Cleaner solution.
EndLine uint32 // TODO(mdempsky): Cleaner solution.
EndLine uint // TODO(mdempsky): Cleaner solution.
decl
}
)
@ -143,8 +144,8 @@ type (
CompositeLit struct {
Type Expr // nil means no literal type
ElemList []Expr
NKeys int // number of elements with keys
EndLine uint32 // TODO(mdempsky): Cleaner solution.
NKeys int // number of elements with keys
EndLine uint // TODO(mdempsky): Cleaner solution.
expr
}
@ -158,7 +159,7 @@ type (
FuncLit struct {
Type *FuncType
Body []Stmt
EndLine uint32 // TODO(mdempsky): Cleaner solution.
EndLine uint // TODO(mdempsky): Cleaner solution.
expr
}

View file

@ -5,8 +5,10 @@
package syntax
import (
"cmd/internal/src"
"fmt"
"io"
"strconv"
"strings"
)
@ -19,21 +21,67 @@ const trace = false
const gcCompat = true
type parser struct {
base *src.PosBase
errh ErrorHandler
scanner
first error // first error encountered
pragma Pragma // pragma flags
fnest int // function nesting level (for error handling)
xnest int // expression nesting level (for complit ambiguity resolution)
indent []byte // tracing support
}
func (p *parser) init(src io.Reader, errh ErrorHandler, pragh PragmaHandler) {
p.scanner.init(src, errh, pragh)
func (p *parser) init(base *src.PosBase, r io.Reader, errh ErrorHandler, pragh PragmaHandler) {
p.base = base
p.errh = errh
p.scanner.init(
r,
// Error and pragma handlers for scanner.
// Because the (line, col) positions passed to these
// handlers are always at or after the current reading
// position, it is save to use the most recent position
// base to compute the corresponding Pos value.
func(line, col uint, msg string) {
p.error_at(p.pos_at(line, col), msg)
},
func(line, col uint, text string) {
if strings.HasPrefix(text, "line ") {
p.updateBase(line, col+5, text[5:])
return
}
if pragh != nil {
p.pragma |= pragh(p.pos_at(line, col), text)
}
},
)
p.first = nil
p.pragma = 0
p.fnest = 0
p.xnest = 0
p.indent = nil
}
const lineMax = 1<<24 - 1 // TODO(gri) this limit is defined for src.Pos - fix
func (p *parser) updateBase(line, col uint, text string) {
// Want to use LastIndexByte below but it's not defined in Go1.4 and bootstrap fails.
i := strings.LastIndex(text, ":") // look from right (Windows filenames may contain ':')
if i < 0 {
return // ignore (not a line directive)
}
nstr := text[i+1:]
n, err := strconv.Atoi(nstr)
if err != nil || n <= 0 || n > lineMax {
p.error_at(p.pos_at(line, col+uint(i+1)), "invalid line number: "+nstr)
return
}
p.base = src.NewLinePragmaBase(src.MakePos(p.base.Pos().Base(), line, col), text[:i], uint(n))
}
func (p *parser) got(tok token) bool {
if p.tok == tok {
p.next()
@ -52,13 +100,25 @@ func (p *parser) want(tok token) {
// ----------------------------------------------------------------------------
// Error handling
// syntax_error reports a syntax error at the current line.
func (p *parser) syntax_error(msg string) {
p.syntax_error_at(p.pos, p.line, msg)
// pos_at returns the Pos value for (line, col) and the current position base.
func (p *parser) pos_at(line, col uint) src.Pos {
return src.MakePos(p.base, line, col)
}
// Like syntax_error, but reports error at given line rather than current lexer line.
func (p *parser) syntax_error_at(pos, line int, msg string) {
// error reports an error at the given position.
func (p *parser) error_at(pos src.Pos, msg string) {
err := Error{pos, msg}
if p.first == nil {
p.first = err
}
if p.errh == nil {
panic(p.first)
}
p.errh(err)
}
// syntax_error_at reports a syntax error at the given position.
func (p *parser) syntax_error_at(pos src.Pos, msg string) {
if trace {
defer p.trace("syntax_error (" + msg + ")")()
}
@ -77,7 +137,7 @@ func (p *parser) syntax_error_at(pos, line int, msg string) {
msg = ", " + msg
default:
// plain error - we don't care about current token
p.error_at(pos, line, "syntax error: "+msg)
p.error_at(pos, "syntax error: "+msg)
return
}
@ -99,9 +159,14 @@ func (p *parser) syntax_error_at(pos, line int, msg string) {
tok = tokstring(p.tok)
}
p.error_at(pos, line, "syntax error: unexpected "+tok+msg)
p.error_at(pos, "syntax error: unexpected "+tok+msg)
}
// Convenience methods using the current token position.
func (p *parser) pos() src.Pos { return p.pos_at(p.line, p.col) }
func (p *parser) error(msg string) { p.error_at(p.pos(), msg) }
func (p *parser) syntax_error(msg string) { p.syntax_error_at(p.pos(), msg) }
// The stopset contains keywords that start a statement.
// They are good synchronization points in case of syntax
// errors and (usually) shouldn't be skipped over.
@ -429,7 +494,7 @@ func (p *parser) funcDecl() *FuncDecl {
f.Body = p.funcBody()
f.Pragma = p.pragma
f.EndLine = uint32(p.line)
f.EndLine = p.line
// TODO(gri) deal with function properties
// if noescape && body != nil {
@ -652,7 +717,7 @@ func (p *parser) operand(keep_parens bool) Expr {
f.init(p)
f.Type = t
f.Body = p.funcBody()
f.EndLine = uint32(p.line)
f.EndLine = p.line
p.xnest--
p.fnest--
return f
@ -873,7 +938,7 @@ func (p *parser) complitexpr() *CompositeLit {
}
}
x.EndLine = uint32(p.line)
x.EndLine = p.line
p.xnest--
p.want(_Rbrace)
@ -1198,7 +1263,7 @@ func (p *parser) fieldDecl(styp *StructType) {
p.want(_Rparen)
tag := p.oliteral()
p.addField(styp, nil, typ, tag)
p.error("cannot parenthesize embedded type")
p.syntax_error("cannot parenthesize embedded type")
} else {
// '(' embed ')' oliteral
@ -1206,7 +1271,7 @@ func (p *parser) fieldDecl(styp *StructType) {
p.want(_Rparen)
tag := p.oliteral()
p.addField(styp, nil, typ, tag)
p.error("cannot parenthesize embedded type")
p.syntax_error("cannot parenthesize embedded type")
}
case _Star:
@ -1217,7 +1282,7 @@ func (p *parser) fieldDecl(styp *StructType) {
p.want(_Rparen)
tag := p.oliteral()
p.addField(styp, nil, typ, tag)
p.error("cannot parenthesize embedded type")
p.syntax_error("cannot parenthesize embedded type")
} else {
// '*' embed oliteral
@ -1285,7 +1350,7 @@ func (p *parser) methodDecl() *Field {
f.init(p)
f.Type = p.qualifiedName(nil)
p.want(_Rparen)
p.error("cannot parenthesize embedded type")
p.syntax_error("cannot parenthesize embedded type")
return f
default:
@ -1352,7 +1417,7 @@ func (p *parser) dotsType() *DotsType {
p.want(_DotDotDot)
t.Elem = p.tryType()
if t.Elem == nil {
p.error("final argument in variadic function missing type")
p.syntax_error("final argument in variadic function missing type")
}
return t
@ -1563,7 +1628,7 @@ func (p *parser) labeledStmt(label *Name) Stmt {
s.Stmt = p.stmt()
if s.Stmt == missing_stmt {
// report error at line of ':' token
p.syntax_error_at(int(label.pos), int(label.line), "missing statement after label")
p.syntax_error_at(label.Pos(), "missing statement after label")
// we are already at the end of the labeled statement - no need to advance
return missing_stmt
}
@ -1646,7 +1711,7 @@ func (p *parser) header(forStmt bool) (init SimpleStmt, cond Expr, post SimpleSt
if p.tok != _Semi {
// accept potential varDecl but complain
if forStmt && p.got(_Var) {
p.error("var declaration not allowed in for initializer")
p.syntax_error("var declaration not allowed in for initializer")
}
init = p.simpleStmt(nil, forStmt)
// If we have a range clause, we are done.
@ -1699,7 +1764,7 @@ func (p *parser) ifStmt() *IfStmt {
p.want(_If)
s.Init, s.Cond, _ = p.header(false)
if s.Cond == nil {
p.error("missing condition in if statement")
p.syntax_error("missing condition in if statement")
}
if gcCompat {
@ -1715,7 +1780,7 @@ func (p *parser) ifStmt() *IfStmt {
case _Lbrace:
s.Else = p.blockStmt()
default:
p.error("else must be followed by if or statement block")
p.syntax_error("else must be followed by if or statement block")
p.advance(_Name, _Rbrace)
}
}
@ -2088,7 +2153,7 @@ func (p *parser) exprList() Expr {
list = append(list, p.expr())
}
t := new(ListExpr)
t.init(p) // TODO(gri) what is the correct thing here?
t.pos = x.Pos()
t.ElemList = list
x = t
}

View file

@ -6,6 +6,7 @@ package syntax
import (
"bytes"
"cmd/internal/src"
"flag"
"fmt"
"io/ioutil"
@ -18,11 +19,11 @@ import (
)
var fast = flag.Bool("fast", false, "parse package files in parallel")
var src = flag.String("src", "parser.go", "source file to parse")
var src_ = flag.String("src", "parser.go", "source file to parse")
var verify = flag.Bool("verify", false, "verify idempotent printing")
func TestParse(t *testing.T) {
_, err := ParseFile(*src, nil, nil, 0)
_, err := ParseFile(*src_, nil, nil, 0)
if err != nil {
t.Fatal(err)
}
@ -39,7 +40,7 @@ func TestStdLib(t *testing.T) {
type parseResult struct {
filename string
lines int
lines uint
}
results := make(chan parseResult)
@ -65,7 +66,7 @@ func TestStdLib(t *testing.T) {
}
}()
var count, lines int
var count, lines uint
for res := range results {
count++
lines += res.lines
@ -133,7 +134,7 @@ func verifyPrint(filename string, ast1 *File) {
panic(err)
}
ast2, err := ParseBytes(buf1.Bytes(), nil, nil, 0)
ast2, err := ParseBytes(src.NewFileBase(filename, filename), buf1.Bytes(), nil, nil, 0)
if err != nil {
panic(err)
}
@ -157,7 +158,7 @@ func verifyPrint(filename string, ast1 *File) {
}
func TestIssue17697(t *testing.T) {
_, err := ParseBytes(nil, nil, nil, 0) // return with parser error, don't panic
_, err := ParseBytes(nil, nil, nil, nil, 0) // return with parser error, don't panic
if err == nil {
t.Errorf("no error reported")
}
@ -182,3 +183,47 @@ func TestParseFile(t *testing.T) {
t.Errorf("got %v; want first error %v", err, first)
}
}
func TestLineDirectives(t *testing.T) {
for _, test := range []struct {
src, msg string
filename string
line, col uint
}{
// test validity of //line directive
{`//line :`, "invalid line number: ", "", 1, 8},
{`//line :x`, "invalid line number: x", "", 1, 8},
{`//line foo :`, "invalid line number: ", "", 1, 12},
{`//line foo:123abc`, "invalid line number: 123abc", "", 1, 11},
{`/**///line foo:x`, "invalid line number: x", "", 1, 15},
{`//line foo:0`, "invalid line number: 0", "", 1, 11},
{fmt.Sprintf(`//line foo:%d`, lineMax+1), fmt.Sprintf("invalid line number: %d", lineMax+1), "", 1, 11},
// test effect of //line directive on (relative) position information
{"//line foo:123\n foo", "syntax error: package statement must be first", "foo", 123, 3},
{"//line foo:123\n//line bar:345\nfoo", "syntax error: package statement must be first", "bar", 345, 0},
} {
_, err := ParseBytes(nil, []byte(test.src), nil, nil, 0)
if err == nil {
t.Errorf("%s: no error reported", test.src)
continue
}
perr, ok := err.(Error)
if !ok {
t.Errorf("%s: got %v; want parser error", test.src, err)
continue
}
if msg := perr.Msg; msg != test.msg {
t.Errorf("%s: got msg = %q; want %q", test.src, msg, test.msg)
}
if filename := perr.Pos.RelFilename(); filename != test.filename {
t.Errorf("%s: got filename = %q; want %q", test.src, filename, test.filename)
}
if line := perr.Pos.RelLine(); line != test.line {
t.Errorf("%s: got line = %d; want %d", test.src, line, test.line)
}
if col := perr.Pos.Col(); col != test.col {
t.Errorf("%s: got col = %d; want %d", test.src, col, test.col)
}
}
}

View file

@ -15,7 +15,7 @@ func TestPrint(t *testing.T) {
t.Skip("skipping test in short mode")
}
ast, err := ParseFile(*src, nil, nil, 0)
ast, err := ParseFile(*src_, nil, nil, 0)
if err != nil {
t.Fatal(err)
}
@ -29,7 +29,7 @@ func TestPrintString(t *testing.T) {
"package p; type _ = int; type T1 = struct{}; type ( _ = *struct{}; T2 = float32 )",
// TODO(gri) expand
} {
ast, err := ParseBytes([]byte(want), nil, nil, 0)
ast, err := ParseBytes(nil, []byte(want), nil, nil, 0)
if err != nil {
t.Error(err)
continue

View file

@ -2,38 +2,55 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// This file implements scanner, a lexical tokenizer for
// Go source. After initialization, consecutive calls of
// next advance the scanner one token at a time.
//
// This file, source.go, and tokens.go are self-contained
// (go tool compile scanner.go source.go tokens.go compiles)
// and thus could be made into its own package.
package syntax
import (
"fmt"
"io"
"strings"
"unicode"
"unicode/utf8"
)
type scanner struct {
source
pragh func(line, col uint, msg string)
nlsemi bool // if set '\n' and EOF translate to ';'
pragma Pragma
// current token, valid after calling next()
pos, line int
line, col uint
tok token
lit string // valid if tok is _Name or _Literal
kind LitKind // valid if tok is _Literal
op Operator // valid if tok is _Operator, _AssignOp, or _IncOp
prec int // valid if tok is _Operator, _AssignOp, or _IncOp
pragh PragmaHandler
}
func (s *scanner) init(src io.Reader, errh ErrorHandler, pragh PragmaHandler) {
func (s *scanner) init(src io.Reader, errh, pragh func(line, col uint, msg string)) {
s.source.init(src, errh)
s.nlsemi = false
s.pragh = pragh
s.nlsemi = false
}
// next advances the scanner by reading the next token.
//
// If a read, source encoding, or lexical error occurs, next
// calls the error handler installed with init. The handler
// must exist.
//
// If a //line or //go: directive is encountered, next
// calls the pragma handler installed with init, if not nil.
//
// The (line, col) position passed to the error and pragma
// handler is always at or after the current source reading
// position.
func (s *scanner) next() {
nlsemi := s.nlsemi
s.nlsemi = false
@ -46,9 +63,9 @@ redo:
}
// token start
s.pos, s.line = s.source.pos0(), s.source.line0
s.line, s.col = s.source.line0, s.source.col0
if isLetter(c) || c >= utf8.RuneSelf && (unicode.IsLetter(c) || s.isCompatRune(c, true)) {
if isLetter(c) || c >= utf8.RuneSelf && s.isIdentRune(c, true) {
s.ident()
return
}
@ -114,8 +131,7 @@ redo:
case '.':
c = s.getr()
if isDigit(c) {
s.ungetr()
s.source.r0-- // make sure '.' is part of literal (line cannot have changed)
s.ungetr2()
s.number('.')
break
}
@ -125,8 +141,7 @@ redo:
s.tok = _DotDotDot
break
}
s.ungetr()
s.source.r0-- // make next ungetr work (line cannot have changed)
s.ungetr2()
}
s.ungetr()
s.tok = _Dot
@ -273,7 +288,7 @@ redo:
default:
s.tok = 0
s.error(fmt.Sprintf("illegal character %#U", c))
s.error(fmt.Sprintf("invalid character %#U", c))
goto redo
}
@ -307,7 +322,7 @@ func (s *scanner) ident() {
// general case
if c >= utf8.RuneSelf {
for unicode.IsLetter(c) || c == '_' || unicode.IsDigit(c) || s.isCompatRune(c, false) {
for s.isIdentRune(c, false) {
c = s.getr()
}
}
@ -329,14 +344,18 @@ func (s *scanner) ident() {
s.tok = _Name
}
func (s *scanner) isCompatRune(c rune, start bool) bool {
if !gcCompat || c < utf8.RuneSelf {
return false
}
if start && unicode.IsNumber(c) {
s.error(fmt.Sprintf("identifier cannot begin with digit %#U", c))
} else {
func (s *scanner) isIdentRune(c rune, first bool) bool {
switch {
case unicode.IsLetter(c) || c == '_':
// ok
case unicode.IsDigit(c):
if first {
s.error(fmt.Sprintf("identifier cannot begin with digit %#U", c))
}
case c >= utf8.RuneSelf:
s.error(fmt.Sprintf("invalid identifier character %#U", c))
default:
return false
}
return true
}
@ -460,7 +479,7 @@ func (s *scanner) stdString() {
break
}
if r < 0 {
s.error_at(s.pos, s.line, "string not terminated")
s.errh(s.line, s.col, "string not terminated")
break
}
}
@ -480,7 +499,7 @@ func (s *scanner) rawString() {
break
}
if r < 0 {
s.error_at(s.pos, s.line, "string not terminated")
s.errh(s.line, s.col, "string not terminated")
break
}
}
@ -526,48 +545,46 @@ func (s *scanner) rune() {
s.tok = _Literal
}
func (s *scanner) lineComment() {
// recognize pragmas
var prefix string
r := s.getr()
if s.pragh == nil {
goto skip
}
switch r {
case 'g':
prefix = "go:"
case 'l':
prefix = "line "
default:
goto skip
}
s.startLit()
for _, m := range prefix {
if r != m {
s.stopLit()
goto skip
}
r = s.getr()
}
func (s *scanner) skipLine(r rune) {
for r >= 0 {
if r == '\n' {
s.ungetr()
s.ungetr() // don't consume '\n' - needed for nlsemi logic
break
}
r = s.getr()
}
s.pragma |= s.pragh(0, s.line, strings.TrimSuffix(string(s.stopLit()), "\r"))
return
}
skip:
// consume line
for r != '\n' && r >= 0 {
func (s *scanner) lineComment() {
r := s.getr()
if s.pragh == nil || (r != 'g' && r != 'l') {
s.skipLine(r)
return
}
// s.pragh != nil && (r == 'g' || r == 'l')
// recognize pragmas
prefix := "go:"
if r == 'l' {
prefix = "line "
}
for _, m := range prefix {
if r != m {
s.skipLine(r)
return
}
r = s.getr()
}
s.ungetr() // don't consume '\n' - needed for nlsemi logic
// pragma text without line ending (which may be "\r\n" if Windows),
s.startLit()
s.skipLine(r)
text := s.stopLit()
if i := len(text) - 1; i >= 0 && text[i] == '\r' {
text = text[:i]
}
s.pragh(s.line, s.col+2, prefix+string(text)) // +2 since pragma text starts after //
}
func (s *scanner) fullComment() {
@ -580,7 +597,7 @@ func (s *scanner) fullComment() {
}
}
if r < 0 {
s.error_at(s.pos, s.line, "comment not terminated")
s.errh(s.line, s.col, "comment not terminated")
return
}
}
@ -628,19 +645,11 @@ func (s *scanner) escape(quote rune) bool {
if c < 0 {
return true // complain in caller about EOF
}
if gcCompat {
name := "hex"
if base == 8 {
name = "octal"
}
s.error(fmt.Sprintf("non-%s character in escape sequence: %c", name, c))
} else {
if c != quote {
s.error(fmt.Sprintf("illegal character %#U in escape sequence", c))
} else {
s.error("escape sequence incomplete")
}
kind := "hex"
if base == 8 {
kind = "octal"
}
s.error(fmt.Sprintf("non-%s character in escape sequence: %c", kind, c))
s.ungetr()
return false
}

View file

@ -56,7 +56,7 @@ func TestTokens(t *testing.T) {
for i, want := range sampleTokens {
nlsemi := false
if got.line != i+1 {
if got.line != uint(i+1) {
t.Errorf("got line %d; want %d", got.line, i+1)
}
@ -256,88 +256,93 @@ var sampleTokens = [...]struct {
func TestScanErrors(t *testing.T) {
for _, test := range []struct {
src, msg string
pos, line int
line, col uint
}{
// Note: Positions for lexical errors are the earliest position
// where the error is apparent, not the beginning of the respective
// token.
// rune-level errors
{"fo\x00o", "invalid NUL character", 2, 1},
{"foo\n\ufeff bar", "invalid BOM in the middle of the file", 4, 2},
{"foo\n\n\xff ", "invalid UTF-8 encoding", 5, 3},
{"fo\x00o", "invalid NUL character", 1, 2},
{"foo\n\ufeff bar", "invalid BOM in the middle of the file", 2, 0},
{"foo\n\n\xff ", "invalid UTF-8 encoding", 3, 0},
// token-level errors
{"x + ~y", "bitwise complement operator is ^", 4, 1},
{"foo$bar = 0", "illegal character U+0024 '$'", 3, 1},
{"const x = 0xyz", "malformed hex constant", 12, 1},
{"0123456789", "malformed octal constant", 10, 1},
{"0123456789. /* foobar", "comment not terminated", 12, 1}, // valid float constant
{"0123456789e0 /*\nfoobar", "comment not terminated", 13, 1}, // valid float constant
{"var a, b = 08, 07\n", "malformed octal constant", 13, 1},
{"(x + 1.0e+x)", "malformed floating-point constant exponent", 10, 1},
{"\u00BD" /* ½ */, "invalid identifier character U+00BD '½'", 1, 0},
{"\U0001d736\U0001d737\U0001d738_½" /* 𝜶𝜷𝜸_½ */, "invalid identifier character U+00BD '½'", 1, 13 /* byte offset */},
{"\U0001d7d8" /* 𝟘 */, "identifier cannot begin with digit U+1D7D8 '𝟘'", 1, 0},
{"foo\U0001d7d8_½" /* foo𝟘_½ */, "invalid identifier character U+00BD '½'", 1, 8 /* byte offset */},
{"x + ~y", "bitwise complement operator is ^", 1, 4},
{"foo$bar = 0", "invalid character U+0024 '$'", 1, 3},
{"const x = 0xyz", "malformed hex constant", 1, 12},
{"0123456789", "malformed octal constant", 1, 10},
{"0123456789. /* foobar", "comment not terminated", 1, 12}, // valid float constant
{"0123456789e0 /*\nfoobar", "comment not terminated", 1, 13}, // valid float constant
{"var a, b = 08, 07\n", "malformed octal constant", 1, 13},
{"(x + 1.0e+x)", "malformed floating-point constant exponent", 1, 10},
{`''`, "empty character literal or unescaped ' in character literal", 1, 1},
{"'\n", "newline in character literal", 1, 1},
{`'\`, "missing '", 2, 1},
{`'\'`, "missing '", 3, 1},
{`'\x`, "missing '", 3, 1},
{`'\x'`, "non-hex character in escape sequence: '", 3, 1},
{`'\y'`, "unknown escape sequence", 2, 1},
{`'\x0'`, "non-hex character in escape sequence: '", 4, 1},
{`'\00'`, "non-octal character in escape sequence: '", 4, 1},
{`'\377' /*`, "comment not terminated", 7, 1}, // valid octal escape
{`'\378`, "non-octal character in escape sequence: 8", 4, 1},
{`'\400'`, "octal escape value > 255: 256", 5, 1},
{`'xx`, "missing '", 2, 1},
{`'\`, "missing '", 1, 2},
{`'\'`, "missing '", 1, 3},
{`'\x`, "missing '", 1, 3},
{`'\x'`, "non-hex character in escape sequence: '", 1, 3},
{`'\y'`, "unknown escape sequence", 1, 2},
{`'\x0'`, "non-hex character in escape sequence: '", 1, 4},
{`'\00'`, "non-octal character in escape sequence: '", 1, 4},
{`'\377' /*`, "comment not terminated", 1, 7}, // valid octal escape
{`'\378`, "non-octal character in escape sequence: 8", 1, 4},
{`'\400'`, "octal escape value > 255: 256", 1, 5},
{`'xx`, "missing '", 1, 2},
{"\"\n", "newline in string", 1, 1},
{`"`, "string not terminated", 0, 1},
{`"foo`, "string not terminated", 0, 1},
{"`", "string not terminated", 0, 1},
{"`foo", "string not terminated", 0, 1},
{"/*/", "comment not terminated", 0, 1},
{"/*\n\nfoo", "comment not terminated", 0, 1},
{"/*\n\nfoo", "comment not terminated", 0, 1},
{`"\`, "string not terminated", 0, 1},
{`"\"`, "string not terminated", 0, 1},
{`"\x`, "string not terminated", 0, 1},
{`"\x"`, "non-hex character in escape sequence: \"", 3, 1},
{`"\y"`, "unknown escape sequence", 2, 1},
{`"\x0"`, "non-hex character in escape sequence: \"", 4, 1},
{`"\00"`, "non-octal character in escape sequence: \"", 4, 1},
{`"\377" /*`, "comment not terminated", 7, 1}, // valid octal escape
{`"\378"`, "non-octal character in escape sequence: 8", 4, 1},
{`"\400"`, "octal escape value > 255: 256", 5, 1},
{`"`, "string not terminated", 1, 0},
{`"foo`, "string not terminated", 1, 0},
{"`", "string not terminated", 1, 0},
{"`foo", "string not terminated", 1, 0},
{"/*/", "comment not terminated", 1, 0},
{"/*\n\nfoo", "comment not terminated", 1, 0},
{"/*\n\nfoo", "comment not terminated", 1, 0},
{`"\`, "string not terminated", 1, 0},
{`"\"`, "string not terminated", 1, 0},
{`"\x`, "string not terminated", 1, 0},
{`"\x"`, "non-hex character in escape sequence: \"", 1, 3},
{`"\y"`, "unknown escape sequence", 1, 2},
{`"\x0"`, "non-hex character in escape sequence: \"", 1, 4},
{`"\00"`, "non-octal character in escape sequence: \"", 1, 4},
{`"\377" /*`, "comment not terminated", 1, 7}, // valid octal escape
{`"\378"`, "non-octal character in escape sequence: 8", 1, 4},
{`"\400"`, "octal escape value > 255: 256", 1, 5},
{`s := "foo\z"`, "unknown escape sequence", 10, 1},
{`s := "foo\z00\nbar"`, "unknown escape sequence", 10, 1},
{`"\x`, "string not terminated", 0, 1},
{`"\x"`, "non-hex character in escape sequence: \"", 3, 1},
{`var s string = "\x"`, "non-hex character in escape sequence: \"", 18, 1},
{`return "\Uffffffff"`, "escape sequence is invalid Unicode code point", 18, 1},
{`s := "foo\z"`, "unknown escape sequence", 1, 10},
{`s := "foo\z00\nbar"`, "unknown escape sequence", 1, 10},
{`"\x`, "string not terminated", 1, 0},
{`"\x"`, "non-hex character in escape sequence: \"", 1, 3},
{`var s string = "\x"`, "non-hex character in escape sequence: \"", 1, 18},
{`return "\Uffffffff"`, "escape sequence is invalid Unicode code point", 1, 18},
// former problem cases
{"package p\n\n\xef", "invalid UTF-8 encoding", 11, 3},
{"package p\n\n\xef", "invalid UTF-8 encoding", 3, 0},
} {
var s scanner
nerrors := 0
s.init(&bytesReader{[]byte(test.src)}, func(err error) {
s.init(&bytesReader{[]byte(test.src)}, func(line, col uint, msg string) {
nerrors++
// only check the first error
e := err.(Error) // we know it's an Error
if nerrors == 1 {
if e.Msg != test.msg {
t.Errorf("%q: got msg = %q; want %q", test.src, e.Msg, test.msg)
if msg != test.msg {
t.Errorf("%q: got msg = %q; want %q", test.src, msg, test.msg)
}
if e.Pos != test.pos {
t.Errorf("%q: got pos = %d; want %d", test.src, e.Pos, test.pos)
if line != test.line {
t.Errorf("%q: got line = %d; want %d", test.src, line, test.line)
}
if e.Line != test.line {
t.Errorf("%q: got line = %d; want %d", test.src, e.Line, test.line)
if col != test.col {
t.Errorf("%q: got col = %d; want %d", test.src, col, test.col)
}
} else if nerrors > 1 {
t.Errorf("%q: got unexpected %q at pos = %d, line = %d", test.src, e.Msg, e.Pos, e.Line)
// TODO(gri) make this use position info
t.Errorf("%q: got unexpected %q at line = %d", test.src, msg, line)
}
}, nil)

View file

@ -2,6 +2,15 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// This file implements source, a buffered rune reader
// which is specialized for the needs of the Go scanner:
// Contiguous sequences of runes (literals) are extracted
// directly as []byte without the need to re-encode the
// runes in UTF-8 (as would be necessary with bufio.Reader).
//
// This file is self-contained (go tool compile source.go
// compiles) and thus could be made into its own package.
package syntax
import (
@ -15,64 +24,69 @@ import (
// suf r0 r w
type source struct {
src io.Reader
errh ErrorHandler
first error // first error encountered
src io.Reader
errh func(line, pos uint, msg string)
// source buffer
buf [4 << 10]byte
offs int // source offset of buf
r0, r, w int // previous/current read and write buf positions, excluding sentinel
line0, line int // previous/current line
err error // pending io error
line0, line uint // previous/current line
col0, col uint // previous/current column (byte offsets from line start)
ioerr error // pending io error
// literal buffer
lit []byte // literal prefix
suf int // literal suffix; suf >= 0 means we are scanning a literal
}
func (s *source) init(src io.Reader, errh ErrorHandler) {
// init initializes source to read from src and to report errors via errh.
// errh must not be nil.
func (s *source) init(src io.Reader, errh func(line, pos uint, msg string)) {
s.src = src
s.errh = errh
s.first = nil
s.buf[0] = utf8.RuneSelf // terminate with sentinel
s.offs = 0
s.r0, s.r, s.w = 0, 0, 0
s.line0, s.line = 1, 1
s.err = nil
s.col0, s.col = 0, 0
s.ioerr = nil
s.lit = s.lit[:0]
s.suf = -1
}
func (s *source) error(msg string) {
s.error_at(s.pos0(), s.line0, msg)
}
func (s *source) error_at(pos, line int, msg string) {
err := Error{pos, line, msg}
if s.first == nil {
s.first = err
}
if s.errh == nil {
panic(s.first)
}
s.errh(err)
}
// pos0 returns the byte position of the last character read.
func (s *source) pos0() int {
return s.offs + s.r0
}
// ungetr ungets the most recently read rune.
func (s *source) ungetr() {
s.r, s.line = s.r0, s.line0
s.r, s.line, s.col = s.r0, s.line0, s.col0
}
// ungetr2 is like ungetr but enables a 2nd ungetr.
// It must not be called if one of the runes seen
// was a newline.
func (s *source) ungetr2() {
s.ungetr()
// line must not have changed
s.r0--
s.col0--
}
func (s *source) error(msg string) {
s.errh(s.line0, s.col0, msg)
}
// getr reads and returns the next rune.
//
// If a read or source encoding error occurs, getr
// calls the error handler installed with init.
// The handler must exist.
//
// The (line, col) position passed to the error handler
// is always at the current source reading position.
func (s *source) getr() rune {
redo:
s.r0, s.line0 = s.r, s.line
s.r0, s.line0, s.col0 = s.r, s.line, s.col
// We could avoid at least one test that is always taken in the
// for loop below by duplicating the common case code (ASCII)
@ -80,7 +94,7 @@ redo:
// in the buffer. Measure and optimize if necessary.
// make sure we have at least one rune in buffer, or we are at EOF
for s.r+utf8.UTFMax > s.w && !utf8.FullRune(s.buf[s.r:s.w]) && s.err == nil && s.w-s.r < len(s.buf) {
for s.r+utf8.UTFMax > s.w && !utf8.FullRune(s.buf[s.r:s.w]) && s.ioerr == nil && s.w-s.r < len(s.buf) {
s.fill() // s.w-s.r < len(s.buf) => buffer is not full
}
@ -88,20 +102,25 @@ redo:
// (invariant: s.buf[s.w] == utf8.RuneSelf)
if b := s.buf[s.r]; b < utf8.RuneSelf {
s.r++
// TODO(gri) Optimization: Instead of adjusting s.col for each character,
// remember the line offset instead and then compute the offset as needed
// (which is less often).
s.col++
if b == 0 {
s.error("invalid NUL character")
goto redo
}
if b == '\n' {
s.line++
s.col = 0
}
return rune(b)
}
// EOF
if s.r == s.w {
if s.err != io.EOF {
s.error(s.err.Error())
if s.ioerr != io.EOF {
s.error(s.ioerr.Error())
}
return -1
}
@ -109,6 +128,7 @@ redo:
// uncommon case: not ASCII
r, w := utf8.DecodeRune(s.buf[s.r:s.w])
s.r += w
s.col += uint(w)
if r == utf8.RuneError && w == 1 {
s.error("invalid UTF-8 encoding")
@ -157,13 +177,13 @@ func (s *source) fill() {
if n > 0 || err != nil {
s.buf[s.w] = utf8.RuneSelf // sentinel
if err != nil {
s.err = err
s.ioerr = err
}
return
}
}
s.err = io.ErrNoProgress
s.ioerr = io.ErrNoProgress
}
func (s *source) startLit() {

View file

@ -5,6 +5,7 @@
package syntax
import (
"cmd/internal/src"
"fmt"
"io"
"os"
@ -15,14 +16,12 @@ type Mode uint
// Error describes a syntax error. Error implements the error interface.
type Error struct {
// TODO(gri) decide what we really need here
Pos int // byte offset from file start
Line int // line (starting with 1)
Msg string
Pos src.Pos
Msg string
}
func (err Error) Error() string {
return fmt.Sprintf("%d: %s", err.Line, err.Msg)
return fmt.Sprintf("%s: %s", err.Pos, err.Msg)
}
var _ error = Error{} // verify that Error implements error
@ -38,11 +37,11 @@ type Pragma uint16
// A PragmaHandler is used to process //line and //go: directives as
// they're scanned. The returned Pragma value will be unioned into the
// next FuncDecl node.
type PragmaHandler func(pos, line int, text string) Pragma
type PragmaHandler func(pos src.Pos, text string) Pragma
// Parse parses a single Go source file from src and returns the corresponding
// syntax tree. If there are syntax errors, Parse will return the first error
// encountered.
// syntax tree. If there are errors, Parse will return the first error found.
// The base argument is only used for position information.
//
// If errh != nil, it is called with each error encountered, and Parse will
// process as much source as possible. If errh is nil, Parse will terminate
@ -51,11 +50,11 @@ type PragmaHandler func(pos, line int, text string) Pragma
// If a PragmaHandler is provided, it is called with each pragma encountered.
//
// The Mode argument is currently ignored.
func Parse(src io.Reader, errh ErrorHandler, pragh PragmaHandler, mode Mode) (_ *File, err error) {
func Parse(base *src.PosBase, src io.Reader, errh ErrorHandler, pragh PragmaHandler, mode Mode) (_ *File, first error) {
defer func() {
if p := recover(); p != nil {
var ok bool
if err, ok = p.(Error); ok {
if err, ok := p.(Error); ok {
first = err
return
}
panic(p)
@ -63,14 +62,14 @@ func Parse(src io.Reader, errh ErrorHandler, pragh PragmaHandler, mode Mode) (_
}()
var p parser
p.init(src, errh, pragh)
p.init(base, src, errh, pragh)
p.next()
return p.file(), p.first
}
// ParseBytes behaves like Parse but it reads the source from the []byte slice provided.
func ParseBytes(src []byte, errh ErrorHandler, pragh PragmaHandler, mode Mode) (*File, error) {
return Parse(&bytesReader{src}, errh, pragh, mode)
func ParseBytes(base *src.PosBase, src []byte, errh ErrorHandler, pragh PragmaHandler, mode Mode) (*File, error) {
return Parse(base, &bytesReader{src}, errh, pragh, mode)
}
type bytesReader struct {
@ -88,13 +87,13 @@ func (r *bytesReader) Read(p []byte) (int, error) {
// ParseFile behaves like Parse but it reads the source from the named file.
func ParseFile(filename string, errh ErrorHandler, pragh PragmaHandler, mode Mode) (*File, error) {
src, err := os.Open(filename)
f, err := os.Open(filename)
if err != nil {
if errh != nil {
errh(err)
}
return nil, err
}
defer src.Close()
return Parse(src, errh, pragh, mode)
defer f.Close()
return Parse(src.NewFileBase(filename, filename), f, errh, pragh, mode)
}

Some files were not shown because too many files have changed in this diff Show more