1 // Copyright 2020 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
18 // An errorMsg is a queued error message, waiting to be printed.
19 type errorMsg struct {
24 // Pos is the current source position being processed,
25 // printed by Errorf, ErrorfLang, Fatalf, and Warnf.
30 numErrors int // number of entries in errorMsgs that are errors (as opposed to warnings)
34 // Errors returns the number of errors reported.
39 // SyntaxErrors returns the number of syntax errors reported
40 func SyntaxErrors() int {
41 return numSyntaxErrors
44 // addErrorMsg adds a new errorMsg (which may be a warning) to errorMsgs.
45 func addErrorMsg(pos src.XPos, format string, args ...interface{}) {
46 msg := fmt.Sprintf(format, args...)
47 // Only add the position if know the position.
48 // See issue golang.org/issue/11361.
50 msg = fmt.Sprintf("%v: %s", FmtPos(pos), msg)
52 errorMsgs = append(errorMsgs, errorMsg{
58 // FmtPos formats pos as a file:line string.
59 func FmtPos(pos src.XPos) string {
63 return Ctxt.OutermostPos(pos).Format(Flag.C == 0, Flag.L == 1)
66 // byPos sorts errors by source position.
69 func (x byPos) Len() int { return len(x) }
70 func (x byPos) Less(i, j int) bool { return x[i].pos.Before(x[j].pos) }
71 func (x byPos) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
73 // FlushErrors sorts errors seen so far by line number, prints them to stdout,
74 // and empties the errors array.
76 if Ctxt != nil && Ctxt.Bso != nil {
79 if len(errorMsgs) == 0 {
82 sort.Stable(byPos(errorMsgs))
83 for i, err := range errorMsgs {
84 if i == 0 || err.msg != errorMsgs[i-1].msg {
85 fmt.Printf("%s", err.msg)
88 errorMsgs = errorMsgs[:0]
91 // lasterror keeps track of the most recently issued error,
92 // to avoid printing multiple error messages on the same line.
93 var lasterror struct {
94 syntax src.XPos // source position of last syntax error
95 other src.XPos // source position of last non-syntax error
96 msg string // error message of last non-syntax error
99 // sameline reports whether two positions a, b are on the same line.
100 func sameline(a, b src.XPos) bool {
101 p := Ctxt.PosTable.Pos(a)
102 q := Ctxt.PosTable.Pos(b)
103 return p.Base() == q.Base() && p.Line() == q.Line()
106 // Errorf reports a formatted error at the current line.
107 func Errorf(format string, args ...interface{}) {
108 ErrorfAt(Pos, format, args...)
111 // ErrorfAt reports a formatted error message at pos.
112 func ErrorfAt(pos src.XPos, format string, args ...interface{}) {
113 msg := fmt.Sprintf(format, args...)
115 if strings.HasPrefix(msg, "syntax error") {
117 // only one syntax error per line, no matter what error
118 if sameline(lasterror.syntax, pos) {
121 lasterror.syntax = pos
123 // only one of multiple equal non-syntax errors per line
124 // (FlushErrors shows only one of them, so we filter them
125 // here as best as we can (they may not appear in order)
126 // so that we don't count them here and exit early, and
127 // then have nothing to show for.)
128 if sameline(lasterror.other, pos) && lasterror.msg == msg {
131 lasterror.other = pos
135 addErrorMsg(pos, "%s", msg)
139 if numErrors >= 10 && Flag.LowerE == 0 {
141 fmt.Printf("%v: too many errors\n", FmtPos(pos))
146 // ErrorfVers reports that a language feature (format, args) requires a later version of Go.
147 func ErrorfVers(lang string, format string, args ...interface{}) {
148 Errorf("%s requires %s or later (-lang was set to %s; check go.mod)", fmt.Sprintf(format, args...), lang, Flag.Lang)
151 // UpdateErrorDot is a clumsy hack that rewrites the last error,
152 // if it was "LINE: undefined: NAME", to be "LINE: undefined: NAME in EXPR".
153 // It is used to give better error messages for dot (selector) expressions.
154 func UpdateErrorDot(line string, name, expr string) {
155 if len(errorMsgs) == 0 {
158 e := &errorMsgs[len(errorMsgs)-1]
159 if strings.HasPrefix(e.msg, line) && e.msg == fmt.Sprintf("%v: undefined: %v\n", line, name) {
160 e.msg = fmt.Sprintf("%v: undefined: %v in %v\n", line, name, expr)
164 // Warnf reports a formatted warning at the current line.
165 // In general the Go compiler does NOT generate warnings,
166 // so this should be used only when the user has opted in
167 // to additional output by setting a particular flag.
168 func Warn(format string, args ...interface{}) {
169 WarnfAt(Pos, format, args...)
172 // WarnfAt reports a formatted warning at pos.
173 // In general the Go compiler does NOT generate warnings,
174 // so this should be used only when the user has opted in
175 // to additional output by setting a particular flag.
176 func WarnfAt(pos src.XPos, format string, args ...interface{}) {
177 addErrorMsg(pos, format, args...)
178 if Flag.LowerM != 0 {
183 // Fatalf reports a fatal error - an internal problem - at the current line and exits.
184 // If other errors have already been printed, then Fatalf just quietly exits.
185 // (The internal problem may have been caused by incomplete information
186 // after the already-reported errors, so best to let users fix those and
187 // try again without being bothered about a spurious internal error.)
189 // But if no errors have been printed, or if -d panic has been specified,
190 // Fatalf prints the error as an "internal compiler error". In a released build,
191 // it prints an error asking to file a bug report. In development builds, it
192 // prints a stack trace.
194 // If -h has been specified, Fatalf panics to force the usual runtime info dump.
195 func Fatalf(format string, args ...interface{}) {
196 FatalfAt(Pos, format, args...)
199 // FatalfAt reports a fatal error - an internal problem - at pos and exits.
200 // If other errors have already been printed, then FatalfAt just quietly exits.
201 // (The internal problem may have been caused by incomplete information
202 // after the already-reported errors, so best to let users fix those and
203 // try again without being bothered about a spurious internal error.)
205 // But if no errors have been printed, or if -d panic has been specified,
206 // FatalfAt prints the error as an "internal compiler error". In a released build,
207 // it prints an error asking to file a bug report. In development builds, it
208 // prints a stack trace.
210 // If -h has been specified, FatalfAt panics to force the usual runtime info dump.
211 func FatalfAt(pos src.XPos, format string, args ...interface{}) {
214 if Debug.Panic != 0 || numErrors == 0 {
215 fmt.Printf("%v: internal compiler error: ", FmtPos(pos))
216 fmt.Printf(format, args...)
219 // If this is a released compiler version, ask for a bug report.
220 if strings.HasPrefix(buildcfg.Version, "go") {
222 fmt.Printf("Please file a bug report including a short program that triggers the error.\n")
223 fmt.Printf("https://golang.org/issue/new\n")
225 // Not a release; dump a stack trace, too.
227 os.Stdout.Write(debug.Stack())
236 // hcrash crashes the compiler when -h is set, to find out where a message is generated.
238 if Flag.LowerH != 0 {
240 if Flag.LowerO != "" {
241 os.Remove(Flag.LowerO)
247 // ErrorExit handles an error-status exit.
248 // It flushes any pending errors, removes the output file, and exits.
251 if Flag.LowerO != "" {
252 os.Remove(Flag.LowerO)
257 // ExitIfErrors calls ErrorExit if any errors have been reported.
258 func ExitIfErrors() {
264 var AutogeneratedPos src.XPos