commit 16e81e5d753312600d9beaac52a9155841662cf0
parent 20bdc9d3b540ec050be7201600f9a67a18174cc8
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Wed, 6 May 2026 13:35:05 -0700
cc: widen integer literals exceeding INT_MAX to i64
parse-primary typed every INT token as i32, regardless of value. The
lexer drops u/U/l/L suffixes, so 4294967296L + 7L pushed both operands
as i32; cg-arith-conv kept the result i32 and cg-cast emitted a
trailing %sext32 after the 64-bit %add, truncating 0x100000007 to 7.
Pick %t-i64 when the value exceeds INT_MAX (C99 §6.4.4.1: smallest
type that holds the value). Fixes cc-libc/018-printf-int-promo on all
three arches.
Diffstat:
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/cc/cc.scm b/cc/cc.scm
@@ -7184,7 +7184,15 @@
(pmatch t
(($ tok? (kind INT) (value ,n))
(advance ps)
- (cg-push-imm (ps-cg ps) %t-i32 n))
+ ;; C99 §6.4.4.1: pick the smallest type that holds the value.
+ ;; The lexer drops u/U/l/L suffixes before we get here, so we can't
+ ;; tell `0x1L` from `0x1`. But a value that doesn't fit in int has
+ ;; to widen anyway — otherwise `4294967296L + 7L` truncates to 7,
+ ;; because cg-arith-conv leaves both operands at i32 width.
+ (cg-push-imm (ps-cg ps)
+ (cond ((<= n 2147483647) %t-i32)
+ (else %t-i64))
+ n))
(($ tok? (kind CHAR) (value ,c))
(advance ps)
;; C99 §6.4.4.4: an integer character constant has type int.