Incorrect Use of `.offset_from(1)` When Transpiling Pointer Decrement on Struct Field
Description
C2Rust incorrectly translates valid C code containing a pointer decrement on a volatile struct field, such as --(global.p);, into Rust using .offset_from(1), which is invalid and causes a type mismatch at compile time.
C code:
int arr[10];
struct S { int * volatile p; } global;
int func(int *restrict r) {
--(global.p);
return *r;
}
int main() {
return 0;
}
Translated Rust Code
#[derive(Copy, Clone)]
#[repr(C)]
pub struct S {
pub p: *mut libc::c_int,
}
#[no_mangle]
pub static mut arr: [libc::c_int; 10] = [0; 10];
#[no_mangle]
pub static mut global: S = S {
p: 0 as *const libc::c_int as *mut libc::c_int,
};
#[no_mangle]
pub unsafe extern "C" fn func(mut r: *mut libc::c_int) -> libc::c_int {
::core::ptr::write_volatile(
&mut global.p as *mut *mut libc::c_int,
(::core::ptr::read_volatile::<
*mut libc::c_int,
>(&global.p as *const *mut libc::c_int))
.offset_from(1) as *mut libc::c_int,
);
::core::ptr::read_volatile::<*mut libc::c_int>(&global.p as *const *mut libc::c_int);
return *r;
}
Cargo build error:
error[E0308]: mismatched types
--> src/runner.rs:29:26
|
29 | .offset_from(1) as *mut libc::c_int,
| ----------- ^ expected `*const i32`, found `usize`
| |
| arguments to this method are incorrect
|
= note: expected raw pointer `*const i32`
found type `usize`
note: method defined here
--> /rustc/05f9846f893b09a1be1fc8560e33fc3c815cfecb/library/core/src/ptr/mut_ptr.rs:856:25
c2rust version: C2Rust 0.20.0
I think I found the source of the problem: https://github.com/immunant/c2rust/blob/12dfbc7526e857b51a2d4dd9046f7d25811d52b6/c2rust-transpile/src/translator/operators.rs#L800
ty is passed here as the type of the "implied" operand of the decrement operator. In other words, the type of the 1 in foo -= 1. For numeric types, that works, since the subtracted value is the same type as the variable. But when the type is a pointer, the subtracted value is an integer, not another pointer. So it's trying to translate this as pointer-pointer subtraction instead.