1
2
3
4
5 package base
6
7 import (
8 "fmt"
9 "internal/buildcfg"
10 "os"
11 "runtime/debug"
12 "sort"
13 "strings"
14
15 "cmd/internal/src"
16 )
17
18
19 type errorMsg struct {
20 pos src.XPos
21 msg string
22 }
23
24
25
26 var Pos src.XPos
27
28 var (
29 errorMsgs []errorMsg
30 numErrors int
31 numSyntaxErrors int
32 )
33
34
35 func Errors() int {
36 return numErrors
37 }
38
39
40 func SyntaxErrors() int {
41 return numSyntaxErrors
42 }
43
44
45 func addErrorMsg(pos src.XPos, format string, args ...interface{}) {
46 msg := fmt.Sprintf(format, args...)
47
48
49 if pos.IsKnown() {
50 msg = fmt.Sprintf("%v: %s", FmtPos(pos), msg)
51 }
52 errorMsgs = append(errorMsgs, errorMsg{
53 pos: pos,
54 msg: msg + "\n",
55 })
56 }
57
58
59 func FmtPos(pos src.XPos) string {
60 if Ctxt == nil {
61 return "???"
62 }
63 return Ctxt.OutermostPos(pos).Format(Flag.C == 0, Flag.L == 1)
64 }
65
66
67 type byPos []errorMsg
68
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] }
72
73
74
75 func FlushErrors() {
76 if Ctxt != nil && Ctxt.Bso != nil {
77 Ctxt.Bso.Flush()
78 }
79 if len(errorMsgs) == 0 {
80 return
81 }
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)
86 }
87 }
88 errorMsgs = errorMsgs[:0]
89 }
90
91
92
93 var lasterror struct {
94 syntax src.XPos
95 other src.XPos
96 msg string
97 }
98
99
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()
104 }
105
106
107 func Errorf(format string, args ...interface{}) {
108 ErrorfAt(Pos, format, args...)
109 }
110
111
112 func ErrorfAt(pos src.XPos, format string, args ...interface{}) {
113 msg := fmt.Sprintf(format, args...)
114
115 if strings.HasPrefix(msg, "syntax error") {
116 numSyntaxErrors++
117
118 if sameline(lasterror.syntax, pos) {
119 return
120 }
121 lasterror.syntax = pos
122 } else {
123
124
125
126
127
128 if sameline(lasterror.other, pos) && lasterror.msg == msg {
129 return
130 }
131 lasterror.other = pos
132 lasterror.msg = msg
133 }
134
135 addErrorMsg(pos, "%s", msg)
136 numErrors++
137
138 hcrash()
139 if numErrors >= 10 && Flag.LowerE == 0 {
140 FlushErrors()
141 fmt.Printf("%v: too many errors\n", FmtPos(pos))
142 ErrorExit()
143 }
144 }
145
146
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)
149 }
150
151
152
153
154 func UpdateErrorDot(line string, name, expr string) {
155 if len(errorMsgs) == 0 {
156 return
157 }
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)
161 }
162 }
163
164
165
166
167
168 func Warn(format string, args ...interface{}) {
169 WarnfAt(Pos, format, args...)
170 }
171
172
173
174
175
176 func WarnfAt(pos src.XPos, format string, args ...interface{}) {
177 addErrorMsg(pos, format, args...)
178 if Flag.LowerM != 0 {
179 FlushErrors()
180 }
181 }
182
183
184
185
186
187
188
189
190
191
192
193
194
195 func Fatalf(format string, args ...interface{}) {
196 FatalfAt(Pos, format, args...)
197 }
198
199
200
201
202
203
204
205
206
207
208
209
210
211 func FatalfAt(pos src.XPos, format string, args ...interface{}) {
212 FlushErrors()
213
214 if Debug.Panic != 0 || numErrors == 0 {
215 fmt.Printf("%v: internal compiler error: ", FmtPos(pos))
216 fmt.Printf(format, args...)
217 fmt.Printf("\n")
218
219
220 if Debug.Panic == 0 && strings.HasPrefix(buildcfg.Version, "go") {
221 fmt.Printf("\n")
222 fmt.Printf("Please file a bug report including a short program that triggers the error.\n")
223 fmt.Printf("https://go.dev/issue/new\n")
224 } else {
225
226 fmt.Println()
227 os.Stdout.Write(debug.Stack())
228 fmt.Println()
229 }
230 }
231
232 hcrash()
233 ErrorExit()
234 }
235
236
237 func Assert(b bool) {
238 if !b {
239 Fatalf("assertion failed")
240 }
241 }
242
243
244 func Assertf(b bool, format string, args ...interface{}) {
245 if !b {
246 Fatalf(format, args...)
247 }
248 }
249
250
251 func AssertfAt(b bool, pos src.XPos, format string, args ...interface{}) {
252 if !b {
253 FatalfAt(pos, format, args...)
254 }
255 }
256
257
258 func hcrash() {
259 if Flag.LowerH != 0 {
260 FlushErrors()
261 if Flag.LowerO != "" {
262 os.Remove(Flag.LowerO)
263 }
264 panic("-h")
265 }
266 }
267
268
269
270 func ErrorExit() {
271 FlushErrors()
272 if Flag.LowerO != "" {
273 os.Remove(Flag.LowerO)
274 }
275 os.Exit(2)
276 }
277
278
279 func ExitIfErrors() {
280 if Errors() > 0 {
281 ErrorExit()
282 }
283 }
284
285 var AutogeneratedPos src.XPos
286
View as plain text