1 /*        $NetBSD: err.c,v 1.272 2025/05/04 08:37:09 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.272 2025/05/04 08:37:09 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           "invalid 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           "invalid 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 invalid type '%s'",                                 // 15
74           "array of function is invalid",                                                 // 16
75           "null dimension",                                                     // 17
76           "invalid 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           "invalid bit-field type '%s'",                                                  // 35
94           "invalid bit-field size: %d",                                         // 36
95           "zero size bit-field",                                                          // 37
96           "function invalid 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           "constant %s too large for 'int'",                                    // 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 requires C90 or later",                                          // 81
140           "\\x requires C90 or later",                                          // 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 with type '%s'", // 86
145           "static '%s' hides external declaration with type '%s'",    // 87
146           "typedef '%s' hides external declaration with type '%s'",   // 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 invalid storage class",                            // 94
153           "declaration of '%s' hides earlier one",                              // 95
154           "cannot dereference non-pointer type '%s'",                           // 96
155           "suffix 'U' requires C90 or later",                                   // 97
156           "suffixes 'F' or 'L' require C90 or later",                           // 98
157           "'%s' undefined",                                                     // 99
158           "unary '+' requires C90 or later",                                    // 100
159           "type '%s' does not have member '%s'",                                // 101
160           "invalid 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 invalid 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           "invalid 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           "invalid combination of %s '%s' and %s '%s', op '%s'",                // 123
182           "invalid 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           "",                           /* no longer used */                              // 127
186           "operator '%s' discards '%s' from '%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           "invalid 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           "",                           /* no longer used */                              // 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           "possible precedence confusion between '%s' and '%s'",                // 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           "'%s' discards '%s' from '%s'",                                                 // 182
241           "invalid combination of %s '%s' and %s '%s' for '%s'",                // 183
242           "invalid 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           "automatic aggregate initialization requires C90 or later", // 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           "'%s' statement not reached",                                         // 193
252           "label '%s' redefined",                                                         // 194
253           "case not in switch",                                                           // 195
254           "case label is converted from '%s' to '%s'",                          // 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 require C90 or later",                          // 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 requires C90 or later",            // 238
297           "",                           /* no longer used */                              // 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           "invalid 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 unrelated '%s'",                           // 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 a character constant requires C90 or later",   // 262
321           "\\? requires C90 or later",                                          // 263
322           "\\v requires C90 or later",                                          // 264
323           "%s does not support 'long long'",                                    // 265
324           "'long double' requires C90 or later",                                // 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 require C90 or later",                           // 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 invalid 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 %s 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 for '%s' of type '%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 '%s' always evaluates to '%s'", // 382
441           "passing '%s' as argument %d to '%s' discards '%s'",                  // 383
442           "function definition for '%s' with identifier list is obsolete in C23", // 384
443           "do-while macro '%.*s' ends with semicolon",                          // 385
444 };
445 
446 static bool is_suppressed[sizeof(msgs) / sizeof(msgs[0])];
447 
448 static struct include_level {
449           const char *filename;
450           int lineno;
451           struct include_level *by;
452 } *includes;
453 
454 void
suppress_messages(const char * p)455 suppress_messages(const char *p)
456 {
457           char *end;
458 
459           for (; ch_isdigit(*p); p = end + 1) {
460                     unsigned long id = strtoul(p, &end, 10);
461                     if ((*end != '\0' && *end != ',') ||
462                         id >= sizeof(msgs) / sizeof(msgs[0]) ||
463                         msgs[id][0] == '\0')
464                               break;
465 
466                     is_suppressed[id] = true;
467 
468                     if (*end == '\0')
469                               return;
470           }
471           errx(1, "invalid message ID '%.*s'", (int)strcspn(p, ","), p);
472 }
473 
474 void
update_location(const char * filename,int lineno,bool is_begin,bool is_end)475 update_location(const char *filename, int lineno, bool is_begin, bool is_end)
476 {
477           struct include_level *top;
478 
479           top = includes;
480           if (is_begin && top != NULL)
481                     top->lineno = curr_pos.p_line;
482 
483           if (top == NULL || is_begin) {
484                     top = xmalloc(sizeof(*top));
485                     top->filename = filename;
486                     top->lineno = lineno;
487                     top->by = includes;
488                     includes = top;
489           } else {
490                     if (is_end) {
491                               includes = top->by;
492                               free(top);
493                               top = includes;
494                     }
495                     if (top != NULL) {
496                               top->filename = filename;
497                               top->lineno = lineno;
498                     }
499           }
500 }
501 
502 static void
print_stack_trace(void)503 print_stack_trace(void)
504 {
505           const struct include_level *top;
506 
507           if ((top = includes) == NULL)
508                     return;
509           /*
510            * Skip the innermost include level since it is already listed in the
511            * diagnostic itself.  Furthermore, its lineno is the line number of
512            * the last '#' line, not the current line.
513            */
514           for (top = top->by; top != NULL; top = top->by)
515                     printf("\tincluded from %s(%d)\n", top->filename, top->lineno);
516 }
517 
518 /*
519  * If Fflag is not set, lbasename() returns a pointer to the last
520  * component of the path, otherwise it returns the argument.
521  */
522 static const char *
lbasename(const char * path)523 lbasename(const char *path)
524 {
525 
526           if (Fflag)
527                     return path;
528 
529           const char *base = path;
530           for (const char *p = path; *p != '\0'; p++)
531                     if (*p == '/')
532                               base = p + 1;
533           return base;
534 }
535 
536 static FILE *
output_channel(void)537 output_channel(void)
538 {
539           return yflag ? stderr : stdout;
540 }
541 
542 static void
verror_at(int msgid,const pos_t * pos,va_list ap)543 verror_at(int msgid, const pos_t *pos, va_list ap)
544 {
545 
546           if (is_suppressed[msgid])
547                     return;
548 
549           FILE *out = output_channel();
550           (void)fprintf(out, "%s(%d): error: ",
551               lbasename(pos->p_file), pos->p_line);
552           (void)vfprintf(out, msgs[msgid], ap);
553           (void)fprintf(out, " [%d]\n", msgid);
554           seen_error = true;
555           print_stack_trace();
556 }
557 
558 static void
vwarning_at(int msgid,const pos_t * pos,va_list ap)559 vwarning_at(int msgid, const pos_t *pos, va_list ap)
560 {
561 
562           if (is_suppressed[msgid])
563                     return;
564 
565           debug_step("%s: lwarn=%d msgid=%d", __func__, lwarn, msgid);
566           if (lwarn == LWARN_NONE || lwarn == msgid)
567                     /* this warning is suppressed by a LINTED comment */
568                     return;
569 
570           FILE *out = output_channel();
571           (void)fprintf(out, "%s(%d): warning: ",
572               lbasename(pos->p_file), pos->p_line);
573           (void)vfprintf(out, msgs[msgid], ap);
574           (void)fprintf(out, " [%d]\n", msgid);
575           seen_warning = true;
576           print_stack_trace();
577 }
578 
579 static void
vmessage_at(int msgid,const pos_t * pos,va_list ap)580 vmessage_at(int msgid, const pos_t *pos, va_list ap)
581 {
582 
583           if (is_suppressed[msgid])
584                     return;
585 
586           FILE *out = output_channel();
587           (void)fprintf(out, "%s(%d): ",
588               lbasename(pos->p_file), pos->p_line);
589           (void)vfprintf(out, msgs[msgid], ap);
590           (void)fprintf(out, " [%d]\n", msgid);
591           print_stack_trace();
592 }
593 
594 void
595 (error_at)(int msgid, const pos_t *pos, ...)
596 {
597           va_list ap;
598 
599           va_start(ap, pos);
600           verror_at(msgid, pos, ap);
601           va_end(ap);
602 }
603 
604 void
605 (error)(int msgid, ...)
606 {
607           va_list ap;
608 
609           va_start(ap, msgid);
610           verror_at(msgid, &curr_pos, ap);
611           va_end(ap);
612 }
613 
614 void
assert_failed(const char * file,int line,const char * func,const char * cond)615 assert_failed(const char *file, int line, const char *func, const char *cond)
616 {
617 
618 #if LINT_FUZZING
619           /*
620            * After encountering a parse error in the grammar, lint often does not
621            * properly clean up its data structures, especially in 'dcs', the
622            * stack of declaration levels.  This often leads to assertion
623            * failures.  These cases are not interesting though, as the purpose of
624            * lint is to check syntactically valid code.  In such a case, exit
625            * gracefully.  This allows a fuzzer like afl to focus on more
626            * interesting cases instead of reporting nonsense translation units
627            * like 'f=({e:;}' or 'v(const(char););e(v){'.
628            */
629           if (sytxerr > 0)
630                     norecover();
631 #endif
632 
633           (void)fflush(stdout);
634           (void)fprintf(stderr,
635               "lint: assertion \"%s\" failed in %s at %s:%d near %s:%d\n",
636               cond, func, file, line,
637               lbasename(curr_pos.p_file), curr_pos.p_line);
638           print_stack_trace();
639           (void)fflush(stdout);
640           abort();
641 }
642 
643 void
644 (warning_at)(int msgid, const pos_t *pos, ...)
645 {
646           va_list ap;
647 
648           va_start(ap, pos);
649           vwarning_at(msgid, pos, ap);
650           va_end(ap);
651 }
652 
653 void
654 (warning)(int msgid, ...)
655 {
656           va_list ap;
657 
658           va_start(ap, msgid);
659           vwarning_at(msgid, &curr_pos, ap);
660           va_end(ap);
661 }
662 
663 void
664 (message_at)(int msgid, const pos_t *pos, ...)
665 {
666           va_list ap;
667 
668           va_start(ap, pos);
669           vmessage_at(msgid, pos, ap);
670           va_end(ap);
671 }
672 
673 void
674 (c99ism)(int msgid, ...)
675 {
676           va_list ap;
677 
678           if (allow_c99)
679                     return;
680 
681           va_start(ap, msgid);
682           int severity = (!allow_gcc ? 1 : 0) + (!allow_trad ? 1 : 0);
683           if (severity == 2)
684                     verror_at(msgid, &curr_pos, ap);
685           if (severity == 1)
686                     vwarning_at(msgid, &curr_pos, ap);
687           va_end(ap);
688 }
689 
690 void
691 (c11ism)(int msgid, ...)
692 {
693           va_list ap;
694 
695           /* FIXME: C11 mode has nothing to do with GCC mode. */
696           if (allow_c11 || allow_gcc)
697                     return;
698           va_start(ap, msgid);
699           verror_at(msgid, &curr_pos, ap);
700           va_end(ap);
701 }
702 
703 void
704 (c23ism)(int msgid, ...)
705 {
706           va_list ap;
707 
708           if (allow_c23)
709                     return;
710           va_start(ap, msgid);
711           verror_at(msgid, &curr_pos, ap);
712           va_end(ap);
713 }
714 
715 bool
716 (gnuism)(int msgid, ...)
717 {
718           va_list ap;
719           int severity = (!allow_gcc ? 1 : 0) +
720               (!allow_trad && !allow_c99 ? 1 : 0);
721 
722           va_start(ap, msgid);
723           if (severity == 2)
724                     verror_at(msgid, &curr_pos, ap);
725           if (severity == 1)
726                     vwarning_at(msgid, &curr_pos, ap);
727           va_end(ap);
728           return severity > 0;
729 }
730 
731 
732 static const char *queries[] = {
733           "",                           /* unused, to make queries 1-based */
734           "implicit conversion from floating point '%s' to integer '%s'",       // Q1
735           "cast from floating point '%s' to integer '%s'",            // Q2
736           "implicit conversion changes sign from '%s' to '%s'",                 // Q3
737           "usual arithmetic conversion for '%s' from '%s' to '%s'",   // Q4
738           "pointer addition has integer on the left-hand side",                 // Q5
739           "no-op cast from '%s' to '%s'",                                                 // Q6
740           "redundant cast from '%s' to '%s' before assignment",                 // Q7
741           "octal number '%.*s'",                                                          // Q8
742           "parenthesized return value",                                         // Q9
743           "chained assignment with '%s' and '%s'",                              // Q10
744           "static variable '%s' in function",                                   // Q11
745           "comma operator with types '%s' and '%s'",                            // Q12
746           "redundant 'extern' in function declaration of '%s'",                 // Q13
747           "comparison '%s' of 'char' with plain integer %d",                    // Q14
748           "implicit conversion from integer 0 to pointer '%s'",                 // Q15
749           "'%s' was declared 'static', now non-'static'",                       // Q16
750           "invisible character U+%04X in %s",                                   // Q17
751           "const automatic variable '%s'",                                      // Q18
752           "implicit conversion from integer '%s' to floating point '%s'",       // Q19
753           "implicit narrowing conversion from void pointer to '%s'",  // Q20
754           "typedef '%s' of struct type '%s'",                                   // Q21
755           "typedef '%s' of union type '%s'",                                    // Q22
756           "typedef '%s' of pointer to struct type '%s'",                        // Q23
757           "typedef '%s' of pointer to union type '%s'",                         // Q24
758 };
759 
760 // Omit any expensive computations in the default mode where none of the
761 // queries are enabled.  Function calls in message details don't need to be
762 // guarded by this flag, as that happens in the query_message macro already.
763 bool any_query_enabled;
764 bool is_query_enabled[sizeof(queries) / sizeof(queries[0])];
765 
766 void
767 (query_message)(int query_id, ...)
768 {
769 
770           if (!is_query_enabled[query_id])
771                     return;
772 
773           va_list ap;
774           FILE *out = output_channel();
775           (void)fprintf(out, "%s(%d): ",
776               lbasename(curr_pos.p_file), curr_pos.p_line);
777           va_start(ap, query_id);
778           (void)vfprintf(out, queries[query_id], ap);
779           va_end(ap);
780           (void)fprintf(out, " [Q%d]\n", query_id);
781           print_stack_trace();
782 }
783 
784 void
enable_queries(const char * p)785 enable_queries(const char *p)
786 {
787           char *end;
788 
789           for (; ch_isdigit(*p); p = end + 1) {
790                     unsigned long id = strtoul(p, &end, 10);
791                     if ((*end != '\0' && *end != ',') ||
792                         id >= sizeof(queries) / sizeof(queries[0]) ||
793                         queries[id][0] == '\0')
794                               break;
795 
796                     any_query_enabled = true;
797                     is_query_enabled[id] = true;
798 
799                     if (*end == '\0')
800                               return;
801           }
802           errx(1, "invalid query ID '%.*s'", (int)strcspn(p, ","), p);
803 }
804