Skip to content

Commit 2097b91

Browse files
committed
transpile: Use raw borrows instead of normal borrows
1 parent 7c403c0 commit 2097b91

24 files changed

+203
-145
lines changed

c2rust-transpile/src/translator/mod.rs

Lines changed: 55 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -4589,60 +4589,67 @@ impl<'c> Translation<'c> {
45894589
.is_some()
45904590
})
45914591
.unwrap_or(false);
4592-
match expr_kind {
4593-
Some(&CExprKind::Literal(_, CLiteral::String(ref bytes, 1)))
4594-
if is_const && !translate_as_macro =>
4595-
{
4596-
let target_ty = self.convert_type(target_cty.ctype)?;
45974592

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

4617-
let call = val.map(|x| mk().method_call_expr(x, method, vec![]));
4606+
// Variable length arrays are already represented as pointers.
4607+
if let CTypeKind::VariableArray(..) = source_ty_kind {
4608+
return Ok(val);
4609+
}
46184610

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

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

4642-
Ok(call)
4643-
}
4640+
// If the target pointee type is different from the source element type,
4641+
// then we need to cast the ptr type as well.
4642+
// TODO: Remove `!translate_as_macro` when `ptr::as_[mut]_ptr` is added above.
4643+
if source_ty_kind.element_ty() != Some(pointee.ctype)
4644+
|| must_cast_mut
4645+
|| !translate_as_macro
4646+
{
4647+
let target_element_ty = self.convert_type(target_cty.ctype)?;
4648+
val = mk().cast_expr(val, target_element_ty);
46444649
}
4645-
}
4650+
4651+
Ok(val)
4652+
})
46464653
}
46474654

46484655
CastKind::NullToPointer => {

c2rust-transpile/src/translator/operators.rs

Lines changed: 66 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -938,54 +938,79 @@ 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+
// Borrowing in a static/const context will extend the lifetime 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+
// Avoid unnecessary reference to pointer decay in fn call args.
999+
// TODO: use `ptr::from_ref` and `ptr::from_mut` once stable (Rust 1.76).
1000+
if ctx.decay_ref.is_yes() || must_cast_mut {
1001+
val = mk().cast_expr(val, ty);
9841002
}
1003+
} else {
1004+
self.use_feature("raw_ref_op");
1005+
val = mk().set_mutbl(mutbl).raw_borrow_expr(val);
9851006

986-
Ok(mk().cast_expr(addr_of_arg, ty))
987-
})
988-
}
1007+
if must_cast_mut {
1008+
val = mk().cast_expr(val, ty);
1009+
}
1010+
}
1011+
1012+
Ok(val)
1013+
})
9891014
}
9901015
c_ast::UnOp::PreIncrement => self.convert_pre_increment(ctx, cqual_type, true, arg),
9911016
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: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ input_file: c2rust-transpile/tests/snapshots/arch-specific/vm_x86.c
1111
unused_assignments,
1212
unused_mut
1313
)]
14+
#![feature(raw_ref_op)]
1415
#[derive(Copy, Clone)]
1516
#[repr(C)]
1617
pub struct vm_t {
@@ -42,18 +43,18 @@ pub unsafe extern "C" fn VM_CallCompiled(
4243
programStack -= 8 as ::core::ffi::c_int + 4 as ::core::ffi::c_int * MAX_VMMAIN_ARGS;
4344
arg = 0 as ::core::ffi::c_int;
4445
while arg < MAX_VMMAIN_ARGS {
45-
*(&mut *image.offset(
46+
*(&raw mut *image.offset(
4647
(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);
48+
) as *mut ::core::ffi::c_int) = *args.offset(arg as isize);
4849
arg += 1;
4950
}
50-
*(&mut *image.offset((programStack + 4 as ::core::ffi::c_int) as isize) as *mut byte
51+
*(&raw mut *image.offset((programStack + 4 as ::core::ffi::c_int) as isize)
5152
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) =
53+
*(&raw mut *image.offset(programStack as isize) as *mut ::core::ffi::c_int) =
5354
-(1 as ::core::ffi::c_int);
5455
entryPoint = ((*vm).codeBase).offset((*vm).entryOfs as isize);
55-
opStack =
56-
(stack.as_mut_ptr() as *mut ::core::ffi::c_int).offset(16 as ::core::ffi::c_int as isize);
56+
opStack = (&raw mut stack as *mut byte as *mut ::core::ffi::c_int)
57+
.offset(16 as ::core::ffi::c_int as isize);
5758
*opStack = 0 as ::core::ffi::c_int;
5859
opStackOfs = 0 as ::core::ffi::c_int;
5960
if opStackOfs != 1 as ::core::ffi::c_int

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

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ input_file: c2rust-transpile/tests/snapshots/arch-specific/vm_x86.c
1111
unused_assignments,
1212
unused_mut
1313
)]
14-
#![feature(asm)]
15-
use ::core::arch::asm;
14+
#![feature(asm, raw_ref_op)]
15+
use core::arch::asm;
1616
#[derive(Copy, Clone)]
1717
#[repr(C)]
1818
pub struct vm_t {
@@ -44,18 +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.offset(
47+
*(&raw mut *image.offset(
4848
(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+
) as *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 =
58-
(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);
5959
*opStack = 0 as ::core::ffi::c_int;
6060
opStackOfs = 0 as ::core::ffi::c_int;
6161
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 {
@@ -79,11 +80,10 @@ pub unsafe extern "C" fn entry() {
7980
[u8; 20],
8081
[::core::ffi::c_char; 20],
8182
>(*b"abc\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
82-
let mut past_end: *mut ::core::ffi::c_char = &mut *simple
83-
.as_mut_ptr()
84-
.offset(::core::mem::size_of::<[::core::ffi::c_char; 9]>() as isize)
85-
as *mut ::core::ffi::c_char;
86-
past_end = &mut *foo.offset(8 as ::core::ffi::c_int as isize) as *mut ::core::ffi::c_char;
83+
let mut past_end: *mut ::core::ffi::c_char = &raw mut *(&raw mut simple
84+
as *mut ::core::ffi::c_char)
85+
.offset(::core::mem::size_of::<[::core::ffi::c_char; 9]>() as isize);
86+
past_end = &raw mut *foo.offset(8 as ::core::ffi::c_int as isize);
8787
}
8888
#[no_mangle]
8989
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
}

0 commit comments

Comments
 (0)