diff --git a/c2rust-transpile/src/translator/mod.rs b/c2rust-transpile/src/translator/mod.rs index 2a4e6710eb..60029632b5 100644 --- a/c2rust-transpile/src/translator/mod.rs +++ b/c2rust-transpile/src/translator/mod.rs @@ -1594,11 +1594,6 @@ fn arrange_header(t: &Translation, is_binary: bool) -> (Vec, Vec (out_attrs, out_items) } -/// Convert a boolean expression to a c_int -fn bool_to_int(val: Box) -> Box { - mk().cast_expr(val, mk().abs_path_ty(vec!["core", "ffi", "c_int"])) -} - /// Add a src_loc = "line:col" attribute to an item/foreign_item fn add_src_loc_attr(attrs: &mut Vec, src_loc: &Option) { if let Some(src_loc) = src_loc.as_ref() { @@ -4229,6 +4224,18 @@ impl<'c> Translation<'c> { } } + CExprKind::Unary(_, op, ..) => { + if matches!(op, CUnOp::Not) { + return true; + } + } + + CExprKind::Binary(_, op, ..) => { + if op.is_comparison() || op.is_logical() { + return true; + } + } + _ => {} } diff --git a/c2rust-transpile/src/translator/operators.rs b/c2rust-transpile/src/translator/operators.rs index b8e7b5b27b..3108748c29 100644 --- a/c2rust-transpile/src/translator/operators.rs +++ b/c2rust-transpile/src/translator/operators.rs @@ -7,7 +7,7 @@ impl<'c> Translation<'c> { &self, mut ctx: ExprContext, expected_type_id: Option, - result_type_id: CQualTypeId, + mut result_type_id: CQualTypeId, op: CBinOp, lhs: CExprId, rhs: CExprId, @@ -29,15 +29,19 @@ impl<'c> Translation<'c> { op if op.is_logical() => { let lhs = self.convert_condition(ctx.used(), true, lhs)?; let rhs = self.convert_condition(ctx.used(), true, rhs)?; - Ok(lhs - .map(|x| bool_to_int(mk().binary_expr(BinOp::from(op), x, rhs.to_expr()))) + let expr_rs = lhs + .map(|x| mk().binary_expr(BinOp::from(op), x, rhs.to_expr())) .and_then(|out| { self.convert_side_effects_expr( ctx, WithStmts::new_val(out), "Binary expression is not supposed to be used", ) - })) + }); + + let expected_type_id = expected_type_id.unwrap_or(result_type_id); + result_type_id.ctype = self.ast_context.type_for_kind(&CTypeKind::Bool); + self.make_cast(ctx, result_type_id, expected_type_id, expr_rs) } // No sequence-point cases @@ -91,6 +95,7 @@ impl<'c> Translation<'c> { // Ops like division and bitxor accept inputs of their expected result type. lhs_type_id = expr_type_id; rhs_type_id = expr_type_id; + result_type_id = expr_type_id; } else if op.input_types_same() && lhs_resolved_ty.kind != rhs_resolved_ty.kind { // Ops like comparisons require argument types to match, but the result type @@ -110,6 +115,7 @@ impl<'c> Translation<'c> { rhs_type_id = ty; } else if matches!(op, ShiftLeft | ShiftRight) { lhs_type_id = expr_type_id; + result_type_id = expr_type_id; } } @@ -136,6 +142,7 @@ impl<'c> Translation<'c> { // have to rely on `trait PartialEq` as much and it is also more idiomatic. if matches!(op, CBinOp::EqualEqual | CBinOp::NotEqual) { let is_null = op == CBinOp::EqualEqual; + let expected_type_id = expected_type_id.unwrap_or(result_type_id); if self.ast_context.is_null_expr(lhs) { let val = self.convert_expr(rhs_ctx, rhs, Some(rhs_type_id))?; @@ -147,7 +154,9 @@ impl<'c> Translation<'c> { is_null, ) })?; - return Ok(val.map(bool_to_int)); + + result_type_id.ctype = self.ast_context.type_for_kind(&CTypeKind::Bool); + return self.make_cast(ctx, result_type_id, expected_type_id, val); } else if self.ast_context.is_null_expr(rhs) { let val = self.convert_expr(ctx, lhs, Some(lhs_type_id))?; let val = val.try_map(|lhs_rs| { @@ -158,7 +167,9 @@ impl<'c> Translation<'c> { is_null, ) })?; - return Ok(val.map(bool_to_int)); + + result_type_id.ctype = self.ast_context.type_for_kind(&CTypeKind::Bool); + return self.make_cast(ctx, result_type_id, expected_type_id, val); } } @@ -168,7 +179,8 @@ impl<'c> Translation<'c> { lhs_val.zip(rhs_val).and_then_try(|(lhs_val, rhs_val)| { self.convert_binary_operator( ctx, - expr_type_id, + expected_type_id, + result_type_id, op, lhs_type_id, rhs_type_id, @@ -389,6 +401,7 @@ impl<'c> Translation<'c> { let val = lhs.and_then_try(|lhs| { self.convert_binary_operator( ctx, + Some(lhs_type_id), compute_res_type_id, underlying_op, compute_lhs_type_id, @@ -398,8 +411,6 @@ impl<'c> Translation<'c> { ) })?; - let val = self.make_cast(ctx, compute_res_type_id, lhs_type_id, val)?; - if is_volatile { val.try_map(|val| self.volatile_write(write, lhs_type_id, val))? .set_unsafe() @@ -471,106 +482,90 @@ impl<'c> Translation<'c> { fn convert_binary_operator( &self, ctx: ExprContext, - expr_type_id: CQualTypeId, + expected_type_id: Option, + mut result_type_id: CQualTypeId, op: CBinOp, lhs_type: CQualTypeId, rhs_type: CQualTypeId, lhs: Box, rhs: Box, ) -> TranslationResult>> { - let is_unsigned_integral_type = self - .ast_context - .resolve_type(expr_type_id.ctype) - .kind - .is_unsigned_integral_type(); - - Ok(WithStmts::new_val(match op { - CBinOp::Add => return self.convert_addition(lhs_type, rhs_type, lhs, rhs), - CBinOp::Subtract => { - return self.convert_subtraction(ctx, expr_type_id, lhs_type, rhs_type, lhs, rhs) - } - - op if op.is_arithmetic() && is_unsigned_integral_type => { - mk().method_call_expr(lhs, op.wrapping_method(), vec![rhs]) - } + if op.is_arithmetic() { + self.convert_arithmetic_operator( + ctx, + expected_type_id, + result_type_id, + op, + lhs_type, + rhs_type, + lhs, + rhs, + ) + } else { + let expected_type_id = expected_type_id.unwrap_or(result_type_id); - op if op.is_arithmetic() || op.is_bitwise() || op.is_bitshift() => { + let expr_rs = if op.is_bitwise() || op.is_bitshift() { mk().binary_expr(BinOp::from(op), lhs, rhs) - } - - op if op.is_comparison() => bool_to_int(mk().binary_expr(BinOp::from(op), lhs, rhs)), - - op => unimplemented!("Translation of binary operator {:?}", op), - })) - } + } else if op.is_comparison() { + result_type_id.ctype = self.ast_context.type_for_kind(&CTypeKind::Bool); + mk().binary_expr(BinOp::from(op), lhs, rhs) + } else { + unimplemented!("Translation of binary operator {:?}", op) + }; - fn convert_addition( - &self, - lhs_type_id: CQualTypeId, - rhs_type_id: CQualTypeId, - lhs: Box, - rhs: Box, - ) -> TranslationResult>> { - let lhs_type = &self.ast_context.resolve_type(lhs_type_id.ctype).kind; - let rhs_type = &self.ast_context.resolve_type(rhs_type_id.ctype).kind; - - if let &CTypeKind::Pointer(pointee) = lhs_type { - Ok(self.convert_pointer_offset(lhs, rhs, pointee.ctype, false, false)) - } else if let &CTypeKind::Pointer(pointee) = rhs_type { - Ok(self.convert_pointer_offset(rhs, lhs, pointee.ctype, false, false)) - } else if lhs_type.is_unsigned_integral_type() { - Ok(WithStmts::new_val(mk().method_call_expr( - lhs, - "wrapping_add", - vec![rhs], - ))) - } else { - Ok(WithStmts::new_val(mk().binary_expr( - BinOp::Add(Default::default()), - lhs, - rhs, - ))) + self.make_cast( + ctx, + result_type_id, + expected_type_id, + WithStmts::new_val(expr_rs), + ) } } - fn convert_subtraction( + fn convert_arithmetic_operator( &self, ctx: ExprContext, - expr_type_id: CQualTypeId, + expected_type_id: Option, + result_type_id: CQualTypeId, + op: CBinOp, lhs_type_id: CQualTypeId, rhs_type_id: CQualTypeId, lhs: Box, rhs: Box, ) -> TranslationResult>> { - let lhs_type = &self.ast_context.resolve_type(lhs_type_id.ctype).kind; - let rhs_type = &self.ast_context.resolve_type(rhs_type_id.ctype).kind; - - if let &CTypeKind::Pointer(pointee) = rhs_type { - let val = self.make_pointer_difference(lhs, rhs, pointee.ctype); - let source_type_id = self.ast_context.type_for_kind(&CTypeKind::PtrDiff); - self.make_cast(ctx, CQualTypeId::new(source_type_id), expr_type_id, val) - } else if let &CTypeKind::Pointer(pointee) = lhs_type { - Ok(self.convert_pointer_offset(lhs, rhs, pointee.ctype, true, false)) - } else if lhs_type.is_unsigned_integral_type() { - Ok(WithStmts::new_val(mk().method_call_expr( - lhs, - "wrapping_sub", - vec![rhs], - ))) + let lhs_type_kind = &self.ast_context.resolve_type(lhs_type_id.ctype).kind; + let rhs_type_kind = &self.ast_context.resolve_type(rhs_type_id.ctype).kind; + + let expr_rs = if let &CTypeKind::Pointer(pointee) = rhs_type_kind { + assert!(matches!(op, CBinOp::Add | CBinOp::Subtract)); + if op == CBinOp::Subtract { + self.make_pointer_difference(lhs, rhs, pointee.ctype) + } else { + self.convert_pointer_offset(rhs, lhs, pointee.ctype, false, false) + } + } else if let &CTypeKind::Pointer(pointee) = lhs_type_kind { + assert!(matches!(op, CBinOp::Add | CBinOp::Subtract)); + let is_negative = op == CBinOp::Subtract; + self.convert_pointer_offset(lhs, rhs, pointee.ctype, is_negative, false) + } else if lhs_type_kind.is_unsigned_integral_type() { + WithStmts::new_val(mk().method_call_expr(lhs, op.wrapping_method(), vec![rhs])) } else { - Ok(WithStmts::new_val(mk().binary_expr( - BinOp::Sub(Default::default()), - lhs, - rhs, - ))) - } + WithStmts::new_val(mk().binary_expr(BinOp::from(op), lhs, rhs)) + }; + + self.make_cast( + ctx, + result_type_id, + expected_type_id.unwrap_or(result_type_id), + expr_rs, + ) } pub fn convert_unary_operator( &self, ctx: ExprContext, expected_type_id: Option, - result_type_id: CQualTypeId, + mut result_type_id: CQualTypeId, op: CUnOp, arg: CExprId, ) -> TranslationResult>> { @@ -595,7 +590,10 @@ impl<'c> Translation<'c> { CUnOp::Not => { let val = self.convert_condition(ctx, false, arg)?; - Ok(val.map(|x| mk().cast_expr(x, mk().abs_path_ty(vec!["core", "ffi", "c_int"])))) + let expected_type_id = expected_type_id.unwrap_or(result_type_id); + + result_type_id.ctype = self.ast_context.type_for_kind(&CTypeKind::Bool); + self.make_cast(ctx, result_type_id, expected_type_id, val) } CUnOp::Extension => self.convert_expr(ctx, arg, expected_type_id), CUnOp::Real | CUnOp::Imag | CUnOp::Coawait => { @@ -640,7 +638,7 @@ impl<'c> Translation<'c> { match self.ast_context.resolve_type(arg_type.ctype).kind { CTypeKind::Pointer(..) => { - one_type_id = CQualTypeId::new(self.ast_context.type_for_kind(&CTypeKind::Int)); + one_type_id = CQualTypeId::new(self.ast_context.type_for_kind(&CTypeKind::IntPtr)); } CTypeKind::Enum(enum_id) => { one_type_id = self.enum_underlying_type(enum_id); diff --git a/c2rust-transpile/tests/snapshots/bool.c b/c2rust-transpile/tests/snapshots/bool.c index 0a14e24852..bb08f1074f 100644 --- a/c2rust-transpile/tests/snapshots/bool.c +++ b/c2rust-transpile/tests/snapshots/bool.c @@ -36,3 +36,18 @@ void test_bool() { int1 *= 2.0; double d = int1; } + +void test_bool_operator(void) { + int comp_int = 1 < 0; + long comp_long = 1 < 0; + + int logic_int = 0 || 0; + long logic_long = 0 || 0; + + void *ptr = 0; + int null_ptr_int = ptr == 0; + long null_ptr_long = ptr == 0; + + int not_int = !0; + long not_long = !0; +} diff --git a/c2rust-transpile/tests/snapshots/exprs.c b/c2rust-transpile/tests/snapshots/exprs.c index 328db7ff0a..c03417ad71 100644 --- a/c2rust-transpile/tests/snapshots/exprs.c +++ b/c2rust-transpile/tests/snapshots/exprs.c @@ -42,6 +42,10 @@ void pointer_arithmetic(void) { int *p2 = i2; ptrdiff_t diff = p1 - p2; int diff_int = p1 - p2; + + // The result type is different from the expected type. + unsigned long *unsigned_long_pointer = 0; + size_t *size_pointer = unsigned_long_pointer + 1; } void assign_result(void) { diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@bool.c.2021.clang15.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@bool.c.2021.clang15.snap index 289bb9014f..b88eb22c84 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@bool.c.2021.clang15.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@bool.c.2021.clang15.snap @@ -56,3 +56,17 @@ pub unsafe extern "C" fn test_bool() { int1 = int1 as u8 as ::core::ffi::c_double * 2.0f64 != 0.; let mut d: ::core::ffi::c_double = int1 as u8 as ::core::ffi::c_double; } +#[no_mangle] +pub unsafe extern "C" fn test_bool_operator() { + let mut comp_int: ::core::ffi::c_int = + ((1 as ::core::ffi::c_int) < 0 as ::core::ffi::c_int) as ::core::ffi::c_int; + let mut comp_long: ::core::ffi::c_long = + ((1 as ::core::ffi::c_int) < 0 as ::core::ffi::c_int) as ::core::ffi::c_long; + let mut logic_int: ::core::ffi::c_int = (false || false) as ::core::ffi::c_int; + let mut logic_long: ::core::ffi::c_long = (false || false) as ::core::ffi::c_long; + let mut ptr: *mut ::core::ffi::c_void = ::core::ptr::null_mut::<::core::ffi::c_void>(); + let mut null_ptr_int: ::core::ffi::c_int = ptr.is_null() as ::core::ffi::c_int; + let mut null_ptr_long: ::core::ffi::c_long = ptr.is_null() as ::core::ffi::c_long; + let mut not_int: ::core::ffi::c_int = true as ::core::ffi::c_int; + let mut not_long: ::core::ffi::c_long = true as ::core::ffi::c_long; +} diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@bool.c.2024.clang15.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@bool.c.2024.clang15.snap index dfd0e473f2..11c6b411d8 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@bool.c.2024.clang15.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@bool.c.2024.clang15.snap @@ -57,3 +57,17 @@ pub unsafe extern "C" fn test_bool() { int1 = int1 as u8 as ::core::ffi::c_double * 2.0f64 != 0.; let mut d: ::core::ffi::c_double = int1 as u8 as ::core::ffi::c_double; } +#[unsafe(no_mangle)] +pub unsafe extern "C" fn test_bool_operator() { + let mut comp_int: ::core::ffi::c_int = + ((1 as ::core::ffi::c_int) < 0 as ::core::ffi::c_int) as ::core::ffi::c_int; + let mut comp_long: ::core::ffi::c_long = + ((1 as ::core::ffi::c_int) < 0 as ::core::ffi::c_int) as ::core::ffi::c_long; + let mut logic_int: ::core::ffi::c_int = (false || false) as ::core::ffi::c_int; + let mut logic_long: ::core::ffi::c_long = (false || false) as ::core::ffi::c_long; + let mut ptr: *mut ::core::ffi::c_void = ::core::ptr::null_mut::<::core::ffi::c_void>(); + let mut null_ptr_int: ::core::ffi::c_int = ptr.is_null() as ::core::ffi::c_int; + let mut null_ptr_long: ::core::ffi::c_long = ptr.is_null() as ::core::ffi::c_long; + let mut not_int: ::core::ffi::c_int = true as ::core::ffi::c_int; + let mut not_long: ::core::ffi::c_long = true as ::core::ffi::c_long; +} diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@call_only_once.c.2021.macos.clang15.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@call_only_once.c.2021.macos.clang15.snap index 0607dabce4..13db6c4c76 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@call_only_once.c.2021.macos.clang15.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@call_only_once.c.2021.macos.clang15.snap @@ -26,7 +26,7 @@ unsafe extern "C" fn called_only_once() -> ::core::ffi::c_int { } #[no_mangle] pub unsafe extern "C" fn assert_call_only_once() -> ::core::ffi::c_int { - if (called_only_once() == 0) as ::core::ffi::c_int as ::core::ffi::c_long != 0 { + if called_only_once() == 0 { __assert_rtn( b"assert_call_only_once\0".as_ptr() as *const ::core::ffi::c_char, b"call_only_once.c\0".as_ptr() as *const ::core::ffi::c_char, diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@call_only_once.c.2024.macos.clang15.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@call_only_once.c.2024.macos.clang15.snap index cc01de2d12..e46bbb6a8b 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@call_only_once.c.2024.macos.clang15.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@call_only_once.c.2024.macos.clang15.snap @@ -27,7 +27,7 @@ unsafe extern "C" fn called_only_once() -> ::core::ffi::c_int { } #[unsafe(no_mangle)] pub unsafe extern "C" fn assert_call_only_once() -> ::core::ffi::c_int { - if (called_only_once() == 0) as ::core::ffi::c_int as ::core::ffi::c_long != 0 { + if called_only_once() == 0 { __assert_rtn( b"assert_call_only_once\0".as_ptr() as *const ::core::ffi::c_char, b"call_only_once.c\0".as_ptr() as *const ::core::ffi::c_char, diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2021.clang15.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2021.clang15.snap index b3f01068e6..ae7c77f817 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2021.clang15.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2021.clang15.snap @@ -68,6 +68,10 @@ pub unsafe extern "C" fn pointer_arithmetic() { let mut p2: *mut ::core::ffi::c_int = &raw mut i2 as *mut ::core::ffi::c_int; let mut diff: ptrdiff_t = p1.offset_from(p2); let mut diff_int: ::core::ffi::c_int = p1.offset_from(p2) as ::core::ffi::c_int; + let mut unsigned_long_pointer: *mut ::core::ffi::c_ulong = + ::core::ptr::null_mut::<::core::ffi::c_ulong>(); + let mut size_pointer: *mut size_t = + unsigned_long_pointer.offset(1 as ::core::ffi::c_int as isize) as *mut size_t; } #[no_mangle] pub unsafe extern "C" fn assign_result() { diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2024.clang15.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2024.clang15.snap index 0c463ce4f5..7b1a395910 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2024.clang15.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2024.clang15.snap @@ -68,6 +68,10 @@ pub unsafe extern "C" fn pointer_arithmetic() { let mut p2: *mut ::core::ffi::c_int = &raw mut i2 as *mut ::core::ffi::c_int; let mut diff: ptrdiff_t = p1.offset_from(p2); let mut diff_int: ::core::ffi::c_int = p1.offset_from(p2) as ::core::ffi::c_int; + let mut unsigned_long_pointer: *mut ::core::ffi::c_ulong = + ::core::ptr::null_mut::<::core::ffi::c_ulong>(); + let mut size_pointer: *mut size_t = + unsigned_long_pointer.offset(1 as ::core::ffi::c_int as isize) as *mut size_t; } #[unsafe(no_mangle)] pub unsafe extern "C" fn assign_result() {