220-const-promote.c (1631B)
1 /* Integer promotion in const-expr: per C11 §6.3.1.1, an unsigned char 2 * (or unsigned short) whose width is less than int promotes to (signed) 3 * int — not unsigned int — because every value of the source type fits. 4 * 5 * This matters for cross-signedness comparisons in const-expr: 6 * (unsigned char)-1 < (int)-1 7 * becomes after promotion: (int)255 < (int)-1 -> 0 8 * If u8 incorrectly promotes to unsigned int, the usual arithmetic 9 * conversions promote both sides to unsigned int, making the LHS 10 * 255u and the RHS 0xFFFFFFFFu — the comparison flips to 1. 11 */ 12 13 /* Encode the const-expr result as an array bound: a non-zero value 14 * makes [0] / [1] become [1] (legal); the wrong (buggy) value would 15 * still compile, so we instead drive a switch via enum and check at 16 * runtime — keeping the exercise inside a const-expr context. */ 17 18 enum { 19 /* (unsigned char)-1 < (int)-1 20 * correct C: 255 < -1 -> 0 21 * buggy: u32 conv -> 255u < 0xFFFFFFFFu -> 1 */ 22 R1 = ((unsigned char)-1 < (int)-1), 23 24 /* (unsigned short)-1 < (int)-1 -- same shape with u16. */ 25 R2 = ((unsigned short)-1 < (int)-1), 26 27 /* (unsigned char)1 + (int)-2 has type int, value -1. 28 * Buggy code: u8 promotes to u32, conv to u32, result u32 -> 0xFFFFFFFF. 29 * The cast back to int recovers -1, but a comparison without 30 * the cast would surface the bug. */ 31 R3 = (((unsigned char)1 + (int)-2) < 0), 32 }; 33 34 int main(void) { 35 if (R1 != 0) return 1; /* the bug makes this 1 */ 36 if (R2 != 0) return 2; /* same with unsigned short */ 37 if (R3 != 1) return 3; /* the bug makes this 0 */ 38 return 0; 39 }