In a Linux kernel module there are definitions for a number of things that are in stdint.h/limits.h for user mode C but are conspicuously missing from the standard kernel headers. E.g. the following:
#define UINT16_MIN (uint16_t)0
#define UINT16_MAX (~UINT16_MIN)
#define INT16_MAX (int16_t)(UINT16_MAX >> 1)
#define INT16_MIN (-INT16_MAX - (int16_t)1)
However, when built with kbuild (i386 target) INT16_MAX is coming out to (int16_t)-1 and INT16_MIN to (int16_t)0. This implies that UINT16_MAX was converted to int16_t by the ~ operator before being right-shifted. If the definition of UINT16_MAX is changed to
#define UINT16_MAX (uint16_t)(~UINT16_MIN)
the result is correct. Is this some deep, dark, and brown-recluse-infested corner of the C language, or just a straight up compiler bug?
EDIT: As explained in comments I thought promotion only occurred when mixing argument types or assigning to a type different than the value, and did not know it could occur with unary operations. This question is a duplicate.