1/* $NetBSD: err.c,v 1.244 2024/05/12 18:49:36 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.244 2024/05/12 18:49:36 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 50bool seen_error; 51bool seen_warning; 52 53/* number of syntax errors */ 54int sytxerr; 55 56 57static 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 to unsigned type", // 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 with negative constant", // 221 280 "conversion of negative constant to unsigned type", // 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 to unsigned type, 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}; 439 440static bool is_suppressed[sizeof(msgs) / sizeof(msgs[0])]; 441 442static struct include_level { 443 const char *filename; 444 int lineno; 445 struct include_level *by; 446} *includes; 447 448void 449suppress_messages(const char *p) 450{ 451 char *end; 452 453 for (; ch_isdigit(*p); p = end + 1) { 454 unsigned long id = strtoul(p, &end, 10); 455 if ((*end != '\0' && *end != ',') || 456 id >= sizeof(msgs) / sizeof(msgs[0]) || 457 msgs[id][0] == '\0') 458 break; 459 460 is_suppressed[id] = true; 461 462 if (*end == '\0') 463 return; 464 } 465 errx(1, "invalid message ID '%.*s'", (int)strcspn(p, ","), p); 466} 467 468void 469update_location(const char *filename, int lineno, bool is_begin, bool is_end) 470{ 471 struct include_level *top; 472 473 top = includes; 474 if (is_begin && top != NULL) 475 top->lineno = curr_pos.p_line; 476 477 if (top == NULL || is_begin) { 478 top = xmalloc(sizeof(*top)); 479 top->filename = filename; 480 top->lineno = lineno; 481 top->by = includes; 482 includes = top; 483 } else { 484 if (is_end) { 485 includes = top->by; 486 free(top); 487 top = includes; 488 } 489 if (top != NULL) { 490 top->filename = filename; 491 top->lineno = lineno; 492 } 493 } 494} 495 496static void 497print_stack_trace(void) 498{ 499 const struct include_level *top; 500 501 if ((top = includes) == NULL) 502 return; 503 /* 504 * Skip the innermost include level since it is already listed in the 505 * diagnostic itself. Furthermore, its lineno is the line number of 506 * the last '#' line, not the current line. 507 */ 508 for (top = top->by; top != NULL; top = top->by) 509 printf("\tincluded from %s(%d)\n", top->filename, top->lineno); 510} 511 512/* 513 * If Fflag is not set, lbasename() returns a pointer to the last 514 * component of the path, otherwise it returns the argument. 515 */ 516static const char * 517lbasename(const char *path) 518{ 519 520 if (Fflag) 521 return path; 522 523 const char *base = path; 524 for (const char *p = path; *p != '\0'; p++) 525 if (*p == '/') 526 base = p + 1; 527 return base; 528} 529 530static FILE * 531output_channel(void) 532{ 533 return yflag ? stderr : stdout; 534} 535 536static void 537verror_at(int msgid, const pos_t *pos, va_list ap) 538{ 539 540 if (is_suppressed[msgid]) 541 return; 542 543 FILE *out = output_channel(); 544 (void)fprintf(out, "%s(%d): error: ", 545 lbasename(pos->p_file), pos->p_line); 546 (void)vfprintf(out, msgs[msgid], ap); 547 (void)fprintf(out, " [%d]\n", msgid); 548 seen_error = true; 549 print_stack_trace(); 550} 551 552static void 553vwarning_at(int msgid, const pos_t *pos, va_list ap) 554{ 555 556 if (is_suppressed[msgid]) 557 return; 558 559 debug_step("%s: lwarn=%d msgid=%d", __func__, lwarn, msgid); 560 if (lwarn == LWARN_NONE || lwarn == msgid) 561 /* this warning is suppressed by a LINTED comment */ 562 return; 563 564 FILE *out = output_channel(); 565 (void)fprintf(out, "%s(%d): warning: ", 566 lbasename(pos->p_file), pos->p_line); 567 (void)vfprintf(out, msgs[msgid], ap); 568 (void)fprintf(out, " [%d]\n", msgid); 569 seen_warning = true; 570 print_stack_trace(); 571} 572 573static void 574vmessage_at(int msgid, const pos_t *pos, va_list ap) 575{ 576 577 if (is_suppressed[msgid]) 578 return; 579 580 FILE *out = output_channel(); 581 (void)fprintf(out, "%s(%d): ", 582 lbasename(pos->p_file), pos->p_line); 583 (void)vfprintf(out, msgs[msgid], ap); 584 (void)fprintf(out, " [%d]\n", msgid); 585 print_stack_trace(); 586} 587 588void 589(error_at)(int msgid, const pos_t *pos, ...) 590{ 591 va_list ap; 592 593 va_start(ap, pos); 594 verror_at(msgid, pos, ap); 595 va_end(ap); 596} 597 598void 599(error)(int msgid, ...) 600{ 601 va_list ap; 602 603 va_start(ap, msgid); 604 verror_at(msgid, &curr_pos, ap); 605 va_end(ap); 606} 607 608void 609assert_failed(const char *file, int line, const char *func, const char *cond) 610{ 611 612 /* 613 * After encountering a parse error in the grammar, lint often does not 614 * properly clean up its data structures, especially in 'dcs', the 615 * stack of declaration levels. This often leads to assertion 616 * failures. These cases are not interesting though, as the purpose of 617 * lint is to check syntactically valid code. In such a case, exit 618 * gracefully. This allows a fuzzer like afl to focus on more 619 * interesting cases instead of reporting nonsense translation units 620 * like 'f=({e:;}' or 'v(const(char););e(v){'. 621 */ 622 if (sytxerr > 0) 623 norecover(); 624 625 (void)fflush(stdout); 626 (void)fprintf(stderr, 627 "lint: assertion \"%s\" failed in %s at %s:%d near %s:%d\n", 628 cond, func, file, line, 629 lbasename(curr_pos.p_file), curr_pos.p_line); 630 print_stack_trace(); 631 (void)fflush(stdout); 632 abort(); 633} 634 635void 636(warning_at)(int msgid, const pos_t *pos, ...) 637{ 638 va_list ap; 639 640 va_start(ap, pos); 641 vwarning_at(msgid, pos, ap); 642 va_end(ap); 643} 644 645void 646(warning)(int msgid, ...) 647{ 648 va_list ap; 649 650 va_start(ap, msgid); 651 vwarning_at(msgid, &curr_pos, ap); 652 va_end(ap); 653} 654 655void 656(message_at)(int msgid, const pos_t *pos, ...) 657{ 658 va_list ap; 659 660 va_start(ap, pos); 661 vmessage_at(msgid, pos, ap); 662 va_end(ap); 663} 664 665void 666(c99ism)(int msgid, ...) 667{ 668 va_list ap; 669 670 if (allow_c99) 671 return; 672 673 va_start(ap, msgid); 674 int severity = (!allow_gcc ? 1 : 0) + (!allow_trad ? 1 : 0); 675 if (severity == 2) 676 verror_at(msgid, &curr_pos, ap); 677 if (severity == 1) 678 vwarning_at(msgid, &curr_pos, ap); 679 va_end(ap); 680} 681 682void 683(c11ism)(int msgid, ...) 684{ 685 va_list ap; 686 687 /* FIXME: C11 mode has nothing to do with GCC mode. */ 688 if (allow_c11 || allow_gcc) 689 return; 690 va_start(ap, msgid); 691 verror_at(msgid, &curr_pos, ap); 692 va_end(ap); 693} 694 695void 696(c23ism)(int msgid, ...) 697{ 698 va_list ap; 699 700 if (allow_c23) 701 return; 702 va_start(ap, msgid); 703 verror_at(msgid, &curr_pos, ap); 704 va_end(ap); 705} 706 707bool 708(gnuism)(int msgid, ...) 709{ 710 va_list ap; 711 int severity = (!allow_gcc ? 1 : 0) + 712 (!allow_trad && !allow_c99 ? 1 : 0); 713 714 va_start(ap, msgid); 715 if (severity == 2) 716 verror_at(msgid, &curr_pos, ap); 717 if (severity == 1) 718 vwarning_at(msgid, &curr_pos, ap); 719 va_end(ap); 720 return severity > 0; 721} 722 723 724static const char *queries[] = { 725 "", /* unused, to make queries 1-based */ 726 "implicit conversion from floating point '%s' to integer '%s'", // Q1 727 "cast from floating point '%s' to integer '%s'", // Q2 728 "implicit conversion changes sign from '%s' to '%s'", // Q3 729 "usual arithmetic conversion for '%s' from '%s' to '%s'", // Q4 730 "pointer addition has integer on the left-hand side", // Q5 731 "no-op cast from '%s' to '%s'", // Q6 732 "redundant cast from '%s' to '%s' before assignment", // Q7 733 "octal number '%.*s'", // Q8 734 "parenthesized return value", // Q9 735 "chained assignment with '%s' and '%s'", // Q10 736 "static variable '%s' in function", // Q11 737 "comma operator with types '%s' and '%s'", // Q12 738 "redundant 'extern' in function declaration of '%s'", // Q13 739 "comparison '%s' of 'char' with plain integer %d", // Q14 740 "implicit conversion from integer 0 to pointer '%s'", // Q15 741 "'%s' was declared 'static', now non-'static'", // Q16 742 "invisible character U+%04X in %s", // Q17 743 "const automatic variable '%s'", // Q18 744 "implicit conversion from integer '%s' to floating point '%s'", // Q19 745 "implicit narrowing conversion from void pointer to '%s'", // Q20 746}; 747 748bool any_query_enabled; /* for optimizing non-query scenarios */ 749bool is_query_enabled[sizeof(queries) / sizeof(queries[0])]; 750 751void 752(query_message)(int query_id, ...) 753{ 754 755 if (!is_query_enabled[query_id]) 756 return; 757 758 va_list ap; 759 FILE *out = output_channel(); 760 (void)fprintf(out, "%s(%d): ", 761 lbasename(curr_pos.p_file), curr_pos.p_line); 762 va_start(ap, query_id); 763 (void)vfprintf(out, queries[query_id], ap); 764 va_end(ap); 765 (void)fprintf(out, " [Q%d]\n", query_id); 766 print_stack_trace(); 767} 768 769void 770enable_queries(const char *p) 771{ 772 char *end; 773 774 for (; ch_isdigit(*p); p = end + 1) { 775 unsigned long id = strtoul(p, &end, 10); 776 if ((*end != '\0' && *end != ',') || 777 id >= sizeof(queries) / sizeof(queries[0]) || 778 queries[id][0] == '\0') 779 break; 780 781 any_query_enabled = true; 782 is_query_enabled[id] = true; 783 784 if (*end == '\0') 785 return; 786 } 787 errx(1, "invalid query ID '%.*s'", (int)strcspn(p, ","), p); 788} 789