err.c revision 1.247 1 /* $NetBSD: err.c,v 1.247 2024/07/10 20:33:37 rillig Exp $ */
2
3 /*
4 * Copyright (c) 1994, 1995 Jochen Pohl
5 * All Rights Reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Jochen Pohl for
18 * The NetBSD Project.
19 * 4. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 #if HAVE_NBTOOL_CONFIG_H
35 #include "nbtool_config.h"
36 #endif
37
38 #include <sys/cdefs.h>
39 #if defined(__RCSID)
40 __RCSID("$NetBSD: err.c,v 1.247 2024/07/10 20:33:37 rillig Exp $");
41 #endif
42
43 #include <limits.h>
44 #include <stdarg.h>
45 #include <stdlib.h>
46 #include <string.h>
47
48 #include "lint1.h"
49
50 bool seen_error;
51 bool seen_warning;
52
53 /* number of syntax errors */
54 int sytxerr;
55
56
57 static const char *const msgs[] = {
58 "empty declaration", // 0
59 "old-style declaration; add 'int'", // 1
60 "empty declaration", // 2
61 "'%s' declared in parameter declaration list", // 3
62 "illegal type combination", // 4
63 "modifying typedef with '%s'; only qualifiers allowed", // 5
64 "use 'double' instead of 'long float'", // 6
65 "only one storage class allowed", // 7
66 "illegal storage class", // 8
67 "only 'register' is valid as storage class in parameter", // 9
68 "duplicate '%s'", // 10
69 "bit-field initializer out of range", // 11
70 "compiler takes size of function", // 12
71 "incomplete enum type '%s'", // 13
72 "", // 14
73 "function returns illegal type '%s'", // 15
74 "array of function is illegal", // 16
75 "null dimension", // 17
76 "illegal use of 'void'", // 18
77 "void type for '%s'", // 19
78 "negative array dimension (%d)", // 20
79 "redeclaration of formal parameter '%s'", // 21
80 "incomplete or misplaced function definition", // 22
81 "undefined label '%s'", // 23
82 "cannot initialize function '%s'", // 24
83 "cannot initialize typedef '%s'", // 25
84 "cannot initialize extern declaration '%s'", // 26
85 "redeclaration of '%s'", // 27
86 "redefinition of '%s'", // 28
87 "'%s' was previously declared extern, becomes static", // 29
88 "redeclaration of '%s'; C90 or later require static", // 30
89 "'%s' has incomplete type '%s'", // 31
90 "type of parameter '%s' defaults to 'int'", // 32
91 "duplicate member name '%s'", // 33
92 "nonportable bit-field type '%s'", // 34
93 "illegal bit-field type '%s'", // 35
94 "illegal bit-field size: %d", // 36
95 "zero size bit-field", // 37
96 "function illegal in structure or union", // 38
97 "zero-sized array '%s' in struct requires C99 or later", // 39
98 "", /* never used */ // 40
99 "bit-field in union is very unusual", // 41
100 "forward reference to enum type", // 42
101 "redefinition of '%s' hides earlier one", // 43
102 "declaration of '%s %s' introduces new type in C90 or later", // 44
103 "base type is really '%s %s'", // 45
104 "%s tag '%s' redeclared as %s", // 46
105 "zero sized %s is a C99 feature", // 47
106 "enumeration value '%s' overflows", // 48
107 "anonymous struct/union members is a C11 feature", // 49
108 "parameter '%s' has function type, should be pointer", // 50
109 "parameter mismatch: %d declared, %d defined", // 51
110 "cannot initialize parameter '%s'", // 52
111 "declared parameter '%s' is missing", // 53
112 "trailing ',' in enum declaration requires C99 or later", // 54
113 "integral constant expression expected", // 55
114 "integral constant too large", // 56
115 "enumeration constant '%s' hides parameter", // 57
116 "type of '%s' does not match prototype", // 58
117 "formal parameter #%d lacks name", // 59
118 "void must be sole parameter", // 60
119 "void parameter '%s' cannot have name", // 61
120 "function prototype parameters must have types", // 62
121 "prototype does not match old-style definition", // 63
122 "()-less function definition", // 64
123 "'%s' has no named members", // 65
124 "", // 66
125 "cannot return incomplete type", // 67
126 "typedef already qualified with '%s'", // 68
127 "inappropriate qualifiers with 'void'", // 69
128 "", /* unused */ // 70
129 "too many characters in character constant", // 71
130 "typedef declares no type name", // 72
131 "empty character constant", // 73
132 "no hex digits follow \\x", // 74
133 "overflow in hex escape", // 75
134 "character escape does not fit in character", // 76
135 "bad octal digit '%c'", // 77
136 "", /* unused */ // 78
137 "dubious escape \\%c", // 79
138 "dubious escape \\%o", // 80
139 "\\a undefined in traditional C", // 81
140 "\\x undefined in traditional C", // 82
141 "storage class after type is obsolescent", // 83
142 "C90 to C17 require formal parameter before '...'", // 84
143 "dubious tag declaration '%s %s'", // 85
144 "automatic '%s' hides external declaration", // 86
145 "static '%s' hides external declaration", // 87
146 "typedef '%s' hides external declaration", // 88
147 "typedef '%s' redeclared", // 89
148 "inconsistent redeclaration of extern '%s'", // 90
149 "declaration of '%s' hides parameter", // 91
150 "inconsistent redeclaration of static '%s'", // 92
151 "dubious static function '%s' at block level", // 93
152 "function '%s' has illegal storage class", // 94
153 "declaration of '%s' hides earlier one", // 95
154 "cannot dereference non-pointer type '%s'", // 96
155 "suffix 'U' is illegal in traditional C", // 97
156 "suffixes 'F' and 'L' are illegal in traditional C", // 98
157 "'%s' undefined", // 99
158 "unary '+' is illegal in traditional C", // 100
159 "type '%s' does not have member '%s'", // 101
160 "illegal use of member '%s'", // 102
161 "left operand of '.' must be struct or union, not '%s'", // 103
162 "left operand of '->' must be pointer to struct or union, not '%s'", // 104
163 "non-unique member requires struct/union %s", // 105
164 "left operand of '->' must be pointer", // 106
165 "operands of '%s' have incompatible types '%s' and '%s'", // 107
166 "operand of '%s' has invalid type '%s'", // 108
167 "void type illegal in expression", // 109
168 "pointer to function is not allowed here", // 110
169 "unacceptable operand of '%s'", // 111
170 "cannot take address of bit-field", // 112
171 "cannot take address of register '%s'", // 113
172 "%soperand of '%s' must be lvalue", // 114
173 "%soperand of '%s' must be modifiable lvalue", // 115
174 "illegal pointer subtraction", // 116
175 "bitwise '%s' on signed value possibly nonportable", // 117
176 "semantics of '%s' change in C90; use explicit cast", // 118
177 "conversion of '%s' to '%s' is out of range", // 119
178 "bitwise '%s' on signed value nonportable", // 120
179 "negative shift", // 121
180 "shift amount %llu is greater than bit-size %llu of '%s'", // 122
181 "illegal combination of %s '%s' and %s '%s', op '%s'", // 123
182 "illegal combination of '%s' and '%s', op '%s'", // 124
183 "pointers to functions can only be compared for equality", // 125
184 "incompatible types '%s' and '%s' in conditional", // 126
185 "'&' before array or function: ignored", // 127
186 "operands of '%s' have incompatible pointer types to '%s' and '%s'", // 128
187 "expression has null effect", // 129
188 "enum type mismatch: '%s' '%s' '%s'", // 130
189 "conversion to '%s' may sign-extend incorrectly", // 131
190 "conversion from '%s' to '%s' may lose accuracy", // 132
191 "conversion of pointer to '%s' loses bits", // 133
192 "conversion of pointer to '%s' may lose bits", // 134
193 "converting '%s' to '%s' increases alignment from %u to %u", // 135
194 "cannot do pointer arithmetic on operand of unknown size", // 136
195 "", /* unused */ // 137
196 "unknown operand size, op '%s'", // 138
197 "division by 0", // 139
198 "modulus by 0", // 140
199 "'%s' overflows '%s'", // 141
200 "operator '%s' produces floating point overflow", // 142
201 "cannot take size/alignment of incomplete type", // 143
202 "cannot take size/alignment of function type '%s'", // 144
203 "cannot take size/alignment of bit-field", // 145
204 "cannot take size/alignment of void", // 146
205 "invalid cast from '%s' to '%s'", // 147
206 "improper cast of void expression", // 148
207 "cannot call '%s', must be a function", // 149
208 "argument mismatch: %d %s passed, %d expected", // 150
209 "void expressions may not be arguments, arg #%d", // 151
210 "argument cannot have unknown size, arg #%d", // 152
211 "converting '%s' to incompatible '%s' for argument %d", // 153
212 "illegal combination of %s '%s' and %s '%s', arg #%d", // 154
213 "passing '%s' to incompatible '%s', arg #%d", // 155
214 "function expects '%s', passing '%s' for arg #%d", // 156
215 "C90 treats constant as unsigned", // 157
216 "'%s' may be used before set", // 158
217 "assignment in conditional context", // 159
218 "operator '==' found where '=' was expected", // 160
219 "constant in conditional context", // 161
220 "operator '%s' compares '%s' with '%s'", // 162
221 "a cast does not yield an lvalue", // 163
222 "assignment of negative constant %lld to unsigned type '%s'", // 164
223 "constant truncated by assignment", // 165
224 "precision lost in bit-field assignment", // 166
225 "array subscript %jd cannot be negative", // 167
226 "array subscript %ju cannot be > %d", // 168
227 "precedence confusion possible: parenthesize!", // 169
228 "first operand of '?' must have scalar type", // 170
229 "cannot assign to '%s' from '%s'", // 171
230 "too many struct/union initializers", // 172
231 "too many array initializers, expected %d", // 173
232 "too many initializers for '%s'", // 174
233 "initialization of incomplete type '%s'", // 175
234 "", /* no longer used */ // 176
235 "non-constant initializer", // 177
236 "initializer does not fit", // 178
237 "cannot initialize struct/union with no named member", // 179
238 "bit-field initializer does not fit", // 180
239 "{}-enclosed or constant initializer of type '%s' required", // 181
240 "incompatible pointer types to '%s' and '%s'", // 182
241 "illegal combination of %s '%s' and %s '%s'", // 183
242 "illegal combination of '%s' and '%s'", // 184
243 "cannot initialize '%s' from '%s'", // 185
244 "bit-field initializer must be an integer in traditional C", // 186
245 "string literal too long (%ju) for target array (%ju)", // 187
246 "no automatic aggregate initialization in traditional C", // 188
247 "", /* no longer used */ // 189
248 "empty array declaration for '%s'", // 190
249 "'%s' set but not used in function '%s'", // 191
250 "'%s' unused in function '%s'", // 192
251 "statement not reached", // 193
252 "label '%s' redefined", // 194
253 "case not in switch", // 195
254 "case label affected by conversion", // 196
255 "non-constant case expression", // 197
256 "non-integral case expression", // 198
257 "duplicate case '%jd' in switch", // 199
258 "duplicate case '%ju' in switch", // 200
259 "default outside switch", // 201
260 "duplicate default in switch", // 202
261 "case label must be of type 'int' in traditional C", // 203
262 "controlling expressions must have scalar type", // 204
263 "switch expression must have integral type", // 205
264 "enumeration value(s) not handled in switch", // 206
265 "loop not entered at top", // 207
266 "break outside loop or switch", // 208
267 "continue outside loop", // 209
268 "enum type mismatch between '%s' and '%s' in initialization", // 210
269 "function has return type '%s' but returns '%s'", // 211
270 "cannot return incomplete type", // 212
271 "void function '%s' cannot return value", // 213
272 "function '%s' expects to return value", // 214
273 "function '%s' implicitly declared to return int", // 215
274 "function '%s' has 'return expr' and 'return'", // 216
275 "function '%s' falls off bottom without returning value", // 217
276 "C90 treats constant as unsigned, op '%s'", // 218
277 "concatenated strings are illegal in traditional C", // 219
278 "fallthrough on case statement", // 220
279 "initialization of unsigned type '%s' with negative constant %lld", // 221
280 "conversion of negative constant %lld to unsigned type '%s'", // 222
281 "end-of-loop code not reached", // 223
282 "cannot recover from previous errors", // 224
283 "static function '%s' called but not defined", // 225
284 "static variable '%s' unused", // 226
285 "const object '%s' should have initializer", // 227
286 "function cannot return const or volatile object", // 228
287 "converting '%s' to '%s' is questionable", // 229
288 "nonportable character comparison '%s'", // 230
289 "parameter '%s' unused in function '%s'", // 231
290 "label '%s' unused in function '%s'", // 232
291 "struct '%s' never defined", // 233
292 "union '%s' never defined", // 234
293 "enum '%s' never defined", // 235
294 "static function '%s' unused", // 236
295 "redeclaration of formal parameter '%s'", // 237
296 "initialization of union is illegal in traditional C", // 238
297 "constant operand to '!'", // 239
298 "", /* unused */ // 240
299 "dubious operation '%s' on enum", // 241
300 "combination of '%s' and '%s', op '%s'", // 242
301 "operator '%s' assumes that '%s' is ordered", // 243
302 "illegal structure pointer combination", // 244
303 "incompatible structure pointers: '%s' '%s' '%s'", // 245
304 "dubious conversion of enum to '%s'", // 246
305 "pointer cast from '%s' to '%s' may be troublesome", // 247
306 "floating-point constant out of range", // 248
307 "syntax error '%s'", // 249
308 "unknown character \\%o", // 250
309 "malformed integer constant", // 251
310 "integer constant out of range", // 252
311 "unterminated character constant", // 253
312 "newline in string or char constant", // 254
313 "undefined or invalid '#' directive", // 255
314 "unterminated comment", // 256
315 "extra characters in lint comment", // 257
316 "unterminated string constant", // 258
317 "argument %d is converted from '%s' to '%s' due to prototype", // 259
318 "previous declaration of '%s'", // 260
319 "previous definition of '%s'", // 261
320 "\\\" inside character constants undefined in traditional C", // 262
321 "\\? undefined in traditional C", // 263
322 "\\v undefined in traditional C", // 264
323 "%s does not support 'long long'", // 265
324 "'long double' is illegal in traditional C", // 266
325 "shift amount %u equals bit-size of '%s'", // 267
326 "variable '%s' declared inline", // 268
327 "parameter '%s' declared inline", // 269
328 "function prototypes are illegal in traditional C", // 270
329 "switch expression must be of type 'int' in traditional C", // 271
330 "empty translation unit", // 272
331 "bit-field type '%s' invalid in C90 or later", // 273
332 "C90 or later forbid comparison of %s with %s", // 274
333 "cast discards 'const' from type '%s'", // 275
334 "'__%s__' is illegal for type '%s'", // 276
335 "initialization of '%s' with '%s'", // 277
336 "combination of '%s' and '%s', arg #%d", // 278
337 "combination of '%s' and '%s' in return", // 279
338 "comment /* %s */ must be outside function", // 280
339 "duplicate comment /* %s */", // 281
340 "comment /* %s */ must precede function definition", // 282
341 "parameter number mismatch in comment /* %s */", // 283
342 "fallthrough on default statement", // 284
343 "prototype declaration", // 285
344 "function definition is not a prototype", // 286
345 "function declaration is not a prototype", // 287
346 "dubious use of /* VARARGS */ with /* %s */", // 288
347 "/* PRINTFLIKE */ and /* SCANFLIKE */ cannot be combined", // 289
348 "static function '%s' declared but not defined", // 290
349 "invalid multibyte character", // 291
350 "cannot concatenate wide and regular string literals", // 292
351 "parameter %d must be 'char *' for PRINTFLIKE/SCANFLIKE", // 293
352 "multi-character character constant", // 294
353 "conversion of '%s' to '%s' is out of range, arg #%d", // 295
354 "conversion of negative constant %lld to unsigned type '%s', arg #%d", // 296
355 "conversion to '%s' may sign-extend incorrectly, arg #%d", // 297
356 "conversion from '%s' to '%s' may lose accuracy, arg #%d", // 298
357 "prototype does not match old-style definition, arg #%d", // 299
358 "old-style definition", // 300
359 "array of incomplete type", // 301
360 "'%s' returns pointer to automatic object", // 302
361 "conversion of %s to %s requires a cast", // 303
362 "conversion of %s to %s requires a cast, arg #%d", // 304
363 "conversion of %s to %s requires a cast, op %s", // 305
364 "constant truncated by conversion, op '%s'", // 306
365 "static variable '%s' set but not used", // 307
366 "invalid type for _Complex", // 308
367 "extra bits set to 0 in conversion of '%s' to '%s', op '%s'", // 309
368 "symbol renaming can't be used on function parameters", // 310
369 "symbol renaming can't be used on automatic variables", // 311
370 "%s does not support '//' comments", // 312
371 "struct or union member name in initializer is a C99 feature", // 313
372 "", /* never used */ // 314
373 "GCC style struct or union member name in initializer", // 315
374 "__FUNCTION__/__PRETTY_FUNCTION__ is a GCC extension", // 316
375 "__func__ is a C99 feature", // 317
376 "variable array dimension is a C99/GCC extension", // 318
377 "compound literals are a C99/GCC extension", // 319
378 "'({ ... })' is a GCC extension", // 320
379 "array initializer with designators is a C99 feature", // 321
380 "zero sized array requires C99 or later", // 322
381 "continue in 'do ... while (0)' loop", // 323
382 "suggest cast from '%s' to '%s' on op '%s' to avoid overflow", // 324
383 "variable declaration in for loop", // 325
384 "attribute '%s' ignored for '%s'", // 326
385 "declarations after statements is a C99 feature", // 327
386 "union cast is a GCC extension", // 328
387 "type '%s' is not a member of '%s'", // 329
388 "operand of '%s' must be bool, not '%s'", // 330
389 "left operand of '%s' must be bool, not '%s'", // 331
390 "right operand of '%s' must be bool, not '%s'", // 332
391 "controlling expression must be bool, not '%s'", // 333
392 "parameter %d expects '%s', gets passed '%s'", // 334
393 "operand of '%s' must not be bool", // 335
394 "left operand of '%s' must not be bool", // 336
395 "right operand of '%s' must not be bool", // 337
396 "option '%c' should be handled in the switch", // 338
397 "option '%c' should be listed in the options string", // 339
398 "initialization with '[a...b]' is a GCC extension", // 340
399 "argument to '%s' must be 'unsigned char' or EOF, not '%s'", // 341
400 "argument to '%s' must be cast to 'unsigned char', not to '%s'", // 342
401 "static array size requires C11 or later", // 343
402 "bit-field of type plain 'int' has implementation-defined signedness", // 344
403 "generic selection requires C11 or later", // 345
404 "call to '%s' effectively discards 'const' from argument", // 346
405 "redeclaration of '%s' with type '%s', expected '%s'", // 347
406 "maximum value %d of '%s' does not match maximum array index %d", // 348
407 "non type argument to alignof is a GCC extension", // 349
408 "'_Atomic' requires C11 or later", // 350
409 "missing%s header declaration for '%s'", // 351
410 "nested 'extern' declaration of '%s'", // 352
411 "empty initializer braces require C23 or later", // 353
412 "'_Static_assert' requires C11 or later", // 354
413 "'_Static_assert' without message requires C23 or later", // 355
414 "short octal escape '%.*s' followed by digit '%c'", // 356
415 "hex escape '%.*s' mixes uppercase and lowercase digits", // 357
416 "hex escape '%.*s' has more than 2 digits", // 358
417 "missing new-style '\\177' or old-style number base", // 359
418 "missing new-style number base after '\\177'", // 360
419 "number base '%.*s' is %ju, must be 8, 10 or 16", // 361
420 "conversion '%.*s' should not be escaped", // 362
421 "escaped character '%.*s' in description of conversion '%.*s'", // 363
422 "missing bit position after '%.*s'", // 364
423 "missing field width after '%.*s'", // 365
424 "missing '\\0' at the end of '%.*s'", // 366
425 "empty description in '%.*s'", // 367
426 "missing comparison value after conversion '%.*s'", // 368
427 "bit position '%.*s' in '%.*s' should be escaped as octal or hex", // 369
428 "field width '%.*s' in '%.*s' should be escaped as octal or hex", // 370
429 "bit position '%.*s' (%ju) in '%.*s' out of range %u..%u", // 371
430 "field width '%.*s' (%ju) in '%.*s' out of range 0..64", // 372
431 "bit field end %ju in '%.*s' out of range 0..64", // 373
432 "unknown conversion '%.*s', must be one of 'bfF=:*'", // 374
433 "comparison value '%.*s' (%ju) exceeds maximum field value %ju", // 375
434 "'%.*s' overlaps earlier '%.*s' on bit %u", // 376
435 "redundant '\\0' at the end of the format", // 377
436 "conversion '%.*s' is unreachable by input value", // 378
437 "comparing integer '%s' to floating point constant %Lg", // 379
438 "lossy conversion of %Lg to '%s', arg #%d", // 380
439 "lossy conversion of %Lg to '%s'", // 381
440 "constant assignment of type '%s' in operand of '!' always evaluates to '%s'", // 382
441 };
442
443 static bool is_suppressed[sizeof(msgs) / sizeof(msgs[0])];
444
445 static struct include_level {
446 const char *filename;
447 int lineno;
448 struct include_level *by;
449 } *includes;
450
451 void
452 suppress_messages(const char *p)
453 {
454 char *end;
455
456 for (; ch_isdigit(*p); p = end + 1) {
457 unsigned long id = strtoul(p, &end, 10);
458 if ((*end != '\0' && *end != ',') ||
459 id >= sizeof(msgs) / sizeof(msgs[0]) ||
460 msgs[id][0] == '\0')
461 break;
462
463 is_suppressed[id] = true;
464
465 if (*end == '\0')
466 return;
467 }
468 errx(1, "invalid message ID '%.*s'", (int)strcspn(p, ","), p);
469 }
470
471 void
472 update_location(const char *filename, int lineno, bool is_begin, bool is_end)
473 {
474 struct include_level *top;
475
476 top = includes;
477 if (is_begin && top != NULL)
478 top->lineno = curr_pos.p_line;
479
480 if (top == NULL || is_begin) {
481 top = xmalloc(sizeof(*top));
482 top->filename = filename;
483 top->lineno = lineno;
484 top->by = includes;
485 includes = top;
486 } else {
487 if (is_end) {
488 includes = top->by;
489 free(top);
490 top = includes;
491 }
492 if (top != NULL) {
493 top->filename = filename;
494 top->lineno = lineno;
495 }
496 }
497 }
498
499 static void
500 print_stack_trace(void)
501 {
502 const struct include_level *top;
503
504 if ((top = includes) == NULL)
505 return;
506 /*
507 * Skip the innermost include level since it is already listed in the
508 * diagnostic itself. Furthermore, its lineno is the line number of
509 * the last '#' line, not the current line.
510 */
511 for (top = top->by; top != NULL; top = top->by)
512 printf("\tincluded from %s(%d)\n", top->filename, top->lineno);
513 }
514
515 /*
516 * If Fflag is not set, lbasename() returns a pointer to the last
517 * component of the path, otherwise it returns the argument.
518 */
519 static const char *
520 lbasename(const char *path)
521 {
522
523 if (Fflag)
524 return path;
525
526 const char *base = path;
527 for (const char *p = path; *p != '\0'; p++)
528 if (*p == '/')
529 base = p + 1;
530 return base;
531 }
532
533 static FILE *
534 output_channel(void)
535 {
536 return yflag ? stderr : stdout;
537 }
538
539 static void
540 verror_at(int msgid, const pos_t *pos, va_list ap)
541 {
542
543 if (is_suppressed[msgid])
544 return;
545
546 FILE *out = output_channel();
547 (void)fprintf(out, "%s(%d): error: ",
548 lbasename(pos->p_file), pos->p_line);
549 (void)vfprintf(out, msgs[msgid], ap);
550 (void)fprintf(out, " [%d]\n", msgid);
551 seen_error = true;
552 print_stack_trace();
553 }
554
555 static void
556 vwarning_at(int msgid, const pos_t *pos, va_list ap)
557 {
558
559 if (is_suppressed[msgid])
560 return;
561
562 debug_step("%s: lwarn=%d msgid=%d", __func__, lwarn, msgid);
563 if (lwarn == LWARN_NONE || lwarn == msgid)
564 /* this warning is suppressed by a LINTED comment */
565 return;
566
567 FILE *out = output_channel();
568 (void)fprintf(out, "%s(%d): warning: ",
569 lbasename(pos->p_file), pos->p_line);
570 (void)vfprintf(out, msgs[msgid], ap);
571 (void)fprintf(out, " [%d]\n", msgid);
572 seen_warning = true;
573 print_stack_trace();
574 }
575
576 static void
577 vmessage_at(int msgid, const pos_t *pos, va_list ap)
578 {
579
580 if (is_suppressed[msgid])
581 return;
582
583 FILE *out = output_channel();
584 (void)fprintf(out, "%s(%d): ",
585 lbasename(pos->p_file), pos->p_line);
586 (void)vfprintf(out, msgs[msgid], ap);
587 (void)fprintf(out, " [%d]\n", msgid);
588 print_stack_trace();
589 }
590
591 void
592 (error_at)(int msgid, const pos_t *pos, ...)
593 {
594 va_list ap;
595
596 va_start(ap, pos);
597 verror_at(msgid, pos, ap);
598 va_end(ap);
599 }
600
601 void
602 (error)(int msgid, ...)
603 {
604 va_list ap;
605
606 va_start(ap, msgid);
607 verror_at(msgid, &curr_pos, ap);
608 va_end(ap);
609 }
610
611 void
612 assert_failed(const char *file, int line, const char *func, const char *cond)
613 {
614
615 /*
616 * After encountering a parse error in the grammar, lint often does not
617 * properly clean up its data structures, especially in 'dcs', the
618 * stack of declaration levels. This often leads to assertion
619 * failures. These cases are not interesting though, as the purpose of
620 * lint is to check syntactically valid code. In such a case, exit
621 * gracefully. This allows a fuzzer like afl to focus on more
622 * interesting cases instead of reporting nonsense translation units
623 * like 'f=({e:;}' or 'v(const(char););e(v){'.
624 */
625 if (sytxerr > 0)
626 norecover();
627
628 (void)fflush(stdout);
629 (void)fprintf(stderr,
630 "lint: assertion \"%s\" failed in %s at %s:%d near %s:%d\n",
631 cond, func, file, line,
632 lbasename(curr_pos.p_file), curr_pos.p_line);
633 print_stack_trace();
634 (void)fflush(stdout);
635 abort();
636 }
637
638 void
639 (warning_at)(int msgid, const pos_t *pos, ...)
640 {
641 va_list ap;
642
643 va_start(ap, pos);
644 vwarning_at(msgid, pos, ap);
645 va_end(ap);
646 }
647
648 void
649 (warning)(int msgid, ...)
650 {
651 va_list ap;
652
653 va_start(ap, msgid);
654 vwarning_at(msgid, &curr_pos, ap);
655 va_end(ap);
656 }
657
658 void
659 (message_at)(int msgid, const pos_t *pos, ...)
660 {
661 va_list ap;
662
663 va_start(ap, pos);
664 vmessage_at(msgid, pos, ap);
665 va_end(ap);
666 }
667
668 void
669 (c99ism)(int msgid, ...)
670 {
671 va_list ap;
672
673 if (allow_c99)
674 return;
675
676 va_start(ap, msgid);
677 int severity = (!allow_gcc ? 1 : 0) + (!allow_trad ? 1 : 0);
678 if (severity == 2)
679 verror_at(msgid, &curr_pos, ap);
680 if (severity == 1)
681 vwarning_at(msgid, &curr_pos, ap);
682 va_end(ap);
683 }
684
685 void
686 (c11ism)(int msgid, ...)
687 {
688 va_list ap;
689
690 /* FIXME: C11 mode has nothing to do with GCC mode. */
691 if (allow_c11 || allow_gcc)
692 return;
693 va_start(ap, msgid);
694 verror_at(msgid, &curr_pos, ap);
695 va_end(ap);
696 }
697
698 void
699 (c23ism)(int msgid, ...)
700 {
701 va_list ap;
702
703 if (allow_c23)
704 return;
705 va_start(ap, msgid);
706 verror_at(msgid, &curr_pos, ap);
707 va_end(ap);
708 }
709
710 bool
711 (gnuism)(int msgid, ...)
712 {
713 va_list ap;
714 int severity = (!allow_gcc ? 1 : 0) +
715 (!allow_trad && !allow_c99 ? 1 : 0);
716
717 va_start(ap, msgid);
718 if (severity == 2)
719 verror_at(msgid, &curr_pos, ap);
720 if (severity == 1)
721 vwarning_at(msgid, &curr_pos, ap);
722 va_end(ap);
723 return severity > 0;
724 }
725
726
727 static const char *queries[] = {
728 "", /* unused, to make queries 1-based */
729 "implicit conversion from floating point '%s' to integer '%s'", // Q1
730 "cast from floating point '%s' to integer '%s'", // Q2
731 "implicit conversion changes sign from '%s' to '%s'", // Q3
732 "usual arithmetic conversion for '%s' from '%s' to '%s'", // Q4
733 "pointer addition has integer on the left-hand side", // Q5
734 "no-op cast from '%s' to '%s'", // Q6
735 "redundant cast from '%s' to '%s' before assignment", // Q7
736 "octal number '%.*s'", // Q8
737 "parenthesized return value", // Q9
738 "chained assignment with '%s' and '%s'", // Q10
739 "static variable '%s' in function", // Q11
740 "comma operator with types '%s' and '%s'", // Q12
741 "redundant 'extern' in function declaration of '%s'", // Q13
742 "comparison '%s' of 'char' with plain integer %d", // Q14
743 "implicit conversion from integer 0 to pointer '%s'", // Q15
744 "'%s' was declared 'static', now non-'static'", // Q16
745 "invisible character U+%04X in %s", // Q17
746 "const automatic variable '%s'", // Q18
747 "implicit conversion from integer '%s' to floating point '%s'", // Q19
748 "implicit narrowing conversion from void pointer to '%s'", // Q20
749 };
750
751 bool any_query_enabled; /* for optimizing non-query scenarios */
752 bool is_query_enabled[sizeof(queries) / sizeof(queries[0])];
753
754 void
755 (query_message)(int query_id, ...)
756 {
757
758 if (!is_query_enabled[query_id])
759 return;
760
761 va_list ap;
762 FILE *out = output_channel();
763 (void)fprintf(out, "%s(%d): ",
764 lbasename(curr_pos.p_file), curr_pos.p_line);
765 va_start(ap, query_id);
766 (void)vfprintf(out, queries[query_id], ap);
767 va_end(ap);
768 (void)fprintf(out, " [Q%d]\n", query_id);
769 print_stack_trace();
770 }
771
772 void
773 enable_queries(const char *p)
774 {
775 char *end;
776
777 for (; ch_isdigit(*p); p = end + 1) {
778 unsigned long id = strtoul(p, &end, 10);
779 if ((*end != '\0' && *end != ',') ||
780 id >= sizeof(queries) / sizeof(queries[0]) ||
781 queries[id][0] == '\0')
782 break;
783
784 any_query_enabled = true;
785 is_query_enabled[id] = true;
786
787 if (*end == '\0')
788 return;
789 }
790 errx(1, "invalid query ID '%.*s'", (int)strcspn(p, ","), p);
791 }
792