Skip to content

Commit 4304aca

Browse files
committed
transpile: Use raw borrows instead of normal borrows
1 parent 68e0293 commit 4304aca

24 files changed

+195
-140
lines changed

c2rust-transpile/src/translator/mod.rs

Lines changed: 55 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -4595,60 +4595,67 @@ impl<'c> Translation<'c> {
45954595
.is_some()
45964596
})
45974597
.unwrap_or(false);
4598-
match expr_kind {
4599-
Some(&CExprKind::Literal(_, CLiteral::String(ref bytes, 1)))
4600-
if is_const && !translate_as_macro =>
4601-
{
4602-
let target_ty = self.convert_type(target_cty.ctype)?;
46034598

4604-
let mut bytes = bytes.to_owned();
4605-
bytes.push(0);
4606-
let byte_literal = mk().lit_expr(bytes);
4607-
let val =
4608-
mk().cast_expr(byte_literal, mk().ptr_ty(mk().path_ty(vec!["u8"])));
4609-
let val = mk().cast_expr(val, target_ty);
4610-
Ok(WithStmts::new_val(val))
4611-
}
4612-
_ => {
4613-
// Variable length arrays are already represented as pointers.
4614-
if let CTypeKind::VariableArray(..) = source_ty_kind {
4615-
Ok(val)
4616-
} else {
4617-
let method = if is_const || ctx.is_static {
4618-
"as_ptr"
4619-
} else {
4620-
"as_mut_ptr"
4621-
};
4599+
if let (Some(&CExprKind::Literal(_, CLiteral::String(ref bytes, 1))), true, false) =
4600+
(expr_kind, is_const, translate_as_macro)
4601+
{
4602+
let target_ty = self.convert_type(target_cty.ctype)?;
4603+
4604+
let mut bytes = bytes.to_owned();
4605+
bytes.push(0);
4606+
let byte_literal = mk().lit_expr(bytes);
4607+
let val = mk().cast_expr(byte_literal, mk().ptr_ty(mk().path_ty(vec!["u8"])));
4608+
let val = mk().cast_expr(val, target_ty);
4609+
return Ok(WithStmts::new_val(val));
4610+
}
46224611

4623-
let call = val.map(|x| mk().method_call_expr(x, method, vec![]));
4612+
// Variable length arrays are already represented as pointers.
4613+
if let CTypeKind::VariableArray(..) = source_ty_kind {
4614+
return Ok(val);
4615+
}
46244616

4625-
// If the target pointee type is different from the source element type,
4626-
// then we need to cast the ptr type as well.
4627-
let call = match source_ty_kind.element_ty() {
4628-
None => call,
4629-
Some(source_element_ty) if source_element_ty == pointee.ctype => {
4630-
call
4631-
}
4632-
Some(_) => {
4633-
let target_ty = self.convert_type(target_cty.ctype)?;
4634-
call.map(|ptr| mk().cast_expr(ptr, target_ty))
4635-
}
4636-
};
4617+
let (mutbl, must_cast_mut) = if is_const {
4618+
(Mutability::Immutable, false)
4619+
} else if ctx.is_static {
4620+
// TODO: The currently used nightly doesn't allow `&raw mut` in
4621+
// static initialisers, but it's allowed since version 1.83.
4622+
// So we take a `&raw const` and then cast.
4623+
// Remove `must_cast_mut` variable when the version is updated.
4624+
(Mutability::Immutable, true)
4625+
} else {
4626+
(Mutability::Mutable, false)
4627+
};
46374628

4638-
// Static arrays can now use as_ptr. Can also cast that const ptr to a
4639-
// mutable pointer as we do here:
4640-
if ctx.is_static && !is_const {
4641-
return Ok(call.map(|val| {
4642-
let inferred_type = mk().infer_ty();
4643-
let ptr_type = mk().mutbl().ptr_ty(inferred_type);
4644-
mk().cast_expr(val, ptr_type)
4645-
}));
4646-
}
4629+
val.result_map(|mut val| {
4630+
if translate_as_macro {
4631+
// Values that translate into temporaries can't be raw-borrowed in Rust,
4632+
// and must be regular-borrowed first.
4633+
// By borrowing, the lifetime will be extended to static.
4634+
let method = match mutbl {
4635+
Mutability::Mutable => "as_mut_ptr",
4636+
Mutability::Immutable => "as_ptr",
4637+
};
4638+
val = mk().method_call_expr(val, method, vec![]);
4639+
} else {
4640+
self.use_feature("raw_ref_op");
4641+
val = mk().set_mutbl(mutbl).raw_borrow_expr(val);
4642+
// TODO: Add call to `ptr::as_[mut]_ptr` once that is available
4643+
// (`array_ptr_get` feature added to nightly in January 2024)
4644+
}
46474645

4648-
Ok(call)
4649-
}
4646+
// If the target pointee type is different from the source element type,
4647+
// then we need to cast the ptr type as well.
4648+
// TODO: Remove `!translate_as_macro` when `ptr::as_[mut]_ptr` is added above.
4649+
if source_ty_kind.element_ty() != Some(pointee.ctype)
4650+
|| must_cast_mut
4651+
|| !translate_as_macro
4652+
{
4653+
let target_element_ty = self.convert_type(target_cty.ctype)?;
4654+
val = mk().cast_expr(val, target_element_ty);
46504655
}
4651-
}
4656+
4657+
Ok(val)
4658+
})
46524659
}
46534660

