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 ...any) {
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 if Flag.LowerU == 0 {
87 sort.Stable(byPos(errorMsgs))
88 }
89 for i, err := range errorMsgs {
90 if i == 0 || err.msg != errorMsgs[i-1].msg {
91 fmt.Print(err.msg)
92 }
93 }
94 errorMsgs = errorMsgs[:0]
95 }
96
97
98
99 var lasterror struct {
100 syntax src.XPos
101 other src.XPos
102 msg string
103 }
104
105
106 func sameline(a, b src.XPos) bool {
107 p := Ctxt.PosTable.Pos(a)
108 q := Ctxt.PosTable.Pos(b)
109 return p.Base() == q.Base() && p.Line() == q.Line()
110 }
111
112
113 func Errorf(format string, args ...any) {
114 ErrorfAt(Pos, 0, format, args...)
115 }
116
117
118 func ErrorfAt(pos src.XPos, code errors.Code, format string, args ...any) {
119 msg := fmt.Sprintf(format, args...)
120
121 if strings.HasPrefix(msg, "syntax error") {
122 numSyntaxErrors++
123
124 if sameline(lasterror.syntax, pos) {
125 return
126 }
127 lasterror.syntax = pos
128 } else {
129
130
131
132
133
134 if sameline(lasterror.other, pos) && lasterror.msg == msg {
135 return
136 }
137 lasterror.other = pos
138 lasterror.msg = msg
139 }
140
141 addErrorMsg(pos, code, "%s", msg)
142 numErrors++
143
144 hcrash()
145 if numErrors >= 10 && Flag.LowerE == 0 {
146 FlushErrors()
147 fmt.Printf("%v: too many errors\n", FmtPos(pos))
148 ErrorExit()
149 }
150 }
151
152
153
154
155 func UpdateErrorDot(line string, name, expr string) {
156 if len(errorMsgs) == 0 {
157 return
158 }
159 e := &errorMsgs[len(errorMsgs)-1]
160 if strings.HasPrefix(e.msg, line) && e.msg == fmt.Sprintf("%v: undefined: %v\n", line, name) {
161 e.msg = fmt.Sprintf("%v: undefined: %v in %v\n", line, name, expr)
162 }
163 }
164
165
166
167
168
169 func Warn(format string, args ...any) {
170 WarnfAt(Pos, format, args...)
171 }
172
173
174
175
176
177 func WarnfAt(pos src.XPos, format string, args ...any) {
178 addErrorMsg(pos, 0, format, args...)
179 if Flag.LowerM != 0 {
180 FlushErrors()
181 }
182 }
183
184
185
186
187
188
189
190
191
192
193
194
195
196 func Fatalf(format string, args ...any) {
197 FatalfAt(Pos, format, args...)
198 }
199
200 var bugStack = counter.NewStack("compile/bug", 16)
201
202
203
204
205
206
207
208
209
210
211
212
213
214 func FatalfAt(pos src.XPos, format string, args ...any) {
215 FlushErrors()
216
217 bugStack.Inc()
218
219 if Debug.Panic != 0 || numErrors == 0 {
220 fmt.Printf("%v: internal compiler error: ", FmtPos(pos))
221 fmt.Printf(format, args...)
222 fmt.Printf("\n")
223
224
225 if Debug.Panic == 0 && strings.HasPrefix(buildcfg.Version, "go") && !strings.Contains(buildcfg.Version, "devel") {
226 fmt.Printf("\n")
227 fmt.Printf("Please file a bug report including a short program that triggers the error.\n")
228 fmt.Printf("https://go.dev/issue/new\n")
229 } else {
230
231 fmt.Println()
232 os.Stdout.Write(debug.Stack())
233 fmt.Println()
234 }
235 }
236
237 hcrash()
238 ErrorExit()
239 }
240
241
242 func Assert(b bool) {
243 if !b {
244 Fatalf("assertion failed")
245 }
246 }
247
248
249 func Assertf(b bool, format string, args ...any) {
250 if !b {
251 Fatalf(format, args...)
252 }
253 }
254
255
256 func AssertfAt(b bool, pos src.XPos, format string, args ...any) {
257 if !b {
258 FatalfAt(pos, format, args...)
259 }
260 }
261
262
263 func hcrash() {
264 if Flag.LowerH != 0 {
265 FlushErrors()
266 if Flag.LowerO != "" {
267 os.Remove(Flag.LowerO)
268 }
269 panic("-h")
270 }
271 }
272
273
274
275 func ErrorExit() {
276 FlushErrors()
277 if Flag.LowerO != "" {
278 os.Remove(Flag.LowerO)
279 }
280 os.Exit(2)
281 }
282
283
284 func ExitIfErrors() {
285 if Errors() > 0 {
286 ErrorExit()
287 }
288 }
289
290 var AutogeneratedPos src.XPos
291
View as plain text