Skip to content
Merged
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
21 changes: 19 additions & 2 deletions c2rust-ast-builder/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use syn::{__private::ToTokens, punctuated::Punctuated, *};

pub mod properties {
use proc_macro2::Span;
use syn::{StaticMutability, Token};
use syn::{PointerMutability, StaticMutability, Token};

pub trait ToToken {
type Token;
Expand All @@ -34,6 +34,13 @@ pub mod properties {
}

impl Mutability {
pub fn to_pointer_mutability(&self, span: Span) -> PointerMutability {
match self {
Mutability::Mutable => PointerMutability::Mut(Token![mut](span)),
Mutability::Immutable => PointerMutability::Const(Token![const](span)),
}
}

pub fn to_static_mutability(&self, span: Span) -> StaticMutability {
match self {
Mutability::Mutable => StaticMutability::Mut(Token![mut](span)),
Expand Down Expand Up @@ -837,7 +844,7 @@ impl Builder {
self.path_expr(vec![name])
}

pub fn addr_of_expr(self, e: Box<Expr>) -> Box<Expr> {
pub fn borrow_expr(self, e: Box<Expr>) -> Box<Expr> {
Box::new(parenthesize_if_necessary(Expr::Reference(ExprReference {
attrs: self.attrs,
and_token: Token![&](self.span),
Expand All @@ -846,6 +853,16 @@ impl Builder {
})))
}

pub fn raw_borrow_expr(self, e: Box<Expr>) -> Box<Expr> {
Box::new(parenthesize_if_necessary(Expr::RawAddr(ExprRawAddr {
attrs: self.attrs,
and_token: Token![&](self.span),
raw: Token![raw](self.span),
mutability: self.mutbl.to_pointer_mutability(self.span),
expr: e,
})))
}

pub fn mac_expr(self, mac: Macro) -> Box<Expr> {
Box::new(Expr::Macro(ExprMacro {
attrs: self.attrs,
Expand Down
1 change: 1 addition & 0 deletions c2rust-transpile/src/rust_ast/set_span.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ impl SetSpan for Expr {
RangeLimits::Closed(mut r) => r.spans[0] = s,
RangeLimits::HalfOpen(mut r) => r.spans[0] = s,
},
Expr::RawAddr(e) => e.and_token.span = s,
Expr::Reference(e) => e.and_token.span = s,
Expr::Return(e) => e.return_token.span = s,
Expr::Try(e) => e.question_token.span = s,
Expand Down
6 changes: 3 additions & 3 deletions c2rust-transpile/src/translator/assembly.rs
Original file line number Diff line number Diff line change
Expand Up @@ -883,7 +883,7 @@ impl<'c> Translation<'c> {
// c2rust-ast-exporter added it (there's no gcc equivalent);
// in this case, we need to do what clang does and pass in
// the operand by-address instead of by-value
out_expr = mk().mutbl().addr_of_expr(out_expr);
out_expr = mk().mutbl().borrow_expr(out_expr);
}

if let Some(_tied_operand) = tied_operands.get(&(output_idx, true)) {
Expand All @@ -900,7 +900,7 @@ impl<'c> Translation<'c> {
let output_local = mk().local(
mk().ident_pat(&output_name),
None,
Some(mk().mutbl().addr_of_expr(out_expr)),
Some(mk().mutbl().borrow_expr(out_expr)),
);
stmts.push(mk().local_stmt(Box::new(output_local)));

Expand All @@ -924,7 +924,7 @@ impl<'c> Translation<'c> {
let mut in_expr = in_expr.into_value();

if operand.mem_only {
in_expr = mk().addr_of_expr(in_expr);
in_expr = mk().borrow_expr(in_expr);
}
if let Some(tied_operand) = tied_operands.get(&(input_idx, false)) {
self.use_crate(ExternCrate::C2RustAsmCasts);
Expand Down
2 changes: 1 addition & 1 deletion c2rust-transpile/src/translator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3082,7 +3082,7 @@ impl<'c> Translation<'c> {
}
}
_ => {
let addr_lhs = mk().set_mutbl(mutbl).addr_of_expr(lhs);
let addr_lhs = mk().set_mutbl(mutbl).borrow_expr(lhs);

let lhs_type = self.convert_type(lhs_type.ctype)?;
let ty = mk().set_mutbl(mutbl).ptr_ty(lhs_type);
Expand Down
23 changes: 21 additions & 2 deletions c2rust-transpile/src/translator/pointers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,17 @@ impl<'c> Translation<'c> {
Some(mk().array_ty(mk().ident_ty("u8"), mk().lit_expr(len as u128)));
}
needs_cast = true;
} else {
}
// Values that translate into temporaries can't be raw-borrowed in Rust,
// and must be regular-borrowed first.
// Borrowing in a static/const context will extend the lifetime to static.
else if arg_is_macro
|| ctx.is_static
&& matches!(
arg_expr_kind,
Some(CExprKind::Literal(..) | CExprKind::CompoundLiteral(..))
)
{
let arg_cty_kind = &self.ast_context.resolve_type(arg_cty.ctype).kind;

if is_array_decay {
Expand All @@ -160,14 +170,23 @@ impl<'c> Translation<'c> {
needs_cast = true;
}
} else {
val = val.map(|val| mk().set_mutbl(mutbl).addr_of_expr(val));
val = val.map(|val| mk().set_mutbl(mutbl).borrow_expr(val));

// Add an intermediate reference-to-pointer cast if the context needs
// reference-to-pointer decay, or if another cast follows.
if ctx.decay_ref.is_yes() || needs_cast {
ref_cast_pointee_ty = Some(self.convert_pointee_type(arg_cty.ctype)?);
}
}
} else {
self.use_feature("raw_ref_op");
val = val.map(|val| mk().set_mutbl(mutbl).raw_borrow_expr(val));

if is_array_decay {
// TODO: Call `ptr::as_[mut]_ptr` instead once that is available.
// (`array_ptr_get` feature added to nightly in January 2024)
needs_cast = true;
}
}

// Perform an intermediate reference-to-pointer cast if needed.
Expand Down
17 changes: 17 additions & 0 deletions c2rust-transpile/tests/snapshots/ref_ub.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// From #301.

typedef struct {
int len;
} Foo;

void dec(Foo* f) {
f->len--;
}

int main() {
Foo f = {5};
Foo *fp = &f;
dec(fp);
f.len = 6;
dec(fp);
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ input_file: c2rust-transpile/tests/snapshots/arch-specific/vm_x86.c
unused_assignments,
unused_mut
)]
#![feature(raw_ref_op)]
#[derive(Copy, Clone)]
#[repr(C)]
pub struct vm_t {
Expand Down Expand Up @@ -52,8 +53,8 @@ pub unsafe extern "C" fn VM_CallCompiled(
*(image.offset(programStack as isize) as *mut byte as *mut ::core::ffi::c_int) =
-(1 as ::core::ffi::c_int);
entryPoint = (*vm).codeBase.offset((*vm).entryOfs as isize);
opStack =
(stack.as_mut_ptr() as *mut ::core::ffi::c_int).offset(16 as ::core::ffi::c_int as isize);
opStack = (&raw mut stack as *mut byte as *mut ::core::ffi::c_int)
.offset(16 as ::core::ffi::c_int as isize);
*opStack = 0 as ::core::ffi::c_int;
opStackOfs = 0 as ::core::ffi::c_int;
if opStackOfs != 1 as ::core::ffi::c_int
Expand Down
8 changes: 4 additions & 4 deletions c2rust-transpile/tests/snapshots/[email protected]
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ input_file: c2rust-transpile/tests/snapshots/arch-os-specific/varargs.c
unused_assignments,
unused_mut
)]
#![feature(c_variadic)]
#![feature(c_variadic, raw_ref_op)]
extern "C" {
fn printf(__format: *const ::core::ffi::c_char, ...) -> ::core::ffi::c_int;
fn vprintf(
Expand Down Expand Up @@ -129,8 +129,8 @@ pub unsafe extern "C" fn valist_struct_pointer_member(
let mut b: vastruct = vastruct {
args: ::core::mem::MaybeUninit::uninit().assume_init(),
};
let mut p: *mut vastruct = &mut a;
let mut q: *mut vastruct = &mut b;
let mut p: *mut vastruct = &raw mut a;
let mut q: *mut vastruct = &raw mut b;
(*p).args = args.clone();
(*q).args = (*p).args.clone();
vprintf(fmt, (*p).args.as_va_list());
Expand All @@ -156,7 +156,7 @@ pub unsafe extern "C" fn borrowed_valist(mut count: size_t, mut args: ...) {
let mut ap: ::core::ffi::VaListImpl;
ap = args.clone();
while count > 0 as size_t {
print_int(&mut ap);
print_int(&raw mut ap);
count = count.wrapping_sub(1);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ input_file: c2rust-transpile/tests/snapshots/arch-specific/vm_x86.c
unused_assignments,
unused_mut
)]
#![feature(asm)]
#![feature(asm, raw_ref_op)]
use ::core::arch::asm;
#[derive(Copy, Clone)]
#[repr(C)]
Expand Down Expand Up @@ -54,8 +54,8 @@ pub unsafe extern "C" fn VM_CallCompiled(
*(image.offset(programStack as isize) as *mut byte as *mut ::core::ffi::c_int) =
-(1 as ::core::ffi::c_int);
entryPoint = (*vm).codeBase.offset((*vm).entryOfs as isize);
opStack =
(stack.as_mut_ptr() as *mut ::core::ffi::c_int).offset(16 as ::core::ffi::c_int as isize);
opStack = (&raw mut stack as *mut byte as *mut ::core::ffi::c_int)
.offset(16 as ::core::ffi::c_int as isize);
*opStack = 0 as ::core::ffi::c_int;
opStackOfs = 0 as ::core::ffi::c_int;
asm!(
Expand Down
17 changes: 10 additions & 7 deletions c2rust-transpile/tests/snapshots/[email protected]
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ input_file: c2rust-transpile/tests/snapshots/arrays.c
unused_assignments,
unused_mut
)]
#![feature(raw_ref_op)]
#[derive(Copy, Clone)]
#[repr(C)]
pub struct C2RustUnnamed {
Expand Down Expand Up @@ -42,7 +43,7 @@ pub static mut static_char_ptr: *mut ::core::ffi::c_char =
b"mystring\0" as *const u8 as *const ::core::ffi::c_char as *mut ::core::ffi::c_char;
#[no_mangle]
pub static mut static_void_ptr: *mut ::core::ffi::c_void =
unsafe { static_char_array.as_ptr() as *mut ::core::ffi::c_char as *mut ::core::ffi::c_void };
unsafe { &raw const static_char_array as *mut ::core::ffi::c_char as *mut ::core::ffi::c_void };
#[no_mangle]
pub unsafe extern "C" fn entry() {
let mut int_2d: [[::core::ffi::c_int; 1]; 1] = [[1 as ::core::ffi::c_int]];
Expand Down Expand Up @@ -84,10 +85,12 @@ pub unsafe extern "C" fn entry() {
::core::mem::transmute::<[u8; 20], [::core::ffi::c_char; 20]>(
*b"abc\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",
);
let mut int_var_ptr: *mut ::core::ffi::c_int = int_empty_init.as_mut_ptr();
let mut int_var_array_ptr: *mut [::core::ffi::c_int; 16] = &mut int_empty_init;
let mut char_var_ptr: *mut ::core::ffi::c_char = char_with_string.as_mut_ptr();
let mut char_var_array_ptr: *mut [::core::ffi::c_char; 4] = &mut char_with_string;
let mut int_var_ptr: *mut ::core::ffi::c_int =
&raw mut int_empty_init as *mut ::core::ffi::c_int;
let mut int_var_array_ptr: *mut [::core::ffi::c_int; 16] = &raw mut int_empty_init;
let mut char_var_ptr: *mut ::core::ffi::c_char =
&raw mut char_with_string as *mut ::core::ffi::c_char;
let mut char_var_array_ptr: *mut [::core::ffi::c_char; 4] = &raw mut char_with_string;
let mut const_char_lit_ptr: *const ::core::ffi::c_char =
b"abc\0" as *const u8 as *const ::core::ffi::c_char;
let mut const_char_lit_array_ptr: *const [::core::ffi::c_char; 4] =
Expand All @@ -97,8 +100,8 @@ pub unsafe extern "C" fn entry() {
let mut char_lit_array_ptr: *mut [::core::ffi::c_char; 4] = b"abc\0" as *const [u8; 4]
as *const [::core::ffi::c_char; 4]
as *mut [::core::ffi::c_char; 4];
let mut past_end: *mut ::core::ffi::c_char = static_char_array
.as_mut_ptr()
let mut past_end: *mut ::core::ffi::c_char = (&raw mut static_char_array
as *mut ::core::ffi::c_char)
.offset(::core::mem::size_of::<[::core::ffi::c_char; 9]>() as isize)
as *mut ::core::ffi::c_char;
past_end = static_char_ptr.offset(8 as ::core::ffi::c_int as isize) as *mut ::core::ffi::c_char;
Expand Down
29 changes: 15 additions & 14 deletions c2rust-transpile/tests/snapshots/[email protected]
Original file line number Diff line number Diff line change
Expand Up @@ -11,28 +11,29 @@ input_file: c2rust-transpile/tests/snapshots/atomics.c
unused_assignments,
unused_mut
)]
#![feature(core_intrinsics)]
#![feature(core_intrinsics, raw_ref_op)]
#[no_mangle]
pub unsafe extern "C" fn c11_atomics(mut x: ::core::ffi::c_int) -> ::core::ffi::c_int {
*&mut x = 0 as ::core::ffi::c_int;
::core::intrinsics::atomic_store_seqcst(&mut x, 1 as ::core::ffi::c_int);
::core::intrinsics::atomic_load_seqcst(&mut x);
::core::intrinsics::atomic_xadd_seqcst(&mut x, 2 as ::core::ffi::c_int);
::core::intrinsics::atomic_xsub_seqcst(&mut x, 1 as ::core::ffi::c_int);
::core::intrinsics::atomic_and_seqcst(&mut x, 0xf as ::core::ffi::c_int);
::core::intrinsics::atomic_or_seqcst(&mut x, 0x10 as ::core::ffi::c_int);
::core::intrinsics::atomic_nand_seqcst(&mut x, 0xff as ::core::ffi::c_int);
::core::intrinsics::atomic_xchg_seqcst(&mut x, 42 as ::core::ffi::c_int);
*&raw mut x = 0 as ::core::ffi::c_int;
::core::intrinsics::atomic_store_seqcst(&raw mut x, 1 as ::core::ffi::c_int);
::core::intrinsics::atomic_load_seqcst(&raw mut x);
::core::intrinsics::atomic_xadd_seqcst(&raw mut x, 2 as ::core::ffi::c_int);
::core::intrinsics::atomic_xsub_seqcst(&raw mut x, 1 as ::core::ffi::c_int);
::core::intrinsics::atomic_and_seqcst(&raw mut x, 0xf as ::core::ffi::c_int);
::core::intrinsics::atomic_or_seqcst(&raw mut x, 0x10 as ::core::ffi::c_int);
::core::intrinsics::atomic_nand_seqcst(&raw mut x, 0xff as ::core::ffi::c_int);
::core::intrinsics::atomic_xchg_seqcst(&raw mut x, 42 as ::core::ffi::c_int);
let mut expected: ::core::ffi::c_int = 42 as ::core::ffi::c_int;
let mut desired: ::core::ffi::c_int = 100 as ::core::ffi::c_int;
let fresh0 = ::core::intrinsics::atomic_cxchg_seqcst_seqcst(&mut x, *&mut expected, desired);
*&mut expected = fresh0.0;
let fresh0 =
::core::intrinsics::atomic_cxchg_seqcst_seqcst(&raw mut x, *&raw mut expected, desired);
*&raw mut expected = fresh0.0;
fresh0.1;
expected = 100 as ::core::ffi::c_int;
desired = 200 as ::core::ffi::c_int;
let fresh1 =
::core::intrinsics::atomic_cxchgweak_seqcst_seqcst(&mut x, *&mut expected, desired);
*&mut expected = fresh1.0;
::core::intrinsics::atomic_cxchgweak_seqcst_seqcst(&raw mut x, *&raw mut expected, desired);
*&raw mut expected = fresh1.0;
fresh1.1;
return x;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ input_file: c2rust-transpile/tests/snapshots/compound_literals.c
unused_assignments,
unused_mut
)]
#![feature(raw_ref_op)]
#[no_mangle]
pub static mut static_single_int: ::core::ffi::c_int = 42;
#[no_mangle]
Expand All @@ -34,21 +35,20 @@ pub const CHAR_ARRAY: [::core::ffi::c_char; 6] =
pub unsafe extern "C" fn local_compound_literals() {
let mut single_int: ::core::ffi::c_int = 42 as ::core::ffi::c_int;
let mut fresh0: ::core::ffi::c_int = 42 as ::core::ffi::c_int;
let mut single_int_ptr: *mut ::core::ffi::c_int = &mut fresh0 as *mut ::core::ffi::c_int;
let mut single_int_ptr: *mut ::core::ffi::c_int = &raw mut fresh0;
let mut fresh1: [::core::ffi::c_int; 2] =
[42 as ::core::ffi::c_int, 9001 as ::core::ffi::c_int];
let mut int_ptr_to_array: *mut ::core::ffi::c_int = fresh1.as_mut_ptr();
let mut int_ptr_to_array: *mut ::core::ffi::c_int = &raw mut fresh1 as *mut ::core::ffi::c_int;
let mut fresh2: [::core::ffi::c_char; 6] =
::core::mem::transmute::<[u8; 6], [::core::ffi::c_char; 6]>(*b"hello\0");
let mut char_ptr_to_array: *mut ::core::ffi::c_char = fresh2.as_mut_ptr();
let mut char_ptr_to_array: *mut ::core::ffi::c_char =
&raw mut fresh2 as *mut ::core::ffi::c_char;
let mut fresh3: [::core::ffi::c_int; 2] =
[42 as ::core::ffi::c_int, 9001 as ::core::ffi::c_int];
let mut int_array_ptr: *mut [::core::ffi::c_int; 2] =
&mut fresh3 as *mut [::core::ffi::c_int; 2];
let mut int_array_ptr: *mut [::core::ffi::c_int; 2] = &raw mut fresh3;
let mut fresh4: [::core::ffi::c_char; 6] =
::core::mem::transmute::<[u8; 6], [::core::ffi::c_char; 6]>(*b"hello\0");
let mut char_array_ptr: *mut [::core::ffi::c_char; 6] =
&mut fresh4 as *mut [::core::ffi::c_char; 6];
let mut char_array_ptr: *mut [::core::ffi::c_char; 6] = &raw mut fresh4;
let mut macro_single_int: ::core::ffi::c_int = SINGLE_INT;
let mut macro_single_int_ptr: *mut ::core::ffi::c_int =
&mut SINGLE_INT as *mut ::core::ffi::c_int;
Expand Down
3 changes: 2 additions & 1 deletion c2rust-transpile/tests/snapshots/[email protected]
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ input_file: c2rust-transpile/tests/snapshots/exprs.c
unused_assignments,
unused_mut
)]
#![feature(raw_ref_op)]
extern "C" {
fn puts(str: *const ::core::ffi::c_char) -> ::core::ffi::c_int;
}
Expand All @@ -29,7 +30,7 @@ pub unsafe extern "C" fn unary_without_side_effect() {
i;
!i;
(i == 0) as ::core::ffi::c_int;
&mut i;
&raw mut i;
i;
i += 1;
i -= 1;
Expand Down
5 changes: 3 additions & 2 deletions c2rust-transpile/tests/snapshots/[email protected]
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ input_file: c2rust-transpile/tests/snapshots/macros.c
unused_assignments,
unused_mut
)]
#![feature(raw_ref_op)]
extern "C" {
fn extern_fn() -> ::core::ffi::c_int;
}
Expand Down Expand Up @@ -370,7 +371,7 @@ pub static mut fns: fn_ptrs = {
init
};
#[no_mangle]
pub static mut p: *const fn_ptrs = unsafe { &fns };
pub static mut p: *const fn_ptrs = unsafe { &raw const fns };
pub const ZSTD_WINDOWLOG_MAX_32: ::core::ffi::c_int = 30 as ::core::ffi::c_int;
pub const ZSTD_WINDOWLOG_MAX_64: ::core::ffi::c_int = 31 as ::core::ffi::c_int;
#[no_mangle]
Expand All @@ -384,7 +385,7 @@ pub unsafe extern "C" fn test_zstd() -> U64 {
#[no_mangle]
pub unsafe extern "C" fn stmt_expr_inc() -> ::core::ffi::c_int {
let mut a: ::core::ffi::c_int = 0 as ::core::ffi::c_int;
let mut b: *mut ::core::ffi::c_int = &mut a;
let mut b: *mut ::core::ffi::c_int = &raw mut a;
({
*b += 1;
*b;
Expand Down
Loading