46544661
CastKind::NullToPointer => {

c2rust-transpile/src/translator/operators.rs

Lines changed: 63 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -938,54 +938,76 @@ impl<'c> Translation<'c> {
938938
// In this translation, there are only pointers to functions and
939939
// & becomes a no-op when applied to a function.
940940

941-
let arg = self.convert_expr(ctx.used().set_needs_address(true), arg, None)?;
941+
let val = self.convert_expr(ctx.used().set_needs_address(true), arg, None)?;
942942

943943
if self.ast_context.is_function_pointer(ctype) {
944-
Ok(arg.map(|x| mk().call_expr(mk().ident_expr("Some"), vec![x])))
944+
return Ok(val.map(|x| mk().call_expr(mk().ident_expr("Some"), vec![x])));
945+
}
946+
947+
let pointee_ty =
948+
self.ast_context
949+
.get_pointee_qual_type(ctype)
950+
.ok_or_else(|| {
951+
TranslationError::generic("Address-of should return a pointer")
952+
})?;
953+
954+
let translate_as_macro = self
955+
.convert_const_macro_expansion(ctx, arg, None)
956+
.ok()
957+
.flatten()
958+
.is_some();
959+
960+
let (mutbl, must_cast_mut) = if pointee_ty.qualifiers.is_const {
961+
(Mutability::Immutable, false)
962+
} else if ctx.is_static {
963+
// TODO: The currently used nightly doesn't allow `&raw mut` in
964+
// static initialisers, but it's allowed since version 1.83.
965+
// So we take a `&raw const` and then cast.
966+
// Remove `must_cast_mut` variable when the version is updated.
967+
(Mutability::Immutable, true)
945968
} else {
946-
let pointee_ty =
947-
self.ast_context
948-
.get_pointee_qual_type(ctype)
949-
.ok_or_else(|| {
950-
TranslationError::generic("Address-of should return a pointer")
951-
})?;
952-
953-
let mutbl = if pointee_ty.qualifiers.is_const {
954-
Mutability::Immutable
955-
} else {
956-
Mutability::Mutable
957-
};
969+
(Mutability::Mutable, false)
970+
};
958971

959-
arg.result_map(|a| {
960-
let mut addr_of_arg: Box<Expr>;
961-
962-
if ctx.is_static {
963-
// static variable initializers aren't able to use &mut,
964-
// so we work around that by using & and an extra cast
965-
// through & to *const to *mut
966-
addr_of_arg = mk().borrow_expr(a);
967-
if let Mutability::Mutable = mutbl {
968-
let mut qtype = pointee_ty;
969-
qtype.qualifiers.is_const = true;
970-
let ty_ = self
971-
.type_converter
972-
.borrow_mut()
973-
.convert_pointer(&self.ast_context, qtype)?;
974-
addr_of_arg = mk().cast_expr(addr_of_arg, ty_);
975-
}
976-
} else {
977-
// Normal case is allowed to use &mut if needed
978-
addr_of_arg = mk().set_mutbl(mutbl).borrow_expr(a);
972+
val.result_map(|mut val| {
973+
if translate_as_macro
974+
|| ctx.is_static
975+
&& matches!(
976+
arg_kind,
977+
CExprKind::Literal(_, _) | CExprKind::CompoundLiteral(_, _)
978+
)
979+
{
980+
// Values that translate into temporaries can't be raw-borrowed in Rust,
981+
// and must be regular-borrowed first.
982+
// By borrowing, the lifetime will be extended to static.
983+
val = mk().set_mutbl(mutbl).borrow_expr(val);
984+
985+
// Immutable references can't be cast directly to mutable pointers, so
986+
// add an intermediate cast to const pointer.
987+
if must_cast_mut {
988+
let mut const_pointee_ty = pointee_ty;
989+
const_pointee_ty.qualifiers.is_const = true;
990+
let const_ty = self
991+
.type_converter
992+
.borrow_mut()
993+
.convert_pointer(&self.ast_context, const_pointee_ty)?;
994+
val = mk().cast_expr(val, const_ty);
995+
}
979996

980-
// Avoid unnecessary reference to pointer decay in fn call args:
981-
if ctx.decay_ref.is_no() {
982-
return Ok(addr_of_arg);
983-
}
997+
// Cast to the final pointer.
998+
// TODO: use `ptr::from_ref` and `ptr::from_mut` once stable (Rust 1.76).
999+
val = mk().cast_expr(val, ty);
1000+
} else {
1001+
self.use_feature("raw_ref_op");
1002+
val = mk().set_mutbl(mutbl).raw_borrow_expr(val);
1003+
1004+
if must_cast_mut {
1005+
val = mk().cast_expr(val, ty);
9841006
}
1007+
}
9851008

986-
Ok(mk().cast_expr(addr_of_arg, ty))
987-
})
988-
}
1009+
Ok(val)
1010+
})
9891011
}
9901012
c_ast::UnOp::PreIncrement => self.convert_pre_increment(ctx, cqual_type, true, arg),
9911013
c_ast::UnOp::PreDecrement => self.convert_pre_increment(ctx, cqual_type, false, arg),

c2rust-transpile/tests/snapshots/snapshots__transpile-aarch64@vm_x86.c.snap

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,17 +42,18 @@ pub unsafe extern "C" fn VM_CallCompiled(
4242
programStack -= 8 as core::ffi::c_int + 4 as core::ffi::c_int * MAX_VMMAIN_ARGS;
4343
arg = 0 as core::ffi::c_int;
4444
while arg < MAX_VMMAIN_ARGS {
45-
*(&mut *image
45+
*(&raw mut *image
4646
.offset((programStack + 8 as core::ffi::c_int + arg * 4 as core::ffi::c_int) as isize)
47-
as *mut byte as *mut core::ffi::c_int) = *args.offset(arg as isize);
47+
as *mut core::ffi::c_int) = *args.offset(arg as isize);
4848
arg += 1;
4949
}
50-
*(&mut *image.offset((programStack + 4 as core::ffi::c_int) as isize) as *mut byte
50+
*(&raw mut *image.offset((programStack + 4 as core::ffi::c_int) as isize)
5151
as *mut core::ffi::c_int) = 0 as core::ffi::c_int;
52-
*(&mut *image.offset(programStack as isize) as *mut byte as *mut core::ffi::c_int) =
52+
*(&raw mut *image.offset(programStack as isize) as *mut core::ffi::c_int) =
5353
-(1 as core::ffi::c_int);
5454
entryPoint = ((*vm).codeBase).offset((*vm).entryOfs as isize);
55-
opStack = (stack.as_mut_ptr() as *mut core::ffi::c_int).offset(16 as core::ffi::c_int as isize);
55+
opStack = (&raw mut stack as *mut byte as *mut core::ffi::c_int)
56+
.offset(16 as core::ffi::c_int as isize);
5657
*opStack = 0 as core::ffi::c_int;
5758
opStackOfs = 0 as core::ffi::c_int;
5859
if opStackOfs != 1 as core::ffi::c_int

c2rust-transpile/tests/snapshots/snapshots__transpile-x86_64@vm_x86.c.snap

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ input_file: c2rust-transpile/tests/snapshots/arch-specific/vm_x86.c
1111
unused_assignments,
1212
unused_mut
1313
)]
14-
#![feature(asm)]
14+
#![feature(asm, raw_ref_op)]
1515
use core::arch::asm;
1616
#[derive(Copy, Clone)]
1717
#[repr(C)]
@@ -44,17 +44,18 @@ pub unsafe extern "C" fn VM_CallCompiled(
4444
programStack -= 8 as core::ffi::c_int + 4 as core::ffi::c_int * MAX_VMMAIN_ARGS;
4545
arg = 0 as core::ffi::c_int;
4646
while arg < MAX_VMMAIN_ARGS {
47-
*(&mut *image
47+
*(&raw mut *image
4848
.offset((programStack + 8 as core::ffi::c_int + arg * 4 as core::ffi::c_int) as isize)
49-
as *mut byte as *mut core::ffi::c_int) = *args.offset(arg as isize);
49+
*mut core::ffi::c_int) = *args.offset(arg as isize);
5050
arg += 1;
5151
}
52-
*(&mut *image.offset((programStack + 4 as core::ffi::c_int) as isize) as *mut byte
52+
*(&raw mut *image.offset((programStack + 4 as core::ffi::c_int) as isize)
5353
as *mut core::ffi::c_int) = 0 as core::ffi::c_int;
54-
*(&mut *image.offset(programStack as isize) as *mut byte as *mut core::ffi::c_int) =
54+
*(&raw mut *image.offset(programStack as isize) as *mut core::ffi::c_int) =
5555
-(1 as core::ffi::c_int);
5656
entryPoint = ((*vm).codeBase).offset((*vm).entryOfs as isize);
57-
opStack = (stack.as_mut_ptr() as *mut core::ffi::c_int).offset(16 as core::ffi::c_int as isize);
57+
opStack = (&raw mut stack as *mut byte as *mut core::ffi::c_int)
58+
.offset(16 as core::ffi::c_int as isize);
5859
*opStack = 0 as core::ffi::c_int;
5960
opStackOfs = 0 as core::ffi::c_int;
6061
asm!(

c2rust-transpile/tests/snapshots/[email protected]

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ input_file: c2rust-transpile/tests/snapshots/arrays.c
1111
unused_assignments,
1212
unused_mut
1313
)]
14+
#![feature(raw_ref_op)]
1415
#[derive(Copy, Clone)]
1516
#[repr(C)]
1617
pub struct C2RustUnnamed {
@@ -78,11 +79,10 @@ pub unsafe extern "C" fn entry() {
7879
[u8; 20],
7980
[core::ffi::c_char; 20],
8081
>(*b"abc\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
81-
let mut past_end: *mut core::ffi::c_char = &mut *simple
82-
.as_mut_ptr()
83-
.offset(::core::mem::size_of::<[core::ffi::c_char; 9]>() as isize)
84-
as *mut core::ffi::c_char;
85-
past_end = &mut *foo.offset(8 as core::ffi::c_int as isize) as *mut core::ffi::c_char;
82+
let mut past_end: *mut core::ffi::c_char = &raw mut *(&raw mut simple
83+
as *mut core::ffi::c_char)
84+
.offset(::core::mem::size_of::<[core::ffi::c_char; 9]>() as isize);
85+
past_end = &raw mut *foo.offset(8 as core::ffi::c_int as isize);
8686
}
8787
#[no_mangle]
8888
pub unsafe extern "C" fn short_initializer() {

c2rust-transpile/tests/snapshots/[email protected]

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,28 +11,29 @@ input_file: c2rust-transpile/tests/snapshots/atomics.c
1111
unused_assignments,
1212
unused_mut
1313
)]
14-
#![feature(core_intrinsics)]
14+
#![feature(core_intrinsics, raw_ref_op)]
1515
#[no_mangle]
1616
pub unsafe extern "C" fn c11_atomics(mut x: core::ffi::c_int) -> core::ffi::c_int {
17-
*&mut x = 0 as core::ffi::c_int;
18-
::core::intrinsics::atomic_store_seqcst(&mut x, 1 as core::ffi::c_int);
19-
::core::intrinsics::atomic_load_seqcst(&mut x);
20-
::core::intrinsics::atomic_xadd_seqcst(&mut x, 2 as core::ffi::c_int);
21-
::core::intrinsics::atomic_xsub_seqcst(&mut x, 1 as core::ffi::c_int);
22-
::core::intrinsics::atomic_and_seqcst(&mut x, 0xf as core::ffi::c_int);
23-
::core::intrinsics::atomic_or_seqcst(&mut x, 0x10 as core::ffi::c_int);
24-
::core::intrinsics::atomic_nand_seqcst(&mut x, 0xff as core::ffi::c_int);
25-
::core::intrinsics::atomic_xchg_seqcst(&mut x, 42 as core::ffi::c_int);
17+
*&raw mut x = 0 as core::ffi::c_int;
18+
::core::intrinsics::atomic_store_seqcst(&raw mut x, 1 as core::ffi::c_int);
19+
::core::intrinsics::atomic_load_seqcst(&raw mut x);
20+
::core::intrinsics::atomic_xadd_seqcst(&raw mut x, 2 as core::ffi::c_int);
21+
::core::intrinsics::atomic_xsub_seqcst(&raw mut x, 1 as core::ffi::c_int);
22+
::core::intrinsics::atomic_and_seqcst(&raw mut x, 0xf as core::ffi::c_int);
23+
::core::intrinsics::atomic_or_seqcst(&raw mut x, 0x10 as core::ffi::c_int);
24+
::core::intrinsics::atomic_nand_seqcst(&raw mut x, 0xff as core::ffi::c_int);
25+
::core::intrinsics::atomic_xchg_seqcst(&raw mut x, 42 as core::ffi::c_int);
2626
let mut expected: core::ffi::c_int = 42 as core::ffi::c_int;
2727
let mut desired: core::ffi::c_int = 100 as core::ffi::c_int;
28-
let fresh0 = ::core::intrinsics::atomic_cxchg_seqcst_seqcst(&mut x, *&mut expected, desired);
29-
*&mut expected = fresh0.0;
28+
let fresh0 =
29+
::core::intrinsics::atomic_cxchg_seqcst_seqcst(&raw mut x, *&raw mut expected, desired);
30+
*&raw mut expected = fresh0.0;
3031
fresh0.1;
3132
expected = 100 as core::ffi::c_int;
3233
desired = 200 as core::ffi::c_int;
3334
let fresh1 =
34-
::core::intrinsics::atomic_cxchgweak_seqcst_seqcst(&mut x, *&mut expected, desired);
35-
*&mut expected = fresh1.0;
35+
::core::intrinsics::atomic_cxchgweak_seqcst_seqcst(&raw mut x, *&raw mut expected, desired);
36+
*&raw mut expected = fresh1.0;
3637
fresh1.1;
3738
return x;
3839
}

c2rust-transpile/tests/snapshots/[email protected]

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ input_file: c2rust-transpile/tests/snapshots/exprs.c
1111
unused_assignments,
1212
unused_mut
1313
)]
14+
#![feature(raw_ref_op)]
1415
extern "C" {
1516
fn puts(str: *const core::ffi::c_char) -> core::ffi::c_int;
1617
}
@@ -29,7 +30,7 @@ pub unsafe extern "C" fn unary_without_side_effect() {
2930
i;
3031
!i;
3132
(i == 0) as core::ffi::c_int;
32-
&mut i;
33+
&raw mut i;
3334
i;
3435
i += 1;
3536
i -= 1;
@@ -43,10 +44,11 @@ pub unsafe extern "C" fn unary_with_side_effect() {
4344
side_effect();
4445
!side_effect();
4546
(side_effect() == 0) as core::ffi::c_int;
46-
&*(b"\0" as *const u8 as *const core::ffi::c_char).offset(::core::mem::transmute::<
47+
&raw const *(b"\0" as *const u8 as *const core::ffi::c_char).offset(::core::mem::transmute::<
4748
unsafe extern "C" fn() -> core::ffi::c_int,
4849
unsafe extern "C" fn() -> core::ffi::c_int,
49-
>(side_effect)() as isize) as *const core::ffi::c_char;
50+
>(side_effect)()
51+
as isize);
5052
*arr[side_effect() as usize];
5153
arr[side_effect() as usize] = (arr[side_effect() as usize]).offset(1);
5254
arr[side_effect() as usize] = (arr[side_effect() as usize]).offset(-1);

0 commit comments

Comments
 (0)