From 9cad53045c1434614faf7a40bf01b4e770c936f2 Mon Sep 17 00:00:00 2001 From: Rua Date: Tue, 24 Mar 2026 16:36:24 +0100 Subject: [PATCH 1/3] transpile: Split off `convert_negate` --- c2rust-transpile/src/translator/operators.rs | 30 ++++++++++++-------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/c2rust-transpile/src/translator/operators.rs b/c2rust-transpile/src/translator/operators.rs index 17b4892340..d95c9f7367 100644 --- a/c2rust-transpile/src/translator/operators.rs +++ b/c2rust-transpile/src/translator/operators.rs @@ -875,9 +875,6 @@ impl<'c> Translation<'c> { arg: CExprId, lrvalue: LRValue, ) -> TranslationResult>> { - let CQualTypeId { ctype, .. } = cqual_type; - let resolved_ctype = self.ast_context.resolve_type(ctype); - let mut unary = match name { c_ast::UnOp::AddressOf => self.convert_address_of(ctx, cqual_type, arg), c_ast::UnOp::PreIncrement => self.convert_pre_increment(ctx, cqual_type, true, arg), @@ -887,15 +884,7 @@ impl<'c> Translation<'c> { c_ast::UnOp::Deref => self.convert_deref(ctx, cqual_type, arg, lrvalue), c_ast::UnOp::Plus => self.convert_expr(ctx.used(), arg, Some(cqual_type)), // promotion is explicit in the clang AST - c_ast::UnOp::Negate => { - let val = self.convert_expr(ctx.used(), arg, Some(cqual_type))?; - - if resolved_ctype.kind.is_unsigned_integral_type() { - Ok(val.map(wrapping_neg_expr)) - } else { - Ok(val.map(neg_expr)) - } - } + c_ast::UnOp::Negate => self.convert_negate(ctx, cqual_type, arg), c_ast::UnOp::Complement => Ok(self .convert_expr(ctx.used(), arg, Some(cqual_type))? .map(|a| mk().unary_expr(UnOp::Not(Default::default()), a))), @@ -934,4 +923,21 @@ impl<'c> Translation<'c> { } Ok(unary) } + + fn convert_negate( + &self, + ctx: ExprContext, + cqual_type: CQualTypeId, + arg: CExprId, + ) -> TranslationResult>> { + let CQualTypeId { ctype, .. } = cqual_type; + let resolved_ctype = self.ast_context.resolve_type(ctype); + let val = self.convert_expr(ctx.used(), arg, Some(cqual_type))?; + + if resolved_ctype.kind.is_unsigned_integral_type() { + Ok(val.map(wrapping_neg_expr)) + } else { + Ok(val.map(neg_expr)) + } + } } From 73b05bdae5d4bfc58a7a4e7eeaed76c8cf1755c1 Mon Sep 17 00:00:00 2001 From: Rua Date: Tue, 24 Mar 2026 16:40:53 +0100 Subject: [PATCH 2/3] transpile: Refactor `convert_negate` --- c2rust-transpile/src/translator/operators.rs | 27 +++++++++----------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/c2rust-transpile/src/translator/operators.rs b/c2rust-transpile/src/translator/operators.rs index d95c9f7367..1dd09b4d24 100644 --- a/c2rust-transpile/src/translator/operators.rs +++ b/c2rust-transpile/src/translator/operators.rs @@ -2,14 +2,6 @@ use super::*; -fn neg_expr(arg: Box) -> Box { - mk().unary_expr(UnOp::Neg(Default::default()), arg) -} - -fn wrapping_neg_expr(arg: Box) -> Box { - mk().method_call_expr(arg, "wrapping_neg", vec![]) -} - impl From for BinOp { fn from(op: c_ast::BinOp) -> Self { match op { @@ -930,14 +922,19 @@ impl<'c> Translation<'c> { cqual_type: CQualTypeId, arg: CExprId, ) -> TranslationResult>> { - let CQualTypeId { ctype, .. } = cqual_type; - let resolved_ctype = self.ast_context.resolve_type(ctype); + let is_unsigned_integral_type = self + .ast_context + .resolve_type(cqual_type.ctype) + .kind + .is_unsigned_integral_type(); let val = self.convert_expr(ctx.used(), arg, Some(cqual_type))?; - if resolved_ctype.kind.is_unsigned_integral_type() { - Ok(val.map(wrapping_neg_expr)) - } else { - Ok(val.map(neg_expr)) - } + Ok(val.map(|val| { + if is_unsigned_integral_type { + mk().method_call_expr(val, "wrapping_neg", vec![]) + } else { + mk().unary_expr(UnOp::Neg(Default::default()), val) + } + })) } } From 9d45ef0f16aaa75c2cd9e4dc1574a2d5440ec540 Mon Sep 17 00:00:00 2001 From: Rua Date: Tue, 24 Mar 2026 16:55:06 +0100 Subject: [PATCH 3/3] transpile: Swap cast and negation for integer literals --- c2rust-transpile/src/translator/literals.rs | 12 ++++++-- c2rust-transpile/src/translator/mod.rs | 1 + c2rust-transpile/src/translator/operators.rs | 28 +++++++++++++------ ...hots__transpile@vm_x86.c.2021.aarch64.snap | 2 +- ...shots__transpile@vm_x86.c.2021.x86_64.snap | 2 +- ...hots__transpile@vm_x86.c.2024.aarch64.snap | 2 +- ...shots__transpile@vm_x86.c.2024.x86_64.snap | 2 +- 7 files changed, 35 insertions(+), 14 deletions(-) diff --git a/c2rust-transpile/src/translator/literals.rs b/c2rust-transpile/src/translator/literals.rs index 256b225de6..ae9ea743bc 100644 --- a/c2rust-transpile/src/translator/literals.rs +++ b/c2rust-transpile/src/translator/literals.rs @@ -14,15 +14,21 @@ impl<'c> Translation<'c> { ty: CQualTypeId, val: u64, base: IntBase, + negative: bool, ) -> TranslationResult> { let lit = match base { IntBase::Dec => mk().int_unsuffixed_lit(val), IntBase::Hex => mk().float_unsuffixed_lit(&format!("0x{:x}", val)), IntBase::Oct => mk().float_unsuffixed_lit(&format!("0o{:o}", val)), }; + let mut expr = mk().lit_expr(lit); + + if negative { + expr = mk().unary_expr(UnOp::Neg(Default::default()), expr); + } let target_ty = self.convert_type(ty.ctype)?; - Ok(mk().cast_expr(mk().lit_expr(lit), target_ty)) + Ok(mk().cast_expr(expr, target_ty)) } /// Return whether the literal can be directly translated as this type. @@ -49,7 +55,9 @@ impl<'c> Translation<'c> { lit: &CLiteral, ) -> TranslationResult>> { match *lit { - CLiteral::Integer(val, base) => Ok(WithStmts::new_val(self.mk_int_lit(ty, val, base)?)), + CLiteral::Integer(val, base) => { + Ok(WithStmts::new_val(self.mk_int_lit(ty, val, base, false)?)) + } CLiteral::Character(val) => { let val = val as u32; diff --git a/c2rust-transpile/src/translator/mod.rs b/c2rust-transpile/src/translator/mod.rs index 13190694a3..c0a3c44a6b 100644 --- a/c2rust-transpile/src/translator/mod.rs +++ b/c2rust-transpile/src/translator/mod.rs @@ -3648,6 +3648,7 @@ impl<'c> Translation<'c> { override_ty.unwrap_or(ty), *val, IntBase::Dec, + false, )?)), OffsetOfKind::Variable(qty, field_id, expr_id) => { self.use_crate(ExternCrate::Memoffset); diff --git a/c2rust-transpile/src/translator/operators.rs b/c2rust-transpile/src/translator/operators.rs index 1dd09b4d24..9a8263f15c 100644 --- a/c2rust-transpile/src/translator/operators.rs +++ b/c2rust-transpile/src/translator/operators.rs @@ -927,14 +927,26 @@ impl<'c> Translation<'c> { .resolve_type(cqual_type.ctype) .kind .is_unsigned_integral_type(); - let val = self.convert_expr(ctx.used(), arg, Some(cqual_type))?; - Ok(val.map(|val| { - if is_unsigned_integral_type { - mk().method_call_expr(val, "wrapping_neg", vec![]) - } else { - mk().unary_expr(UnOp::Neg(Default::default()), val) - } - })) + if let (&CExprKind::Literal(_, CLiteral::Integer(val, base)), false) = + (&self.ast_context[arg].kind, is_unsigned_integral_type) + { + // If we are negating a literal, generate a negated literal directly. + // This will create an expression like `-1 as ty` without parentheses, + // rather than `-(1 as ty)`. + Ok(WithStmts::new_val( + self.mk_int_lit(cqual_type, val, base, true)?, + )) + } else { + let val = self.convert_expr(ctx.used(), arg, Some(cqual_type))?; + + Ok(val.map(|val| { + if is_unsigned_integral_type { + mk().method_call_expr(val, "wrapping_neg", vec![]) + } else { + mk().unary_expr(UnOp::Neg(Default::default()), val) + } + })) + } } } diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@vm_x86.c.2021.aarch64.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@vm_x86.c.2021.aarch64.snap index 83b2aad8a6..bf1cad61f4 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@vm_x86.c.2021.aarch64.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@vm_x86.c.2021.aarch64.snap @@ -53,7 +53,7 @@ pub unsafe extern "C" fn VM_CallCompiled( *(image.offset((programStack + 4 as ::core::ffi::c_int) as isize) as *mut byte as *mut ::core::ffi::c_int) = 0 as ::core::ffi::c_int; *(image.offset(programStack as isize) as *mut byte as *mut ::core::ffi::c_int) = - -(1 as ::core::ffi::c_int); + -1 as ::core::ffi::c_int; entryPoint = (*vm).codeBase.offset((*vm).entryOfs as isize); opStack = (&raw mut stack as *mut byte as *mut ::core::ffi::c_int) .offset(16 as ::core::ffi::c_int as isize); diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@vm_x86.c.2021.x86_64.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@vm_x86.c.2021.x86_64.snap index 3f61aca898..771666b0ca 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@vm_x86.c.2021.x86_64.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@vm_x86.c.2021.x86_64.snap @@ -54,7 +54,7 @@ pub unsafe extern "C" fn VM_CallCompiled( *(image.offset((programStack + 4 as ::core::ffi::c_int) as isize) as *mut byte as *mut ::core::ffi::c_int) = 0 as ::core::ffi::c_int; *(image.offset(programStack as isize) as *mut byte as *mut ::core::ffi::c_int) = - -(1 as ::core::ffi::c_int); + -1 as ::core::ffi::c_int; entryPoint = (*vm).codeBase.offset((*vm).entryOfs as isize); opStack = (&raw mut stack as *mut byte as *mut ::core::ffi::c_int) .offset(16 as ::core::ffi::c_int as isize); diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@vm_x86.c.2024.aarch64.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@vm_x86.c.2024.aarch64.snap index bae469ba73..7d56552a65 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@vm_x86.c.2024.aarch64.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@vm_x86.c.2024.aarch64.snap @@ -52,7 +52,7 @@ pub unsafe extern "C" fn VM_CallCompiled( *(image.offset((programStack + 4 as ::core::ffi::c_int) as isize) as *mut byte as *mut ::core::ffi::c_int) = 0 as ::core::ffi::c_int; *(image.offset(programStack as isize) as *mut byte as *mut ::core::ffi::c_int) = - -(1 as ::core::ffi::c_int); + -1 as ::core::ffi::c_int; entryPoint = (*vm).codeBase.offset((*vm).entryOfs as isize); opStack = (&raw mut stack as *mut byte as *mut ::core::ffi::c_int) .offset(16 as ::core::ffi::c_int as isize); diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@vm_x86.c.2024.x86_64.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@vm_x86.c.2024.x86_64.snap index 8255a1e65f..c4a70029ab 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@vm_x86.c.2024.x86_64.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@vm_x86.c.2024.x86_64.snap @@ -53,7 +53,7 @@ pub unsafe extern "C" fn VM_CallCompiled( *(image.offset((programStack + 4 as ::core::ffi::c_int) as isize) as *mut byte as *mut ::core::ffi::c_int) = 0 as ::core::ffi::c_int; *(image.offset(programStack as isize) as *mut byte as *mut ::core::ffi::c_int) = - -(1 as ::core::ffi::c_int); + -1 as ::core::ffi::c_int; entryPoint = (*vm).codeBase.offset((*vm).entryOfs as isize); opStack = (&raw mut stack as *mut byte as *mut ::core::ffi::c_int) .offset(16 as ::core::ffi::c_int as isize);