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
30 changes: 20 additions & 10 deletions c2rust-transpile/src/c_ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1356,19 +1356,29 @@ impl TypedAstContext {
let lhs_resolved_ty = self.ast_context.resolve_type(lhs_type_id.ctype);
let rhs_resolved_ty = self.ast_context.resolve_type(rhs_type_id.ctype);

let neither_ptr = !lhs_resolved_ty.kind.is_pointer()
&& !rhs_resolved_ty.kind.is_pointer();

if op.all_types_same() && neither_ptr {
if CTypeKind::PULLBACK_KINDS.contains(&lhs_resolved_ty.kind) {
if op == CBinOp::Subtract
&& lhs_resolved_ty.kind.is_pointer()
&& rhs_resolved_ty.kind.is_pointer()
{
// Pointer difference operator should return `ptrdiff_t`.
let new_type_id =
self.ast_context.type_for_kind(&CTypeKind::PtrDiff).unwrap();
Some(CQualTypeId::new(new_type_id))
} else {
let neither_ptr = !lhs_resolved_ty.kind.is_pointer()
&& !rhs_resolved_ty.kind.is_pointer();

if op.all_types_same() && neither_ptr {
if CTypeKind::PULLBACK_KINDS.contains(&lhs_resolved_ty.kind) {
Some(lhs_type_id)
} else {
Some(rhs_type_id)
}
} else if op.is_bitshift() {
Some(lhs_type_id)
} else {
Some(rhs_type_id)
return;
}
} else if op.is_bitshift() {
Some(lhs_type_id)
} else {
return;
}
}
CExprKind::Unary(_ty, op, e, _idk) => op.expected_result_type(
Expand Down
40 changes: 17 additions & 23 deletions c2rust-transpile/src/translator/operators.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,6 @@ impl<'c> Translation<'c> {
ctx = ctx.decay_ref();
}

let ty = self.convert_type(expr_type_id.ctype)?;

let lhs_kind = &self.ast_context.index_unwrap_parens(lhs).kind;
let mut lhs_type_id = lhs_kind.get_qual_type().ok_or_else(|| {
format_translation_err!(
Expand Down Expand Up @@ -174,9 +172,9 @@ impl<'c> Translation<'c> {

lhs_val.zip(rhs_val).and_then_try(|(lhs_val, rhs_val)| {
self.convert_binary_operator(
ctx,
expr_type_id,
op,
ty,
expr_type_id.ctype,
lhs_type_id,
rhs_type_id,
lhs_val,
Expand Down Expand Up @@ -218,12 +216,11 @@ impl<'c> Translation<'c> {
WithStmts::new_val(read.clone()),
)?;

let ty = self.convert_type(compute_res_type_id.ctype)?;
let val = lhs.and_then_try(|lhs| {
self.convert_binary_operator(
ctx,
compute_res_type_id,
bin_op,
ty,
compute_res_type_id.ctype,
compute_lhs_type_id,
rhs_type_id,
lhs,
Expand Down Expand Up @@ -426,12 +423,11 @@ impl<'c> Translation<'c> {
WithStmts::new_val(read.clone()),
)?;

let ty = self.convert_type(result_type_id.ctype)?;
let val = lhs.and_then_try(|lhs|
self.convert_binary_operator(
ctx,
result_type_id,
op,
ty,
result_type_id.ctype,
expr_or_comp_type_id,
rhs_type_id,
lhs,
Expand Down Expand Up @@ -503,23 +499,25 @@ impl<'c> Translation<'c> {
/// arguments be usable as rvalues.
fn convert_binary_operator(
&self,
ctx: ExprContext,
expr_type_id: CQualTypeId,
op: CBinOp,
ty: Box<Type>,
ctype: CTypeId,
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(ctype)
.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(ty, 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])
Expand Down Expand Up @@ -566,7 +564,8 @@ impl<'c> Translation<'c> {

fn convert_subtraction(
&self,
ty: Box<Type>,
ctx: ExprContext,
expr_type_id: CQualTypeId,
lhs_type_id: CQualTypeId,
rhs_type_id: CQualTypeId,
lhs: Box<Expr>,
Expand All @@ -576,14 +575,9 @@ impl<'c> Translation<'c> {
let rhs_type = &self.ast_context.resolve_type(rhs_type_id.ctype).kind;

if let &CTypeKind::Pointer(pointee) = rhs_type {
let mut offset = mk().method_call_expr(lhs, "offset_from", vec![rhs]);

if let Some(sz) = self.compute_size_of_expr(pointee.ctype) {
let div = cast_int(sz, "isize", false);
offset = mk().binary_expr(BinOp::Div(Default::default()), offset, div);
}

Ok(WithStmts::new_val(mk().cast_expr(offset, ty)).set_unsafe())
let val = self.make_pointer_difference(lhs, rhs, pointee.ctype);
let source_type_id = self.ast_context.type_for_kind(&CTypeKind::PtrDiff).unwrap();
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() {
Expand Down
17 changes: 17 additions & 0 deletions c2rust-transpile/src/translator/pointers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,23 @@ impl<'c> Translation<'c> {
WithStmts::new_val(res).set_unsafe()
}

/// Creates a pointer difference expression. Returns an expression of type `isize`.
pub fn make_pointer_difference(
&self,
lhs_rs: Box<Expr>,
rhs_rs: Box<Expr>,
pointee_type_id: CTypeId,
) -> WithStmts<Box<Expr>> {
let mut expr_rs = mk().method_call_expr(lhs_rs, "offset_from", vec![rhs_rs]);

if let Some(sz) = self.compute_size_of_expr(pointee_type_id) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this needed? If lhs_rs is already of type *mut $pointee_type then offset_from returns the size in units of $pointee_type. There is byte_offset_from for the byte distance. Am I missing something here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure. I left it unchanged because it was already in the original code.

let div_rs = cast_int(sz, "isize", false);
expr_rs = mk().binary_expr(BinOp::Div(Default::default()), expr_rs, div_rs);
}

WithStmts::new_val(expr_rs).set_unsafe()
}

/// Construct an expression for a NULL at any type, including forward declarations,
/// function pointers, and normal pointers.
pub fn null_ptr(&self, type_id: CTypeId) -> TranslationResult<Box<Expr>> {
Expand Down
11 changes: 11 additions & 0 deletions c2rust-transpile/tests/snapshots/exprs.c
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#include <stddef.h>

int puts(const char *str);

static int side_effect(){
Expand Down Expand Up @@ -66,3 +68,12 @@ void statement_expr() {

puts("should be unreachable!");
}

void pointer_arithmetic(void) {
int i1[] = { 0, 1 };
int i2[] = { 10, 11 };
int *p1 = i1;
int *p2 = i2;
ptrdiff_t diff = p1 - p2;
int diff_int = p1 - p2;
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ expression: cat tests/snapshots/exprs.2021.clang15.rs
extern "C" {
fn puts(str: *const ::core::ffi::c_char) -> ::core::ffi::c_int;
}
pub type ptrdiff_t = isize;
pub type E = ::core::ffi::c_uint;
pub const EA: E = 0;
pub type int_t = ::core::ffi::c_int;
Expand Down Expand Up @@ -82,3 +83,12 @@ pub unsafe extern "C" fn statement_expr() {
};
puts(b"should be unreachable!\0".as_ptr() as *const ::core::ffi::c_char);
}
#[no_mangle]
pub unsafe extern "C" fn pointer_arithmetic() {
let mut i1: [::core::ffi::c_int; 2] = [0 as ::core::ffi::c_int, 1 as ::core::ffi::c_int];
let mut i2: [::core::ffi::c_int; 2] = [10 as ::core::ffi::c_int, 11 as ::core::ffi::c_int];
let mut p1: *mut ::core::ffi::c_int = &raw mut i1 as *mut ::core::ffi::c_int;
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;
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ expression: cat tests/snapshots/exprs.2024.clang15.rs
unsafe extern "C" {
unsafe fn puts(str: *const ::core::ffi::c_char) -> ::core::ffi::c_int;
}
pub type ptrdiff_t = isize;
pub type E = ::core::ffi::c_uint;
pub const EA: E = 0;
pub type int_t = ::core::ffi::c_int;
Expand Down Expand Up @@ -82,3 +83,12 @@ pub unsafe extern "C" fn statement_expr() {
};
puts(b"should be unreachable!\0".as_ptr() as *const ::core::ffi::c_char);
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn pointer_arithmetic() {
let mut i1: [::core::ffi::c_int; 2] = [0 as ::core::ffi::c_int, 1 as ::core::ffi::c_int];
let mut i2: [::core::ffi::c_int; 2] = [10 as ::core::ffi::c_int, 11 as ::core::ffi::c_int];
let mut p1: *mut ::core::ffi::c_int = &raw mut i1 as *mut ::core::ffi::c_int;
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;
}
Loading