boot2

Playing with the boostrap
git clone https://git.ryansepassi.com/git/boot2.git
Log | Files | Refs | README

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 }