https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106319
Bug ID: 106319 Summary: False positives from -Wanalyzer-va-arg-type-mismatch on int promotion Product: gcc Version: 12.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: analyzer Assignee: dmalcolm at gcc dot gnu.org Reporter: dmalcolm at gcc dot gnu.org Target Milestone: --- Consider e.g.: static void __attribute__((noinline)) __analyzer_consume_n_ints (int num, ...) { __builtin_va_list ap; __builtin_va_start (ap, num); int i, v; for (i = 0; i < num; i++) v = __builtin_va_arg (ap, int); __builtin_va_end (ap); } void test_int (int x) { __analyzer_consume_n_ints (1, x); } void test_3_ints (int x, int y, int z) { __analyzer_consume_n_ints (3, x, y, z); } void test_short (short s) { __analyzer_consume_n_ints (1, s); } Currently we emit this false postive: ../../src/gcc/testsuite/gcc.dg/analyzer/stdarg-types-3.c: In function ‘__analyzer_consume_n_ints’: ../../src/gcc/testsuite/gcc.dg/analyzer/stdarg-types-3.c:9:7: warning: ‘va_arg’ expected ‘int’ but received ‘short int’ for variadic argument 1 of ‘ap’ [CWE-686] [-Wanalyzer-va-arg-type-mismatch] 9 | v = __builtin_va_arg (ap, int); | ~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~ ‘test_short’: events 1-2 | | 24 | void test_short (short s) | | ^~~~~~~~~~ | | | | | (1) entry to ‘test_short’ | 25 | { | 26 | __analyzer_consume_n_ints (1, s); | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (2) calling ‘__analyzer_consume_n_ints’ from ‘test_short’ with 1 variadic argument | +--> ‘__analyzer_consume_n_ints’: events 3-6 | | 2 | __analyzer_consume_n_ints (int num, ...) | | ^~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (3) entry to ‘__analyzer_consume_n_ints’ |...... | 8 | for (i = 0; i < num; i++) | | ~~~~~~~ | | | | | (4) following ‘true’ branch (when ‘i < num’)... | 9 | v = __builtin_va_arg (ap, int); | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (5) ...to here | | (6) ‘va_arg’ expected ‘int’ but received ‘short int’ for variadic argument 1 of ‘ap’ | Reproducer: https://godbolt.org/z/6xrvErbov >From https://en.cppreference.com/w/c/language/variadic : "At the function call, each argument that is a part of the variable argument list undergoes special implicit conversions known as default argument promotions." From https://en.cppreference.com/w/c/language/conversion#Default_argument_promotions : "In a function call expression when the call is made to 1) a function without a prototype 2) a variadic function, where the argument expression is one of the trailing arguments that are matched against the ellipsis parameter Each argument of integer type undergoes integer promotion (see below), and each argument of type float is implicitly converted to the type double" >From https://en.cppreference.com/w/c/language/conversion#Integer_promotions : "Integer promotion is the implicit conversion of a value of any integer type with rank less or equal to rank of int or of a bit field of type _Bool, int, signed int, unsigned int, to the value of type int or unsigned int. If int can represent the entire range of values of the original type (or the range of values of the original bit field), the value is converted to type int. Otherwise the value is converted to unsigned int." Seen on Linux kernel e.g. in drivers/input/keyboard/lm8323.c, where we falsely complain in lm8323_write_pwm_one about: 418 | lm8323_write(pwm->chip, 4, with 4 args: int, int, int, u16; the u16 should be promoted to int.