False positive -Wconstant-conversion after signed char array enablement
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
After commit [a5ef934a8d29](https://github.com/llvm/llvm-project/commit/a5ef934a8d295dc03be3960f2b3744ec2e53238e) ("[clang] Warn on signed char array constant conversion (#203792)"), there is an instance from [an optimization change in Linux kernel v6.19 and newer](https://git.kernel.org/linus/c4eb7ad32eab13ba64cc452c6f43d518b63f5e03), which can be independently reproduced:
```c
enum base64_variant {
BASE64_STD, /* RFC 4648 (standard) */
BASE64_URLSAFE, /* RFC 4648 (base64url) */
BASE64_IMAP, /* RFC 3501 */
};
/*
* Initialize the base64 reverse mapping for a single character
* This macro maps a character to its corresponding base64 value,
* returning -1 if the character is invalid.
* char 'A'-'Z' maps to 0-25, 'a'-'z' maps to 26-51, '0'-'9' maps to 52-61,
* ch_62 maps to 62, ch_63 maps to 63, and other characters return -1
*/
#define INIT_1(v, ch_62, ch_63) \
[v] = (v) >= 'A' && (v) <= 'Z' ? (v) - 'A' \
: (v) >= 'a' && (v) <= 'z' ? (v) - 'a' + 26 \
: (v) >= '0' && (v) <= '9' ? (v) - '0' + 52 \
: (v) == (ch_62) ? 62 : (v) == (ch_63) ? 63 : -1
/*
* Recursive macros to generate multiple Base64 reverse mapping table entries.
* Each macro generates a sequence of entries in the lookup table:
* INIT_2 generates 2 entries, INIT_4 generates 4, INIT_8 generates 8, and so on up to INIT_32.
*/
#define INIT_2(v, ...) INIT_1(v, __VA_ARGS__), INIT_1((v) + 1, __VA_ARGS__)
#define INIT_4(v, ...) INIT_2(v, __VA_ARGS__), INIT_2((v) + 2, __VA_ARGS__)
#define INIT_8(v, ...) INIT_4(v, __VA_ARGS__), INIT_4((v) + 4, __VA_ARGS__)
#define INIT_16(v, ...) INIT_8(v, __VA_ARGS__), INIT_8((v) + 8, __VA_ARGS__)
#define INIT_32(v, ...) INIT_16(v, __VA_ARGS__), INIT_16((v) + 16, __VA_ARGS__)
#define BASE64_REV_INIT(ch_62, ch_63) { \
[0 ... 0x1f] = -1, \
INIT_32(0x20, ch_62, ch_63), \
INIT_32(0x40, ch_62, ch_63), \
INIT_32(0x60, ch_62, ch_63), \
[0x80 ... 0xff] = -1 }
static const signed char base64_rev_maps[][256] __attribute__((__unused__)) = {
[BASE64_STD] = BASE64_REV_INIT('+', '/'),
[BASE64_URLSAFE] = BASE64_REV_INIT('-', '_'),
[BASE64_IMAP] = BASE64_REV_INIT('+', ',')
};
```
```
$ clang -fsyntax-only -Wconstant-conversion test.c
test.c:41:21: warning: implicit conversion from 'int' to 'signed char' changes value from 131 to -125 [-Wconstant-conversion]
41 | [BASE64_IMAP] = BASE64_REV_INIT('+', ',')
| ^~~~~~~~~~~~~~~~~~~~~~~~~
test.c:35:5: note: expanded from macro 'BASE64_REV_INIT'
31 | #define BASE64_REV_INIT(ch_62, ch_63) { \
| ~
32 | [0 ... 0x1f] = -1, \
33 | INIT_32(0x20, ch_62, ch_63), \
34 | INIT_32(0x40, ch_62, ch_63), \
35 | INIT_32(0x60, ch_62, ch_63), \
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~
test.c:29:50: note: expanded from macro 'INIT_32'
29 | #define INIT_32(v, ...) INIT_16(v, __VA_ARGS__), INIT_16((v) + 16, __VA_ARGS__)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test.c:28:49: note: expanded from macro 'INIT_16'
28 | #define INIT_16(v, ...) INIT_8(v, __VA_ARGS__), INIT_8((v) + 8, __VA_ARGS__)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
note: (skipping 1 expansions in backtrace; use -fmacro-backtrace-limit=0 to see all)
test.c:26:48: note: expanded from macro 'INIT_4'
26 | #define INIT_4(v, ...) INIT_2(v, __VA_ARGS__), INIT_2((v) + 2, __VA_ARGS__)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
test.c:25:48: note: expanded from macro 'INIT_2'
25 | #define INIT_2(v, ...) INIT_1(v, __VA_ARGS__), INIT_1((v) + 1, __VA_ARGS__)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
test.c:17:48: note: expanded from macro 'INIT_1'
17 | : (v) >= '0' && (v) <= '9' ? (v) - '0' + 52 \
| ~~~~~~~~~~^~~~
test.c:41:21: warning: implicit conversion from 'int' to 'signed char' changes value from 130 to -126 [-Wconstant-conversion]
41 | [BASE64_IMAP] = BASE64_REV_INIT('+', ',')
| ^~~~~~~~~~~~~~~~~~~~~~~~~
test.c:35:5: note: expanded from macro 'BASE64_REV_INIT'
31 | #define BASE64_REV_INIT(ch_62, ch_63) { \
| ~
32 | [0 ... 0x1f] = -1, \
33 | INIT_32(0x20, ch_62, ch_63), \
34 | INIT_32(0x40, ch_62, ch_63), \
35 | INIT_32(0x60, ch_62, ch_63), \
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~
test.c:29:50: note: expanded from macro 'INIT_32'
29 | #define INIT_32(v, ...) INIT_16(v, __VA_ARGS__), INIT_16((v) + 16, __VA_ARGS__)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test.c:28:49: note: expanded from macro 'INIT_16'
28 | #define INIT_16(v, ...) INIT_8(v, __VA_ARGS__), INIT_8((v) + 8, __VA_ARGS__)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
note: (skipping 1 expansions in backtrace; use -fmacro-backtrace-limit=0 to see all)
test.c:26:48: note: expanded from macro 'INIT_4'
26 | #define INIT_4(v, ...) INIT_2(v, __VA_ARGS__), INIT_2((v) + 2, __VA_ARGS__)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
test.c:25:24: note: expanded from macro 'INIT_2'
25 | #define INIT_2(v, ...) INIT_1(v, __VA_ARGS__), INIT_1((v) + 1, __VA_ARGS__)
| ^~~~~~~~~~~~~~~~~~~~~~
test.c:17:48: note: expanded from macro 'INIT_1'
17 | : (v) >= '0' && (v) <= '9' ? (v) - '0' + 52 \
| ~~~~~~~~~~^~~~
test.c:41:21: warning: implicit conversion from 'int' to 'signed char' changes value from 129 to -127 [-Wconstant-conversion]
41 | [BASE64_IMAP] = BASE64_REV_INIT('+', ',')
| ^~~~~~~~~~~~~~~~~~~~~~~~~
test.c:35:5: note: expanded from macro 'BASE64_REV_INIT'
31 | #define BASE64_REV_INIT(ch_62, ch_63) { \
| ~
32 | [0 ... 0x1f] = -1, \
33 | INIT_32(0x20, ch_62, ch_63), \
34 | INIT_32(0x40, ch_62, ch_63), \
35 | INIT_32(0x60, ch_62, ch_63), \
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~
test.c:29:50: note: expanded from macro 'INIT_32'
29 | #define INIT_32(v, ...) INIT_16(v, __VA_ARGS__), INIT_16((v) + 16, __VA_ARGS__)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test.c:28:49: note: expanded from macro 'INIT_16'
28 | #define INIT_16(v, ...) INIT_8(v, __VA_ARGS__), INIT_8((v) + 8, __VA_ARGS__)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
note: (skipping 1 expansions in backtrace; use -fmacro-backtrace-limit=0 to see all)
test.c:26:24: note: expanded from macro 'INIT_4'
26 | #define INIT_4(v, ...) INIT_2(v, __VA_ARGS__), INIT_2((v) + 2, __VA_ARGS__)
| ^~~~~~~~~~~~~~~~~~~~~~
test.c:25:48: note: expanded from macro 'INIT_2'
25 | #define INIT_2(v, ...) INIT_1(v, __VA_ARGS__), INIT_1((v) + 1, __VA_ARGS__)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
test.c:17:48: note: expanded from macro 'INIT_1'
17 | : (v) >= '0' && (v) <= '9' ? (v) - '0' + 52 \
| ~~~~~~~~~~^~~~
test.c:41:21: warning: implicit conversion from 'int' to 'signed char' changes value from 128 to -128 [-Wconstant-conversion]
41 | [BASE64_IMAP] = BASE64_REV_INIT('+', ',')
| ^~~~~~~~~~~~~~~~~~~~~~~~~
test.c:35:5: note: expanded from macro 'BASE64_REV_INIT'
31 | #define BASE64_REV_INIT(ch_62, ch_63) { \
| ~
32 | [0 ... 0x1f] = -1, \
33 | INIT_32(0x20, ch_62, ch_63), \
34 | INIT_32(0x40, ch_62, ch_63), \
35 | INIT_32(0x60, ch_62, ch_63), \
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~
test.c:29:50: note: expanded from macro 'INIT_32'
29 | #define INIT_32(v, ...) INIT_16(v, __VA_ARGS__), INIT_16((v) + 16, __VA_ARGS__)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test.c:28:49: note: expanded from macro 'INIT_16'
28 | #define INIT_16(v, ...) INIT_8(v, __VA_ARGS__), INIT_8((v) + 8, __VA_ARGS__)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
note: (skipping 1 expansions in backtrace; use -fmacro-backtrace-limit=0 to see all)
test.c:26:24: note: expanded from macro 'INIT_4'
26 | #define INIT_4(v, ...) INIT_2(v, __VA_ARGS__), INIT_2((v) + 2, __VA_ARGS__)
| ^~~~~~~~~~~~~~~~~~~~~~
test.c:25:24: note: expanded from macro 'INIT_2'
25 | #define INIT_2(v, ...) INIT_1(v, __VA_ARGS__), INIT_1((v) + 1, __VA_ARGS__)
| ^~~~~~~~~~~~~~~~~~~~~~
test.c:17:48: note: expanded from macro 'INIT_1'
17 | : (v) >= '0' && (v) <= '9' ? (v) - '0' + 52 \
| ~~~~~~~~~~^~~~
test.c:40:24: warning: implicit conversion from 'int' to 'signed char' changes value from 131 to -125 [-Wconstant-conversion]
40 | [BASE64_URLSAFE] = BASE64_REV_INIT('-', '_'),
| ^~~~~~~~~~~~~~~~~~~~~~~~~
test.c:35:5: note: expanded from macro 'BASE64_REV_INIT'
31 | #define BASE64_REV_INIT(ch_62, ch_63) { \
| ~
32 | [0 ... 0x1f] = -1, \
33 | INIT_32(0x20, ch_62, ch_63), \
34 | INIT_32(0x40, ch_62, ch_63), \
35 | INIT_32(0x60, ch_62, ch_63), \
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~
test.c:29:50: note: expanded from macro 'INIT_32'
29 | #define INIT_32(v, ...) INIT_16(v, __VA_ARGS__), INIT_16((v) + 16, __VA_ARGS__)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test.c:28:49: note: expanded from macro 'INIT_16'
28 | #define INIT_16(v, ...) INIT_8(v, __VA_ARGS__), INIT_8((v) + 8, __VA_ARGS__)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
note: (skipping 1 expansions in backtrace; use -fmacro-backtrace-limit=0 to see all)
test.c:26:48: note: expanded from macro 'INIT_4'
26 | #define INIT_4(v, ...) INIT_2(v, __VA_ARGS__), INIT_2((v) + 2, __VA_ARGS__)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
test.c:25:48: note: expanded from macro 'INIT_2'
25 | #define INIT_2(v, ...) INIT_1(v, __VA_ARGS__), INIT_1((v) + 1, __VA_ARGS__)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
test.c:17:48: note: expanded from macro 'INIT_1'
17 | : (v) >= '0' && (v) <= '9' ? (v) - '0' + 52 \
| ~~~~~~~~~~^~~~
test.c:40:24: warning: implicit conversion from 'int' to 'signed char' changes value from 130 to -126 [-Wconstant-conversion]
40 | [BASE64_URLSAFE] = BASE64_REV_INIT('-', '_'),
| ^~~~~~~~~~~~~~~~~~~~~~~~~
test.c:35:5: note: expanded from macro 'BASE64_REV_INIT'
31 | #define BASE64_REV_INIT(ch_62, ch_63) { \
| ~
32 | [0 ... 0x1f] = -1, \
33 | INIT_32(0x20, ch_62, ch_63), \
34 | INIT_32(0x40, ch_62, ch_63), \
35 | INIT_32(0x60, ch_62, ch_63), \
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~
test.c:29:50: note: expanded from macro 'INIT_32'
29 | #define INIT_32(v, ...) INIT_16(v, __VA_ARGS__), INIT_16((v) + 16, __VA_ARGS__)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test.c:28:49: note: expanded from macro 'INIT_16'
28 | #define INIT_16(v, ...) INIT_8(v, __VA_ARGS__), INIT_8((v) + 8, __VA_ARGS__)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
note: (skipping 1 expansions in backtrace; use -fmacro-backtrace-limit=0 to see all)
test.c:26:48: note: expanded from macro 'INIT_4'
26 | #define INIT_4(v, ...) INIT_2(v, __VA_ARGS__), INIT_2((v) + 2, __VA_ARGS__)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
test.c:25:24: note: expanded from macro 'INIT_2'
25 | #define INIT_2(v, ...) INIT_1(v, __VA_ARGS__), INIT_1((v) + 1, __VA_ARGS__)
| ^~~~~~~~~~~~~~~~~~~~~~
test.c:17:48: note: expanded from macro 'INIT_1'
17 | : (v) >= '0' && (v) <= '9' ? (v) - '0' + 52 \
| ~~~~~~~~~~^~~~
test.c:40:24: warning: implicit conversion from 'int' to 'signed char' changes value from 129 to -127 [-Wconstant-conversion]
40 | [BASE64_URLSAFE] = BASE64_REV_INIT('-', '_'),
| ^~~~~~~~~~~~~~~~~~~~~~~~~
test.c:35:5: note: expanded from macro 'BASE64_REV_INIT'
31 | #define BASE64_REV_INIT(ch_62, ch_63) { \
| ~
32 | [0 ... 0x1f] = -1, \
33 | INIT_32(0x20, ch_62, ch_63), \
34 | INIT_32(0x40, ch_62, ch_63), \
35 | INIT_32(0x60, ch_62, ch_63), \
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~
test.c:29:50: note: expanded from macro 'INIT_32'
29 | #define INIT_32(v, ...) INIT_16(v, __VA_ARGS__), INIT_16((v) + 16, __VA_ARGS__)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test.c:28:49: note: expanded from macro 'INIT_16'
28 | #define INIT_16(v, ...) INIT_8(v, __VA_ARGS__), INIT_8((v) + 8, __VA_ARGS__)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
note: (skipping 1 expansions in backtrace; use -fmacro-backtrace-limit=0 to see all)
test.c:26:24: note: expanded from macro 'INIT_4'
26 | #define INIT_4(v, ...) INIT_2(v, __VA_ARGS__), INIT_2((v) + 2, __VA_ARGS__)
| ^~~~~~~~~~~~~~~~~~~~~~
test.c:25:48: note: expanded from macro 'INIT_2'
25 | #define INIT_2(v, ...) INIT_1(v, __VA_ARGS__), INIT_1((v) + 1, __VA_ARGS__)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
test.c:17:48: note: expanded from macro 'INIT_1'
17 | : (v) >= '0' && (v) <= '9' ? (v) - '0' + 52 \
| ~~~~~~~~~~^~~~
test.c:40:24: warning: implicit conversion from 'int' to 'signed char' changes value from 128 to -128 [-Wconstant-conversion]
40 | [BASE64_URLSAFE] = BASE64_REV_INIT('-', '_'),
| ^~~~~~~~~~~~~~~~~~~~~~~~~
test.c:35:5: note: expanded from macro 'BASE64_REV_INIT'
31 | #define BASE64_REV_INIT(ch_62, ch_63) { \
| ~
32 | [0 ... 0x1f] = -1, \
33 | INIT_32(0x20, ch_62, ch_63), \
34 | INIT_32(0x40, ch_62, ch_63), \
35 | INIT_32(0x60, ch_62, ch_63), \
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~
test.c:29:50: note: expanded from macro 'INIT_32'
29 | #define INIT_32(v, ...) INIT_16(v, __VA_ARGS__), INIT_16((v) + 16, __VA_ARGS__)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test.c:28:49: note: expanded from macro 'INIT_16'
28 | #define INIT_16(v, ...) INIT_8(v, __VA_ARGS__), INIT_8((v) + 8, __VA_ARGS__)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
note: (skipping 1 expansions in backtrace; use -fmacro-backtrace-limit=0 to see all)
test.c:26:24: note: expanded from macro 'INIT_4'
26 | #define INIT_4(v, ...) INIT_2(v, __VA_ARGS__), INIT_2((v) + 2, __VA_ARGS__)
| ^~~~~~~~~~~~~~~~~~~~~~
test.c:25:24: note: expanded from macro 'INIT_2'
25 | #define INIT_2(v, ...) INIT_1(v, __VA_ARGS__), INIT_1((v) + 1, __VA_ARGS__)
| ^~~~~~~~~~~~~~~~~~~~~~
test.c:17:48: note: expanded from macro 'INIT_1'
17 | : (v) >= '0' && (v) <= '9' ? (v) - '0' + 52 \
| ~~~~~~~~~~^~~~
test.c:39:20: warning: implicit conversion from 'int' to 'signed char' changes value from 131 to -125 [-Wconstant-conversion]
39 | [BASE64_STD] = BASE64_REV_INIT('+', '/'),
| ^~~~~~~~~~~~~~~~~~~~~~~~~
test.c:35:5: note: expanded from macro 'BASE64_REV_INIT'
31 | #define BASE64_REV_INIT(ch_62, ch_63) { \
| ~
32 | [0 ... 0x1f] = -1, \
33 | INIT_32(0x20, ch_62, ch_63), \
34 | INIT_32(0x40, ch_62, ch_63), \
35 | INIT_32(0x60, ch_62, ch_63), \
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~
test.c:29:50: note: expanded from macro 'INIT_32'
29 | #define INIT_32(v, ...) INIT_16(v, __VA_ARGS__), INIT_16((v) + 16, __VA_ARGS__)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test.c:28:49: note: expanded from macro 'INIT_16'
28 | #define INIT_16(v, ...) INIT_8(v, __VA_ARGS__), INIT_8((v) + 8, __VA_ARGS__)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
note: (skipping 1 expansions in backtrace; use -fmacro-backtrace-limit=0 to see all)
test.c:26:48: note: expanded from macro 'INIT_4'
26 | #define INIT_4(v, ...) INIT_2(v, __VA_ARGS__), INIT_2((v) + 2, __VA_ARGS__)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
test.c:25:48: note: expanded from macro 'INIT_2'
25 | #define INIT_2(v, ...) INIT_1(v, __VA_ARGS__), INIT_1((v) + 1, __VA_ARGS__)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
test.c:17:48: note: expanded from macro 'INIT_1'
17 | : (v) >= '0' && (v) <= '9' ? (v) - '0' + 52 \
| ~~~~~~~~~~^~~~
test.c:39:20: warning: implicit conversion from 'int' to 'signed char' changes value from 130 to -126 [-Wconstant-conversion]
39 | [BASE64_STD] = BASE64_REV_INIT('+', '/'),
| ^~~~~~~~~~~~~~~~~~~~~~~~~
test.c:35:5: note: expanded from macro 'BASE64_REV_INIT'
31 | #define BASE64_REV_INIT(ch_62, ch_63) { \
| ~
32 | [0 ... 0x1f] = -1, \
33 | INIT_32(0x20, ch_62, ch_63), \
34 | INIT_32(0x40, ch_62, ch_63), \
35 | INIT_32(0x60, ch_62, ch_63), \
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~
test.c:29:50: note: expanded from macro 'INIT_32'
29 | #define INIT_32(v, ...) INIT_16(v, __VA_ARGS__), INIT_16((v) + 16, __VA_ARGS__)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test.c:28:49: note: expanded from macro 'INIT_16'
28 | #define INIT_16(v, ...) INIT_8(v, __VA_ARGS__), INIT_8((v) + 8, __VA_ARGS__)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
note: (skipping 1 expansions in backtrace; use -fmacro-backtrace-limit=0 to see all)
test.c:26:48: note: expanded from macro 'INIT_4'
26 | #define INIT_4(v, ...) INIT_2(v, __VA_ARGS__), INIT_2((v) + 2, __VA_ARGS__)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
test.c:25:24: note: expanded from macro 'INIT_2'
25 | #define INIT_2(v, ...) INIT_1(v, __VA_ARGS__), INIT_1((v) + 1, __VA_ARGS__)
| ^~~~~~~~~~~~~~~~~~~~~~
test.c:17:48: note: expanded from macro 'INIT_1'
17 | : (v) >= '0' && (v) <= '9' ? (v) - '0' + 52 \
| ~~~~~~~~~~^~~~
test.c:39:20: warning: implicit conversion from 'int' to 'signed char' changes value from 129 to -127 [-Wconstant-conversion]
39 | [BASE64_STD] = BASE64_REV_INIT('+', '/'),
| ^~~~~~~~~~~~~~~~~~~~~~~~~
test.c:35:5: note: expanded from macro 'BASE64_REV_INIT'
31 | #define BASE64_REV_INIT(ch_62, ch_63) { \
| ~
32 | [0 ... 0x1f] = -1, \
33 | INIT_32(0x20, ch_62, ch_63), \
34 | INIT_32(0x40, ch_62, ch_63), \
35 | INIT_32(0x60, ch_62, ch_63), \
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~
test.c:29:50: note: expanded from macro 'INIT_32'
29 | #define INIT_32(v, ...) INIT_16(v, __VA_ARGS__), INIT_16((v) + 16, __VA_ARGS__)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test.c:28:49: note: expanded from macro 'INIT_16'
28 | #define INIT_16(v, ...) INIT_8(v, __VA_ARGS__), INIT_8((v) + 8, __VA_ARGS__)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
note: (skipping 1 expansions in backtrace; use -fmacro-backtrace-limit=0 to see all)
test.c:26:24: note: expanded from macro 'INIT_4'
26 | #define INIT_4(v, ...) INIT_2(v, __VA_ARGS__), INIT_2((v) + 2, __VA_ARGS__)
| ^~~~~~~~~~~~~~~~~~~~~~
test.c:25:48: note: expanded from macro 'INIT_2'
25 | #define INIT_2(v, ...) INIT_1(v, __VA_ARGS__), INIT_1((v) + 1, __VA_ARGS__)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
test.c:17:48: note: expanded from macro 'INIT_1'
17 | : (v) >= '0' && (v) <= '9' ? (v) - '0' + 52 \
| ~~~~~~~~~~^~~~
test.c:39:20: warning: implicit conversion from 'int' to 'signed char' changes value from 128 to -128 [-Wconstant-conversion]
39 | [BASE64_STD] = BASE64_REV_INIT('+', '/'),
| ^~~~~~~~~~~~~~~~~~~~~~~~~
test.c:35:5: note: expanded from macro 'BASE64_REV_INIT'
31 | #define BASE64_REV_INIT(ch_62, ch_63) { \
| ~
32 | [0 ... 0x1f] = -1, \
33 | INIT_32(0x20, ch_62, ch_63), \
34 | INIT_32(0x40, ch_62, ch_63), \
35 | INIT_32(0x60, ch_62, ch_63), \
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~
test.c:29:50: note: expanded from macro 'INIT_32'
29 | #define INIT_32(v, ...) INIT_16(v, __VA_ARGS__), INIT_16((v) + 16, __VA_ARGS__)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test.c:28:49: note: expanded from macro 'INIT_16'
28 | #define INIT_16(v, ...) INIT_8(v, __VA_ARGS__), INIT_8((v) + 8, __VA_ARGS__)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
note: (skipping 1 expansions in backtrace; use -fmacro-backtrace-limit=0 to see all)
test.c:26:24: note: expanded from macro 'INIT_4'
26 | #define INIT_4(v, ...) INIT_2(v, __VA_ARGS__), INIT_2((v) + 2, __VA_ARGS__)
| ^~~~~~~~~~~~~~~~~~~~~~
test.c:25:24: note: expanded from macro 'INIT_2'
25 | #define INIT_2(v, ...) INIT_1(v, __VA_ARGS__), INIT_1((v) + 1, __VA_ARGS__)
| ^~~~~~~~~~~~~~~~~~~~~~
test.c:17:48: note: expanded from macro 'INIT_1'
17 | : (v) >= '0' && (v) <= '9' ? (v) - '0' + 52 \
| ~~~~~~~~~~^~~~
12 warnings generated.
```
https://godbolt.org/z/jc9s16osM
This is a false positive since `(v) >= '0' && (v) <= '9'` cannot be true for the range of values of `v` that the warning is complaining about (`0x7c ... 0x7f`). As seen from the godbolt link above, GCC does not warn and it seems like this warning should not fire for unreachable code based on `test6()` in `clang/test/Sema/constant-conversion.c`. I am not sure if this is an existing issue that the change exposed or there is something else that needs to be done to fix this. I am not sure how to work around this otherwise (other than widening the type).
Contributor guide
Research direction
The report provides a standalone test.c reproducer; first run clang -fsyntax-only -Wconstant-conversion test.c and inspect the diagnostic path for signed-char array constant initializers. Add a regression test covering the BASE64_REV_INIT case and verify the false-positive warnings no longer appear while valid constant-conversion diagnostics remain.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- c
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 55/100