Skip to content

Commit 198e9d7

Browse files
committed
transpile: Use raw borrows instead of normal borrows
1 parent 2c11d59 commit 198e9d7

25 files changed

+206
-147
lines changed

c2rust-transpile/src/translator/mod.rs

Lines changed: 55 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -4625,60 +4625,67 @@ impl<'c> Translation<'c> {
46254625
.is_some()
46264626
})
46274627
.unwrap_or(false);
4628-
match expr_kind {
4629-
Some(&CExprKind::Literal(_, CLiteral::String(ref bytes, 1)))
4630-
if is_const && !translate_as_macro =>
4631-
{
4632-
let target_ty = self.convert_type(target_cty.ctype)?;
46334628

4634-
let mut bytes = bytes.to_owned();
4635-
bytes.push(0);
4636-
let byte_literal = mk().lit_expr(bytes);
4637-
let val =
4638-
mk().cast_expr(byte_literal, mk().ptr_ty(mk().path_ty(vec!["u8"])));
4639-
let val = mk().cast_expr(val, target_ty);
4640-
Ok(WithStmts::new_val(val))
4641-
}
4642-
_ => {
4643-
// Variable length arrays are already represented as pointers.
4644-
if let CTypeKind::VariableArray(..) = source_ty_kind {
4645-
Ok(val)
4646-
} else {
4647-
let method = if is_const || ctx.is_static {
4648-
"as_ptr"
4649-
} else {
4650-
"as_mut_ptr"
4651-
};
4629+
if let (Some(&CExprKind::Literal(_, CLiteral::String(ref bytes, 1))), true, false) =
4630+
(expr_kind, is_const, translate_as_macro)
4631+
{
4632+
let target_ty = self.convert_type(target_cty.ctype)?;
4633+
4634+
let mut bytes = bytes.to_owned();
4635+
bytes.push(0);
4636+
let byte_literal = mk().lit_expr(bytes);
4637+
let val = mk().cast_expr(byte_literal, mk().ptr_ty(mk().path_ty(vec!["u8"])));
4638+
let val = mk().cast_expr(val, target_ty);
4639+
return Ok(WithStmts::new_val(val));
4640+
}
46524641

4653-
let call = val.map(|x| mk().method_call_expr(x, method, vec![]));
4642+
// Variable length arrays are already represented as pointers.
4643+
if let CTypeKind::VariableArray(..) = source_ty_kind {
4644+
return Ok(val);
4645+
}
46544646

4655-
// If the target pointee type is different from the source element type,
4656-
// then we need to cast the ptr type as well.
4657-
let call = match source_ty_kind.element_ty() {
4658-
None => call,
4659-
Some(source_element_ty) if source_element_ty == pointee.ctype => {
4660-
call
4661-
}
4662-
Some(_) => {
4663-
let target_ty = self.convert_type(target_cty.ctype)?;
4664-
call.map(|ptr| mk().cast_expr(ptr, target_ty))
4665-
}
4666-
};
4647+
let (mutbl, must_cast_mut) = if is_const {
4648+
(Mutability::Immutable, false)
4649+
} else if ctx.is_static {
4650+
// TODO: The currently used nightly doesn't allow `&raw mut` in
4651+
// static initialisers, but it's allowed since version 1.83.
4652+
// So we take a `&raw const` and then cast.
4653+
// Remove `must_cast_mut` variable when the version is updated.
4654+
(Mutability::Immutable, true)
4655+
} else {
4656+
(Mutability::Mutable, false)
4657+
};
46674658

4668-
// Static arrays can now use as_ptr. Can also cast that const ptr to a
4669-
// mutable pointer as we do here:
4670-
if ctx.is_static && !is_const {
4671-
return Ok(call.map(|val| {
4672-
let inferred_type = mk().infer_ty();
4673-
let ptr_type = mk().mutbl().ptr_ty(inferred_type);
4674-
mk().cast_expr(val, ptr_type)
4675-
}));
4676-
}
4659+
val.result_map(|mut val| {
4660+
if translate_as_macro {
4661+
// Values that translate into temporaries can't be raw-borrowed in Rust,
4662+
// and must be regular-borrowed first.
4663+
// Borrowing in a static/const context will extend the lifetime to static.
4664+
let method = match mutbl {
4665+
Mutability::Mutable => "as_mut_ptr",
4666+
Mutability::Immutable => "as_ptr",
4667+
};
4668+
val = mk().method_call_expr(val, method, vec![]);
4669+
} else {
4670+
self.use_feature("raw_ref_op");
4671+
val = mk().set_mutbl(mutbl).raw_borrow_expr(val);
4672+
// TODO: Add call to `ptr::as_[mut]_ptr` once that is available
4673+
// (`array_ptr_get` feature added to nightly in January 2024)
4674+
}
46774675

4678-
Ok(call)
4679-
}
4676+
// If the target pointee type is different from the source element type,
4677+
// then we need to cast the ptr type as well.
4678+
// TODO: Remove `!translate_as_macro` when `ptr::as_[mut]_ptr` is added above.
4679+
if source_ty_kind.element_ty() != Some(pointee.ctype)
4680+
|| must_cast_mut
4681+
|| !translate_as_macro
4682+
{
4683+
let target_element_ty = self.convert_type(target_cty.ctype)?;
4684+
val = mk().cast_expr(val, target_element_ty);
46804685
}
4681-
}
4686+
4687+
Ok(val)
4688+
})
46824689
}
46834690

46844691
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: 7 additions & 7 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,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)