Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 12 additions & 5 deletions c2rust-transpile/src/translator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1594,11 +1594,6 @@ fn arrange_header(t: &Translation, is_binary: bool) -> (Vec<syn::Attribute>, Vec
(out_attrs, out_items)
}

/// Convert a boolean expression to a c_int
fn bool_to_int(val: Box<Expr>) -> Box<Expr> {
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<syn::Attribute>, src_loc: &Option<SrcLoc>) {
if let Some(src_loc) = src_loc.as_ref() {
Expand Down Expand Up @@ -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;
}
}

_ => {}
}

Expand Down
168 changes: 83 additions & 85 deletions c2rust-transpile/src/translator/operators.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ impl<'c> Translation<'c> {
&self,
mut ctx: ExprContext,
expected_type_id: Option<CQualTypeId>,
result_type_id: CQualTypeId,
mut result_type_id: CQualTypeId,
op: CBinOp,
lhs: CExprId,
rhs: CExprId,
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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;
}
}

Expand All @@ -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))?;
Expand All @@ -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| {
Expand All @@ -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);
}
}

Expand All @@ -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,
Expand Down Expand Up @@ -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,
Expand All @@ -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()
Expand Down Expand Up @@ -471,106 +482,90 @@ impl<'c> Translation<'c> {
fn convert_binary_operator(
&self,
ctx: ExprContext,
expr_type_id: CQualTypeId,
expected_type_id: Option<CQualTypeId>,
mut result_type_id: CQualTypeId,
op: CBinOp,
lhs_type: CQualTypeId,
rhs_type: CQualTypeId,
lhs: Box<Expr>,
rhs: Box<Expr>,
) -> TranslationResult<WithStmts<Box<Expr>>> {
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<Expr>,
rhs: Box<Expr>,
) -> TranslationResult<WithStmts<Box<Expr>>> {
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<CQualTypeId>,
result_type_id: CQualTypeId,
op: CBinOp,
lhs_type_id: CQualTypeId,
rhs_type_id: CQualTypeId,
lhs: Box<Expr>,
rhs: Box<Expr>,
) -> TranslationResult<WithStmts<Box<Expr>>> {
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<CQualTypeId>,
result_type_id: CQualTypeId,
mut result_type_id: CQualTypeId,
op: CUnOp,
arg: CExprId,
) -> TranslationResult<WithStmts<Box<Expr>>> {
Expand All @@ -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 => {
Expand Down Expand Up @@ -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);
Expand Down
15 changes: 15 additions & 0 deletions c2rust-transpile/tests/snapshots/bool.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
4 changes: 4 additions & 0 deletions c2rust-transpile/tests/snapshots/exprs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Loading
Loading