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