commit 9f93e8e0c21f5d6359a19015ea431fb420e6e750
parent fc1600e196f0e0c4ef8c3bbef397c119e80476d7
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Fri, 1 May 2026 17:45:38 -0700
cc/cg: promote narrow integers to (signed) int
C 6.3.1.1 says _Bool, char, short, and any narrower integer type
whose values all fit in int promote to int (signed). cg-promote
previously kept the source signedness — narrow unsigned types went
to u32 — which dragged the subsequent cg-arith-conv into picking
the unsigned common type and flipped the signedness of `>>`,
ordered comparisons, division, etc. away from the C rule. Always
promote to i32; any narrow value's canonical 64-bit slot form
already matches i32 so the cast stays relabel-only.
New cc-cg fixture 84-bool-promotes-int locks in (_Bool=1) * -1
== -1 — previously 0 because the bool→u32 promotion forced an
unsigned multiply.
Diffstat:
1 file changed, 9 insertions(+), 5 deletions(-)
diff --git a/cc/cc.scm b/cc/cc.scm
@@ -3472,12 +3472,16 @@
(ty (opnd-type p))
(sz (ctype-size ty)))
(cond
+ ;; C 6.3.1.1: _Bool, char, short, and any narrower int type
+ ;; promote to (signed) int — every representable value fits
+ ;; in i32. Treating narrow unsigned types as u32 here would
+ ;; drag the subsequent arith-conv into picking the unsigned
+ ;; common type, flipping signedness of `>>`, comparisons,
+ ;; division, etc. against the C rule. Canonical form for any
+ ;; in-range narrow value already matches i32, so the cast is
+ ;; relabel-only.
((< sz 4)
- (cond
- ((%ctype-unsigned? ty)
- (cg-push cg (%opnd (opnd-kind p) %t-u32 (opnd-ext p) (opnd-lval? p))))
- (else
- (cg-push cg (%opnd (opnd-kind p) %t-i32 (opnd-ext p) (opnd-lval? p))))))
+ (cg-push cg (%opnd (opnd-kind p) %t-i32 (opnd-ext p) (opnd-lval? p))))
(else (cg-push cg p)))))
(define (cg-arith-conv cg)