commit 2bdeb46f9c551570bc731997aad31fc6991e5449
parent 6e16d41536712479f63a338cbacd62feca3dfddf
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Tue, 26 May 2026 17:51:19 -0700
parse: fix _Bool conversion to emit compare-against-zero rather than truncate
Converting a non-bool scalar to _Bool is semantically "value != 0", not a
width truncation. A value whose set bits all lie above the bool storage width
(e.g. 256, or the sign bit of a 128-bit operand) must still produce 1. Emit
an explicit compare-against-zero (int or fp) followed by a narrow trunc for
any non-bool scalar source.
Diffstat:
1 file changed, 20 insertions(+), 0 deletions(-)
diff --git a/lang/c/parse/cg_adapter.c b/lang/c/parse/cg_adapter.c
@@ -785,6 +785,26 @@ void pcg_convert(Parser* p, const Type* dst) {
CfreeCgTypeId id = pcg_tid(p, dst);
int emit = pcg_emit_enabled(p);
if (src == dst) return;
+ /* Conversion to _Bool is "value != 0", not a truncation: a value whose set
+ * bits all lie above the bool storage width (e.g. 256, or the sign bit of a
+ * 128-bit operand) must still become 1. Emit an explicit compare-against-zero
+ * for any non-bool scalar source. */
+ if (dst->kind == TY_BOOL && src->kind != TY_BOOL) {
+ if (emit) {
+ CfreeCgTypeId sid = pcg_tid(p, src);
+ if (sf) {
+ cfree_cg_push_float(p->cg, 0.0, sid);
+ cfree_cg_fp_cmp(p->cg, CFREE_CG_FP_UNE);
+ } else {
+ cfree_cg_push_int(p->cg, 0, sid);
+ cfree_cg_int_cmp(p->cg, CFREE_CG_INT_NE);
+ }
+ /* The compare yields a 0/1 int; narrow it to the bool storage width. */
+ cfree_cg_trunc(p->cg, id);
+ }
+ pcg_retag_top(p, dst);
+ return;
+ }
if (type_is_ptr(src) && type_is_ptr(dst)) {
if (emit) cfree_cg_bitcast(p->cg, id);
pcg_retag_top(p, dst);