335-ternary-merge-arith-conv.c (2118B)
1 /* tests/cc/335-ternary-merge-arith-conv.c — C11 §6.5.15 ¶5: ternary 2 * applies the usual arithmetic conversions to its second and third 3 * operands and the result type is the resulting common type. 4 * 5 * cc.scm originally took arm 1's type as the merge slot's result type 6 * unchanged. When arm 1 was narrower than arm 2, the surrounding 7 * expression saw a too-narrow rvalue and cg-arith-conv truncated to 8 * that width on the next op. Concretely, in 9 * 10 * (uint32_t)x | (cond ? 0 : -(x & 0x80000000)) 11 * 12 * the ternary's int arm-1 dominated the merge type, so the `|` was 13 * lowered as 32-bit and the upper sign-extension bits in arm-2 were 14 * dropped. tcc.flat.c's gen_opic uses exactly this idiom for 15 * sign-extension of narrow constants, so the cc.scm-built tcc-boot2 16 * miscompiled int < int as unsigned and 220-const-promote.c failed 17 * under tcc-cc. 18 * 19 * Keep this fixture as a runtime check on cc.scm directly so the 20 * regression surfaces without dragging tcc into the loop. */ 21 typedef unsigned long long u64; 22 typedef unsigned int u32; 23 24 int main(void) { 25 u64 l = (u64)-1; 26 int t = 0; 27 28 /* The exact pattern from tcc.flat.c gen_opic line 5471-5475. */ 29 u64 sext = ((u32)l | 30 (t & 0x10 ? 0 : -(l & 0x80000000))); 31 if (sext != (u64)-1) return 1; 32 33 /* Same shape with the ternary's arms in the other order — the 34 * picked common type must not depend on which arm parses first. */ 35 u64 sext2 = ((u32)l | 36 (t & 0x10 ? -(l & 0x80000000) : 0)); 37 if (sext2 != 0xFFFFFFFFULL) return 2; 38 39 /* Asymmetric arm types (int vs u64) at top level. With arm-1's 40 * type leaking through, the result is read as a 32-bit value and 41 * the high bits vanish. */ 42 u64 a = (1 ? 0 : (u64)0x100000001ULL); 43 if (a != 0) return 3; 44 u64 b = (0 ? 0 : (u64)0x100000001ULL); 45 if (b != 0x100000001ULL) return 4; 46 47 /* Mixed signed/unsigned ternary: result type should follow the 48 * usual arithmetic conversions (i32 + u32 -> u32). */ 49 int s = -1; 50 u32 u = 1u; 51 u32 r = (1 ? s : u); 52 if (r != 0xFFFFFFFFu) return 5; 53 54 return 0; 55 }