mirror of
https://github.com/golang/go
synced 2024-11-11 23:40:22 -07:00
[dev.regabi] cmd/compile: clean up error API
Prepare for factoring the error API out of this package by cleaning it up. The doc comments use the intended new names, which will be introduced in the next CL. Change-Id: Ie4c8d4262422da32a9a9f750fda42c225b6b42a8 Reviewed-on: https://go-review.googlesource.com/c/go/+/272248 Trust: Russ Cox <rsc@golang.org> Reviewed-by: Matthew Dempsky <mdempsky@google.com>
This commit is contained in:
parent
5fd949e4bd
commit
357c576878
1
src/_rex.20201123151057
Normal file
1
src/_rex.20201123151057
Normal file
@ -0,0 +1 @@
|
||||
|
@ -19,9 +19,6 @@ var externdcl []*Node
|
||||
|
||||
func testdclstack() {
|
||||
if !types.IsDclstackValid() {
|
||||
if nerrors != 0 {
|
||||
errorexit()
|
||||
}
|
||||
Fatalf("mark left on the dclstack")
|
||||
}
|
||||
}
|
||||
|
@ -102,16 +102,6 @@ var pragcgobuf [][]string
|
||||
var outfile string
|
||||
var linkobj string
|
||||
|
||||
// nerrors is the number of compiler errors reported
|
||||
// since the last call to saveerrors.
|
||||
var nerrors int
|
||||
|
||||
// nsavederrors is the total number of compiler errors
|
||||
// reported before the last call to saveerrors.
|
||||
var nsavederrors int
|
||||
|
||||
var nsyntaxerrors int
|
||||
|
||||
var decldepth int32
|
||||
|
||||
var nolocalimports bool
|
||||
|
@ -104,9 +104,7 @@ func initOrder(l []*Node) []*Node {
|
||||
// confused us and there might not be
|
||||
// a loop. Let the user fix those
|
||||
// first.
|
||||
if nerrors > 0 {
|
||||
errorexit()
|
||||
}
|
||||
ExitIfErrors()
|
||||
|
||||
findInitLoopAndExit(firstLHS(n), new([]*Node))
|
||||
Fatalf("initialization unfinished, but failed to identify loop")
|
||||
|
@ -12,10 +12,6 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// lineno is the source position at the start of the most recently lexed token.
|
||||
// TODO(gri) rename and eventually remove
|
||||
var lineno src.XPos
|
||||
|
||||
func makePos(base *src.PosBase, line, col uint) src.XPos {
|
||||
return Ctxt.PosTable.XPos(src.MakePos(base, line, col))
|
||||
}
|
||||
|
@ -119,7 +119,7 @@ func usage() {
|
||||
}
|
||||
|
||||
func hidePanic() {
|
||||
if Debug_panic == 0 && nsavederrors+nerrors > 0 {
|
||||
if Debug_panic == 0 && Errors() > 0 {
|
||||
// If we've already complained about things
|
||||
// in the program, don't bother complaining
|
||||
// about a panic too; let the user clean up
|
||||
@ -567,7 +567,6 @@ func Main(archInit func(*Arch)) {
|
||||
initUniverse()
|
||||
|
||||
dclcontext = PEXTERN
|
||||
nerrors = 0
|
||||
|
||||
autogeneratedPos = makePos(src.NewFileBase("<autogenerated>", "<autogenerated>"), 1, 0)
|
||||
|
||||
@ -625,10 +624,10 @@ func Main(archInit func(*Arch)) {
|
||||
if n.Op == ODCLFUNC {
|
||||
Curfn = n
|
||||
decldepth = 1
|
||||
saveerrors()
|
||||
errorsBefore := Errors()
|
||||
typecheckslice(Curfn.Nbody.Slice(), ctxStmt)
|
||||
checkreturn(Curfn)
|
||||
if nerrors != 0 {
|
||||
if Errors() > errorsBefore {
|
||||
Curfn.Nbody.Set(nil) // type errors; do not compile
|
||||
}
|
||||
// Now that we've checked whether n terminates,
|
||||
@ -641,11 +640,9 @@ func Main(archInit func(*Arch)) {
|
||||
// check past phase 9 isn't sufficient, as we may exit with other errors
|
||||
// before then, thus skipping map key errors.
|
||||
checkMapKeys()
|
||||
timings.AddEvent(fcount, "funcs")
|
||||
ExitIfErrors()
|
||||
|
||||
if nsavederrors+nerrors != 0 {
|
||||
errorexit()
|
||||
}
|
||||
timings.AddEvent(fcount, "funcs")
|
||||
|
||||
fninit(xtop)
|
||||
|
||||
@ -660,12 +657,8 @@ func Main(archInit func(*Arch)) {
|
||||
}
|
||||
}
|
||||
capturevarscomplete = true
|
||||
|
||||
Curfn = nil
|
||||
|
||||
if nsavederrors+nerrors != 0 {
|
||||
errorexit()
|
||||
}
|
||||
ExitIfErrors()
|
||||
|
||||
// Phase 5: Inlining
|
||||
timings.Start("fe", "inlining")
|
||||
@ -674,14 +667,10 @@ func Main(archInit func(*Arch)) {
|
||||
// otherwise lazily when used or re-exported.
|
||||
for _, n := range importlist {
|
||||
if n.Func.Inl != nil {
|
||||
saveerrors()
|
||||
typecheckinl(n)
|
||||
}
|
||||
}
|
||||
|
||||
if nsavederrors+nerrors != 0 {
|
||||
errorexit()
|
||||
}
|
||||
ExitIfErrors()
|
||||
}
|
||||
|
||||
if Debug.l != 0 {
|
||||
@ -793,10 +782,7 @@ func Main(archInit func(*Arch)) {
|
||||
// Check the map keys again, since we typechecked the external
|
||||
// declarations.
|
||||
checkMapKeys()
|
||||
|
||||
if nerrors+nsavederrors != 0 {
|
||||
errorexit()
|
||||
}
|
||||
ExitIfErrors()
|
||||
|
||||
// Write object data to disk.
|
||||
timings.Start("be", "dumpobj")
|
||||
@ -827,10 +813,7 @@ func Main(archInit func(*Arch)) {
|
||||
}
|
||||
|
||||
logopt.FlushLoggedOpts(Ctxt, myimportpath)
|
||||
|
||||
if nerrors+nsavederrors != 0 {
|
||||
errorexit()
|
||||
}
|
||||
ExitIfErrors()
|
||||
|
||||
flusherrors()
|
||||
timings.Stop()
|
||||
@ -1011,11 +994,6 @@ func readSymABIs(file, myimportpath string) {
|
||||
}
|
||||
}
|
||||
|
||||
func saveerrors() {
|
||||
nsavederrors += nerrors
|
||||
nerrors = 0
|
||||
}
|
||||
|
||||
func arsize(b *bufio.Reader, name string) int {
|
||||
var buf [ArhdrSize]byte
|
||||
if _, err := io.ReadFull(b, buf[:]); err != nil {
|
||||
@ -1396,7 +1374,7 @@ func clearImports() {
|
||||
// leave s->block set to cause redeclaration
|
||||
// errors if a conflicting top-level name is
|
||||
// introduced by a different file.
|
||||
if !n.Name.Used() && nsyntaxerrors == 0 {
|
||||
if !n.Name.Used() && SyntaxErrors() == 0 {
|
||||
unused = append(unused, importedPkg{n.Pos, n.Name.Pkg.Path, s.Name})
|
||||
}
|
||||
s.Def = nil
|
||||
@ -1405,7 +1383,7 @@ func clearImports() {
|
||||
if IsAlias(s) {
|
||||
// throw away top-level name left over
|
||||
// from previous import . "x"
|
||||
if n.Name != nil && n.Name.Pack != nil && !n.Name.Pack.Name.Used() && nsyntaxerrors == 0 {
|
||||
if n.Name != nil && n.Name.Pack != nil && !n.Name.Pack.Name.Used() && SyntaxErrors() == 0 {
|
||||
unused = append(unused, importedPkg{n.Name.Pack.Pos, n.Name.Pack.Name.Pkg.Path, ""})
|
||||
n.Name.Pack.Name.SetUsed(true)
|
||||
}
|
||||
|
@ -136,7 +136,7 @@ func (a *Mpflt) Float64() float64 {
|
||||
x, _ := a.Val.Float64()
|
||||
|
||||
// check for overflow
|
||||
if math.IsInf(x, 0) && nsavederrors+nerrors == 0 {
|
||||
if math.IsInf(x, 0) && Errors() == 0 {
|
||||
Fatalf("ovf in Mpflt Float64")
|
||||
}
|
||||
|
||||
@ -148,7 +148,7 @@ func (a *Mpflt) Float32() float64 {
|
||||
x := float64(x32)
|
||||
|
||||
// check for overflow
|
||||
if math.IsInf(x, 0) && nsavederrors+nerrors == 0 {
|
||||
if math.IsInf(x, 0) && Errors() == 0 {
|
||||
Fatalf("ovf in Mpflt Float32")
|
||||
}
|
||||
|
||||
|
@ -72,7 +72,7 @@ func (a *Mpint) SetFloat(b *Mpflt) bool {
|
||||
|
||||
func (a *Mpint) Add(b *Mpint) {
|
||||
if a.Ovf || b.Ovf {
|
||||
if nsavederrors+nerrors == 0 {
|
||||
if Errors() == 0 {
|
||||
Fatalf("ovf in Mpint Add")
|
||||
}
|
||||
a.SetOverflow()
|
||||
@ -88,7 +88,7 @@ func (a *Mpint) Add(b *Mpint) {
|
||||
|
||||
func (a *Mpint) Sub(b *Mpint) {
|
||||
if a.Ovf || b.Ovf {
|
||||
if nsavederrors+nerrors == 0 {
|
||||
if Errors() == 0 {
|
||||
Fatalf("ovf in Mpint Sub")
|
||||
}
|
||||
a.SetOverflow()
|
||||
@ -104,7 +104,7 @@ func (a *Mpint) Sub(b *Mpint) {
|
||||
|
||||
func (a *Mpint) Mul(b *Mpint) {
|
||||
if a.Ovf || b.Ovf {
|
||||
if nsavederrors+nerrors == 0 {
|
||||
if Errors() == 0 {
|
||||
Fatalf("ovf in Mpint Mul")
|
||||
}
|
||||
a.SetOverflow()
|
||||
@ -120,7 +120,7 @@ func (a *Mpint) Mul(b *Mpint) {
|
||||
|
||||
func (a *Mpint) Quo(b *Mpint) {
|
||||
if a.Ovf || b.Ovf {
|
||||
if nsavederrors+nerrors == 0 {
|
||||
if Errors() == 0 {
|
||||
Fatalf("ovf in Mpint Quo")
|
||||
}
|
||||
a.SetOverflow()
|
||||
@ -137,7 +137,7 @@ func (a *Mpint) Quo(b *Mpint) {
|
||||
|
||||
func (a *Mpint) Rem(b *Mpint) {
|
||||
if a.Ovf || b.Ovf {
|
||||
if nsavederrors+nerrors == 0 {
|
||||
if Errors() == 0 {
|
||||
Fatalf("ovf in Mpint Rem")
|
||||
}
|
||||
a.SetOverflow()
|
||||
@ -154,7 +154,7 @@ func (a *Mpint) Rem(b *Mpint) {
|
||||
|
||||
func (a *Mpint) Or(b *Mpint) {
|
||||
if a.Ovf || b.Ovf {
|
||||
if nsavederrors+nerrors == 0 {
|
||||
if Errors() == 0 {
|
||||
Fatalf("ovf in Mpint Or")
|
||||
}
|
||||
a.SetOverflow()
|
||||
@ -166,7 +166,7 @@ func (a *Mpint) Or(b *Mpint) {
|
||||
|
||||
func (a *Mpint) And(b *Mpint) {
|
||||
if a.Ovf || b.Ovf {
|
||||
if nsavederrors+nerrors == 0 {
|
||||
if Errors() == 0 {
|
||||
Fatalf("ovf in Mpint And")
|
||||
}
|
||||
a.SetOverflow()
|
||||
@ -178,7 +178,7 @@ func (a *Mpint) And(b *Mpint) {
|
||||
|
||||
func (a *Mpint) AndNot(b *Mpint) {
|
||||
if a.Ovf || b.Ovf {
|
||||
if nsavederrors+nerrors == 0 {
|
||||
if Errors() == 0 {
|
||||
Fatalf("ovf in Mpint AndNot")
|
||||
}
|
||||
a.SetOverflow()
|
||||
@ -190,7 +190,7 @@ func (a *Mpint) AndNot(b *Mpint) {
|
||||
|
||||
func (a *Mpint) Xor(b *Mpint) {
|
||||
if a.Ovf || b.Ovf {
|
||||
if nsavederrors+nerrors == 0 {
|
||||
if Errors() == 0 {
|
||||
Fatalf("ovf in Mpint Xor")
|
||||
}
|
||||
a.SetOverflow()
|
||||
@ -202,7 +202,7 @@ func (a *Mpint) Xor(b *Mpint) {
|
||||
|
||||
func (a *Mpint) Lsh(b *Mpint) {
|
||||
if a.Ovf || b.Ovf {
|
||||
if nsavederrors+nerrors == 0 {
|
||||
if Errors() == 0 {
|
||||
Fatalf("ovf in Mpint Lsh")
|
||||
}
|
||||
a.SetOverflow()
|
||||
@ -229,7 +229,7 @@ func (a *Mpint) Lsh(b *Mpint) {
|
||||
|
||||
func (a *Mpint) Rsh(b *Mpint) {
|
||||
if a.Ovf || b.Ovf {
|
||||
if nsavederrors+nerrors == 0 {
|
||||
if Errors() == 0 {
|
||||
Fatalf("ovf in Mpint Rsh")
|
||||
}
|
||||
a.SetOverflow()
|
||||
@ -267,7 +267,7 @@ func (a *Mpint) Neg() {
|
||||
|
||||
func (a *Mpint) Int64() int64 {
|
||||
if a.Ovf {
|
||||
if nsavederrors+nerrors == 0 {
|
||||
if Errors() == 0 {
|
||||
Fatalf("constant overflow")
|
||||
}
|
||||
return 0
|
||||
|
@ -64,7 +64,7 @@ func parseFiles(filenames []string) uint {
|
||||
lines += p.file.Lines
|
||||
p.file = nil // release memory
|
||||
|
||||
if nsyntaxerrors != 0 {
|
||||
if SyntaxErrors() != 0 {
|
||||
errorexit()
|
||||
}
|
||||
// Always run testdclstack here, even when debug_dclstack is not set, as a sanity measure.
|
||||
@ -333,7 +333,7 @@ func (p *noder) importDecl(imp *syntax.ImportDecl) {
|
||||
val := p.basicLit(imp.Path)
|
||||
ipkg := importfile(&val)
|
||||
if ipkg == nil {
|
||||
if nerrors == 0 {
|
||||
if Errors() == 0 {
|
||||
Fatalf("phase error in import")
|
||||
}
|
||||
return
|
||||
|
@ -198,7 +198,7 @@ func funccompile(fn *Node) {
|
||||
}
|
||||
|
||||
if fn.Type == nil {
|
||||
if nerrors == 0 {
|
||||
if Errors() == 0 {
|
||||
Fatalf("funccompile missing type")
|
||||
}
|
||||
return
|
||||
@ -224,10 +224,9 @@ func funccompile(fn *Node) {
|
||||
}
|
||||
|
||||
func compile(fn *Node) {
|
||||
saveerrors()
|
||||
|
||||
errorsBefore := Errors()
|
||||
order(fn)
|
||||
if nerrors != 0 {
|
||||
if Errors() > errorsBefore {
|
||||
return
|
||||
}
|
||||
|
||||
@ -237,7 +236,7 @@ func compile(fn *Node) {
|
||||
fn.Func.initLSym(true)
|
||||
|
||||
walk(fn)
|
||||
if nerrors != 0 {
|
||||
if Errors() > errorsBefore {
|
||||
return
|
||||
}
|
||||
if instrumenting {
|
||||
|
243
src/cmd/compile/internal/gc/print.go
Normal file
243
src/cmd/compile/internal/gc/print.go
Normal file
@ -0,0 +1,243 @@
|
||||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package gc
|
||||
|
||||
import (
|
||||
"cmd/internal/objabi"
|
||||
"cmd/internal/src"
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime/debug"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// An errorMsg is a queued error message, waiting to be printed.
|
||||
type errorMsg struct {
|
||||
pos src.XPos
|
||||
msg string
|
||||
}
|
||||
|
||||
// Pos is the current source position being processed,
|
||||
// printed by Errorf, ErrorfLang, Fatalf, and Warnf.
|
||||
var lineno src.XPos
|
||||
|
||||
var (
|
||||
errorMsgs []errorMsg
|
||||
numErrors int // number of entries in errorMsgs that are errors (as opposed to warnings)
|
||||
numSyntaxErrors int
|
||||
)
|
||||
|
||||
// Errors returns the number of errors reported.
|
||||
func Errors() int {
|
||||
return numErrors
|
||||
}
|
||||
|
||||
// SyntaxErrors returns the number of syntax errors reported
|
||||
func SyntaxErrors() int {
|
||||
return numSyntaxErrors
|
||||
}
|
||||
|
||||
// addErrorMsg adds a new errorMsg (which may be a warning) to errorMsgs.
|
||||
func addErrorMsg(pos src.XPos, format string, args ...interface{}) {
|
||||
msg := fmt.Sprintf(format, args...)
|
||||
// Only add the position if know the position.
|
||||
// See issue golang.org/issue/11361.
|
||||
if pos.IsKnown() {
|
||||
msg = fmt.Sprintf("%v: %s", linestr(pos), msg)
|
||||
}
|
||||
errorMsgs = append(errorMsgs, errorMsg{
|
||||
pos: pos,
|
||||
msg: msg + "\n",
|
||||
})
|
||||
}
|
||||
|
||||
// FmtPos formats pos as a file:line string.
|
||||
func linestr(pos src.XPos) string {
|
||||
if Ctxt == nil {
|
||||
return "???"
|
||||
}
|
||||
return Ctxt.OutermostPos(pos).Format(Debug.C == 0, Debug.L == 1)
|
||||
}
|
||||
|
||||
// byPos sorts errors by source position.
|
||||
type byPos []errorMsg
|
||||
|
||||
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.
|
||||
func flusherrors() {
|
||||
Ctxt.Bso.Flush()
|
||||
if len(errorMsgs) == 0 {
|
||||
return
|
||||
}
|
||||
sort.Stable(byPos(errorMsgs))
|
||||
for i, err := range errorMsgs {
|
||||
if i == 0 || err.msg != errorMsgs[i-1].msg {
|
||||
fmt.Printf("%s", err.msg)
|
||||
}
|
||||
}
|
||||
errorMsgs = errorMsgs[:0]
|
||||
}
|
||||
|
||||
// lasterror keeps track of the most recently issued error,
|
||||
// to avoid printing multiple error messages on the same line.
|
||||
var lasterror struct {
|
||||
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
|
||||
}
|
||||
|
||||
// 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()
|
||||
}
|
||||
|
||||
// Errorf reports a formatted error at the current line.
|
||||
func yyerror(format string, args ...interface{}) {
|
||||
yyerrorl(lineno, format, args...)
|
||||
}
|
||||
|
||||
// ErrorfAt reports a formatted error message at pos.
|
||||
func yyerrorl(pos src.XPos, format string, args ...interface{}) {
|
||||
msg := fmt.Sprintf(format, args...)
|
||||
|
||||
if strings.HasPrefix(msg, "syntax error") {
|
||||
numSyntaxErrors++
|
||||
// only one syntax error per line, no matter what error
|
||||
if sameline(lasterror.syntax, pos) {
|
||||
return
|
||||
}
|
||||
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 sameline(lasterror.other, pos) && lasterror.msg == msg {
|
||||
return
|
||||
}
|
||||
lasterror.other = pos
|
||||
lasterror.msg = msg
|
||||
}
|
||||
|
||||
addErrorMsg(pos, "%s", msg)
|
||||
numErrors++
|
||||
|
||||
hcrash()
|
||||
if numErrors >= 10 && Debug.e == 0 {
|
||||
flusherrors()
|
||||
fmt.Printf("%v: too many errors\n", linestr(pos))
|
||||
errorexit()
|
||||
}
|
||||
}
|
||||
|
||||
// ErrorfVers reports that a language feature (format, args) requires a later version of Go.
|
||||
func yyerrorv(lang string, format string, args ...interface{}) {
|
||||
yyerror("%s requires %s or later (-lang was set to %s; check go.mod)", fmt.Sprintf(format, args...), lang, flag_lang)
|
||||
}
|
||||
|
||||
// UpdateErrorDot is a clumsy hack that rewrites the last error,
|
||||
// if it was "LINE: undefined: NAME", to be "LINE: undefined: NAME in EXPR".
|
||||
// It is used to give better error messages for dot (selector) expressions.
|
||||
func UpdateErrorDot(line string, name, expr string) {
|
||||
if len(errorMsgs) == 0 {
|
||||
return
|
||||
}
|
||||
e := &errorMsgs[len(errorMsgs)-1]
|
||||
if strings.HasPrefix(e.msg, line) && e.msg == fmt.Sprintf("%v: undefined: %v\n", line, name) {
|
||||
e.msg = fmt.Sprintf("%v: undefined: %v in %v\n", line, name, expr)
|
||||
}
|
||||
}
|
||||
|
||||
// Warnf reports a formatted warning at the current line.
|
||||
// In general the Go compiler does NOT generate warnings,
|
||||
// so this should be used only when the user has opted in
|
||||
// to additional output by setting a particular flag.
|
||||
func Warn(format string, args ...interface{}) {
|
||||
Warnl(lineno, format, args...)
|
||||
}
|
||||
|
||||
// WarnfAt reports a formatted warning at pos.
|
||||
// In general the Go compiler does NOT generate warnings,
|
||||
// so this should be used only when the user has opted in
|
||||
// to additional output by setting a particular flag.
|
||||
func Warnl(pos src.XPos, format string, args ...interface{}) {
|
||||
addErrorMsg(pos, format, args...)
|
||||
if Debug.m != 0 {
|
||||
flusherrors()
|
||||
}
|
||||
}
|
||||
|
||||
// Fatal reports a fatal error - an internal problem - at the current line and exits.
|
||||
// If other errors have already been printed, then Fatal just quietly exits.
|
||||
// (The internal problem may have been caused by incomplete information
|
||||
// after the already-reported errors, so best to let users fix those and
|
||||
// try again without being bothered about a spurious internal error.)
|
||||
//
|
||||
// But if no errors have been printed, or if -d panic has been specified,
|
||||
// Fatal prints the error as an "internal compiler error". In a released build,
|
||||
// it prints an error asking to file a bug report. In development builds, it
|
||||
// prints a stack trace.
|
||||
//
|
||||
// If -h has been specified, Fatal panics to force the usual runtime info dump.
|
||||
func Fatalf(format string, args ...interface{}) {
|
||||
flusherrors()
|
||||
|
||||
if Debug_panic != 0 || numErrors == 0 {
|
||||
fmt.Printf("%v: internal compiler error: ", linestr(lineno))
|
||||
fmt.Printf(format, args...)
|
||||
fmt.Printf("\n")
|
||||
|
||||
// If this is a released compiler version, ask for a bug report.
|
||||
if strings.HasPrefix(objabi.Version, "go") {
|
||||
fmt.Printf("\n")
|
||||
fmt.Printf("Please file a bug report including a short program that triggers the error.\n")
|
||||
fmt.Printf("https://golang.org/issue/new\n")
|
||||
} else {
|
||||
// Not a release; dump a stack trace, too.
|
||||
fmt.Println()
|
||||
os.Stdout.Write(debug.Stack())
|
||||
fmt.Println()
|
||||
}
|
||||
}
|
||||
|
||||
hcrash()
|
||||
errorexit()
|
||||
}
|
||||
|
||||
// hcrash crashes the compiler when -h is set, to find out where a message is generated.
|
||||
func hcrash() {
|
||||
if Debug.h != 0 {
|
||||
flusherrors()
|
||||
if outfile != "" {
|
||||
os.Remove(outfile)
|
||||
}
|
||||
panic("-h")
|
||||
}
|
||||
}
|
||||
|
||||
// ErrorExit handles an error-status exit.
|
||||
// It flushes any pending errors, removes the output file, and exits.
|
||||
func errorexit() {
|
||||
flusherrors()
|
||||
if outfile != "" {
|
||||
os.Remove(outfile)
|
||||
}
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
// ExitIfErrors calls ErrorExit if any errors have been reported.
|
||||
func ExitIfErrors() {
|
||||
if Errors() > 0 {
|
||||
errorexit()
|
||||
}
|
||||
}
|
@ -6,13 +6,10 @@ package gc
|
||||
|
||||
import (
|
||||
"cmd/compile/internal/types"
|
||||
"cmd/internal/objabi"
|
||||
"cmd/internal/src"
|
||||
"crypto/md5"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime/debug"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
@ -21,13 +18,6 @@ import (
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
type Error struct {
|
||||
pos src.XPos
|
||||
msg string
|
||||
}
|
||||
|
||||
var errors []Error
|
||||
|
||||
// largeStack is info about a function whose stack frame is too large (rare).
|
||||
type largeStack struct {
|
||||
locals int64
|
||||
@ -41,170 +31,6 @@ var (
|
||||
largeStackFrames []largeStack
|
||||
)
|
||||
|
||||
func errorexit() {
|
||||
flusherrors()
|
||||
if outfile != "" {
|
||||
os.Remove(outfile)
|
||||
}
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
func adderrorname(n *Node) {
|
||||
if n.Op != ODOT {
|
||||
return
|
||||
}
|
||||
old := fmt.Sprintf("%v: undefined: %v\n", n.Line(), n.Left)
|
||||
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(pos src.XPos, format string, args ...interface{}) {
|
||||
msg := fmt.Sprintf(format, args...)
|
||||
// Only add the position if know the position.
|
||||
// See issue golang.org/issue/11361.
|
||||
if pos.IsKnown() {
|
||||
msg = fmt.Sprintf("%v: %s", linestr(pos), msg)
|
||||
}
|
||||
errors = append(errors, Error{
|
||||
pos: pos,
|
||||
msg: msg + "\n",
|
||||
})
|
||||
}
|
||||
|
||||
// byPos sorts errors by source position.
|
||||
type byPos []Error
|
||||
|
||||
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.
|
||||
func flusherrors() {
|
||||
Ctxt.Bso.Flush()
|
||||
if len(errors) == 0 {
|
||||
return
|
||||
}
|
||||
sort.Stable(byPos(errors))
|
||||
for i, err := range errors {
|
||||
if i == 0 || err.msg != errors[i-1].msg {
|
||||
fmt.Printf("%s", err.msg)
|
||||
}
|
||||
}
|
||||
errors = errors[:0]
|
||||
}
|
||||
|
||||
func hcrash() {
|
||||
if Debug.h != 0 {
|
||||
flusherrors()
|
||||
if outfile != "" {
|
||||
os.Remove(outfile)
|
||||
}
|
||||
var x *int
|
||||
*x = 0
|
||||
}
|
||||
}
|
||||
|
||||
func linestr(pos src.XPos) string {
|
||||
return Ctxt.OutermostPos(pos).Format(Debug.C == 0, Debug.L == 1)
|
||||
}
|
||||
|
||||
// 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 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
|
||||
}
|
||||
|
||||
// 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 sameline(lasterror.syntax, pos) {
|
||||
return
|
||||
}
|
||||
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 sameline(lasterror.other, pos) && lasterror.msg == msg {
|
||||
return
|
||||
}
|
||||
lasterror.other = pos
|
||||
lasterror.msg = msg
|
||||
}
|
||||
|
||||
adderr(pos, "%s", msg)
|
||||
|
||||
hcrash()
|
||||
nerrors++
|
||||
if nsavederrors+nerrors >= 10 && Debug.e == 0 {
|
||||
flusherrors()
|
||||
fmt.Printf("%v: too many errors\n", linestr(pos))
|
||||
errorexit()
|
||||
}
|
||||
}
|
||||
|
||||
func yyerrorv(lang string, format string, args ...interface{}) {
|
||||
what := fmt.Sprintf(format, args...)
|
||||
yyerrorl(lineno, "%s requires %s or later (-lang was set to %s; check go.mod)", what, lang, flag_lang)
|
||||
}
|
||||
|
||||
func yyerror(format string, args ...interface{}) {
|
||||
yyerrorl(lineno, format, args...)
|
||||
}
|
||||
|
||||
func Warn(fmt_ string, args ...interface{}) {
|
||||
Warnl(lineno, fmt_, args...)
|
||||
}
|
||||
|
||||
func Warnl(line src.XPos, fmt_ string, args ...interface{}) {
|
||||
adderr(line, fmt_, args...)
|
||||
if Debug.m != 0 {
|
||||
flusherrors()
|
||||
}
|
||||
}
|
||||
|
||||
func Fatalf(fmt_ string, args ...interface{}) {
|
||||
flusherrors()
|
||||
|
||||
if Debug_panic != 0 || nsavederrors+nerrors == 0 {
|
||||
fmt.Printf("%v: internal compiler error: ", linestr(lineno))
|
||||
fmt.Printf(fmt_, args...)
|
||||
fmt.Printf("\n")
|
||||
|
||||
// If this is a released compiler version, ask for a bug report.
|
||||
if strings.HasPrefix(objabi.Version, "go") {
|
||||
fmt.Printf("\n")
|
||||
fmt.Printf("Please file a bug report including a short program that triggers the error.\n")
|
||||
fmt.Printf("https://golang.org/issue/new\n")
|
||||
} else {
|
||||
// Not a release; dump a stack trace, too.
|
||||
fmt.Println()
|
||||
os.Stdout.Write(debug.Stack())
|
||||
fmt.Println()
|
||||
}
|
||||
}
|
||||
|
||||
hcrash()
|
||||
errorexit()
|
||||
}
|
||||
|
||||
// hasUniquePos reports whether n has a unique position that can be
|
||||
// used for reporting error messages.
|
||||
//
|
||||
|
@ -280,7 +280,7 @@ func typecheck(n *Node, top int) (res *Node) {
|
||||
yyerrorl(n.Pos, "constant definition loop%s", cycleTrace(cycleFor(n)))
|
||||
}
|
||||
|
||||
if nsavederrors+nerrors == 0 {
|
||||
if Errors() == 0 {
|
||||
var trace string
|
||||
for i := len(typecheck_tcstack) - 1; i >= 0; i-- {
|
||||
x := typecheck_tcstack[i]
|
||||
@ -891,7 +891,7 @@ func typecheck1(n *Node, top int) (res *Node) {
|
||||
|
||||
t := n.Left.Type
|
||||
if t == nil {
|
||||
adderrorname(n)
|
||||
UpdateErrorDot(n.Line(), n.Left.String(), n.String())
|
||||
n.Type = nil
|
||||
return n
|
||||
}
|
||||
@ -3641,7 +3641,7 @@ func typecheckdef(n *Node) {
|
||||
if n.SubOp() != 0 { // like OPRINTN
|
||||
break
|
||||
}
|
||||
if nsavederrors+nerrors > 0 {
|
||||
if Errors() > 0 {
|
||||
// Can have undefined variables in x := foo
|
||||
// that make x have an n.name.Defn == nil.
|
||||
// If there are other errors anyway, don't
|
||||
@ -3686,9 +3686,9 @@ func typecheckdef(n *Node) {
|
||||
n.SetWalkdef(1)
|
||||
setTypeNode(n, types.New(TFORW))
|
||||
n.Type.Sym = n.Sym
|
||||
nerrors0 := nerrors
|
||||
errorsBefore := Errors()
|
||||
typecheckdeftype(n)
|
||||
if n.Type.Etype == TFORW && nerrors > nerrors0 {
|
||||
if n.Type.Etype == TFORW && Errors() > errorsBefore {
|
||||
// Something went wrong during type-checking,
|
||||
// but it was reported. Silence future errors.
|
||||
n.Type.SetBroke(true)
|
||||
|
@ -20,6 +20,7 @@ const zeroValSize = 1024 // must match value of runtime/map.go:maxZero
|
||||
|
||||
func walk(fn *Node) {
|
||||
Curfn = fn
|
||||
errorsBefore := Errors()
|
||||
|
||||
if Debug.W != 0 {
|
||||
s := fmt.Sprintf("\nbefore walk %v", Curfn.Func.Nname.Sym)
|
||||
@ -59,7 +60,7 @@ func walk(fn *Node) {
|
||||
}
|
||||
|
||||
lineno = lno
|
||||
if nerrors != 0 {
|
||||
if Errors() > errorsBefore {
|
||||
return
|
||||
}
|
||||
walkstmtlist(Curfn.Nbody.Slice())
|
||||
|
Loading…
Reference in New Issue
Block a user