mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
all: merge dev.inline into master
Change-Id: I7715581a04e513dcda9918e853fa6b1ddc703770
This commit is contained in:
commit
47ce87877b
124 changed files with 6096 additions and 5655 deletions
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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": "",
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
`
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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},
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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?
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import (
|
|||
)
|
||||
|
||||
func (n *Node) Line() string {
|
||||
return Ctxt.LineHist.LineString(int(n.Lineno))
|
||||
return linestr(n.Pos)
|
||||
}
|
||||
|
||||
var atExitFuncs []func()
|
||||
|
|
|
|||
|
|
@ -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...
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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])
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue