Skip to content

Commit 2c047f0

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

File tree

22 files changed

+151
-118
lines changed

22 files changed

+151
-118
lines changed

c2rust-transpile/src/translator/mod.rs

Lines changed: 54 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -4595,59 +4595,65 @@ 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)?;
4603-
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-
};
46224598

4623-
let call = val.map(|x| mk().method_call_expr(x, method, vec![]));
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+
}
46244611

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-
};
4612+
// Variable length arrays are already represented as pointers.
4613+
if let CTypeKind::VariableArray(..) = source_ty_kind {
4614+
return Ok(val);
4615+
}
46374616

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-
}
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+
};
46474628

4648-
Ok(call)
4649-
}
4629+
let val = val.map(|val| {
4630+
if ctx.is_const {
4631+
// A constant cannot be raw-borrowed, but its lifetime will be
4632+
// extended to static if it's regular-borrowed first.
4633+
let method = match mutbl {
4634+
Mutability::Mutable => "as_mut_ptr",
4635+
Mutability::Immutable => "as_ptr",
4636+
};
4637+
mk().method_call_expr(val, method, vec![])
4638+
} else {
4639+
self.use_feature("raw_ref_op");
4640+
mk().set_mutbl(mutbl).raw_borrow_expr(val)
4641+
// TODO: Add call to `ptr::as_[mut]_ptr` once that is available
4642+
// (`array_ptr_get` feature added to nightly in January 2024)
46504643
}
4644+
});
4645+
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 `!ctx.is_const` when `ptr::as_[mut]_ptr` is added above.
4649+
if source_ty_kind.element_ty() != Some(pointee.ctype)
4650+
|| must_cast_mut
4651+
|| !ctx.is_const
4652+
{
4653+
let target_element_ty = self.convert_type(target_cty.ctype)?;
4654+
Ok(val.map(|val| mk().cast_expr(val, target_element_ty)))
4655+
} else {
4656+
Ok(val)
46514657
}
46524658
}
46534659

c2rust-transpile/src/translator/operators.rs

Lines changed: 42 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -938,53 +938,53 @@ 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])))
945-
} 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-
};
944+
return Ok(val.map(|x| mk().call_expr(mk().ident_expr("Some"), vec![x])));
945+
}
958946

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);
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 (mutbl, must_cast_mut) = if pointee_ty.qualifiers.is_const {
955+
(Mutability::Immutable, false)
956+
} else if ctx.is_static {
957+
// TODO: The currently used nightly doesn't allow `&raw mut` in
958+
// static initialisers, but it's allowed since version 1.83.
959+
// So we take a `&raw const` and then cast.
960+
// Remove `must_cast_mut` variable when the version is updated.
961+
(Mutability::Immutable, true)
962+
} else {
963+
(Mutability::Mutable, false)
964+
};
979965

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-
}
984-
}
966+
let val = val.map(|val| {
967+
if ctx.is_const {
968+
// A constant cannot be raw-borrowed, but its lifetime will be
969+
// extended to static if it's regular-borrowed first.
970+
let method = match mutbl {
971+
Mutability::Mutable => "from_mut",
972+
Mutability::Immutable => "from_ref",
973+
};
974+
mk().call_expr(
975+
mk().abs_path_expr(vec!["core", "ptr", method]),
976+
vec![mk().set_mutbl(mutbl).borrow_expr(val)],
977+
)
978+
} else {
979+
self.use_feature("raw_ref_op");
980+
mk().set_mutbl(mutbl).raw_borrow_expr(val)
981+
}
982+
});
985983

986-
Ok(mk().cast_expr(addr_of_arg, ty))
987-
})
984+
if must_cast_mut {
985+
Ok(val.map(|val| mk().cast_expr(val, ty)))
986+
} else {
987+
Ok(val)
988988
}
989989
}
990990
c_ast::UnOp::PreIncrement => self.convert_pre_increment(ctx, cqual_type, true, arg),

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

Lines changed: 4 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,9 @@ 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 as *mut core::ffi::c_char)
83+
.offset(::core::mem::size_of::<[core::ffi::c_char; 9]>() as isize);
84+
past_end = &raw mut *foo.offset(8 as core::ffi::c_int as isize);
8685
}
8786
#[no_mangle]
8887
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);

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ input_file: c2rust-transpile/tests/snapshots/macros.c
1111
unused_assignments,
1212
unused_mut
1313
)]
14+
#![feature(raw_ref_op)]
1415
extern "C" {
1516
fn extern_fn() -> core::ffi::c_int;
1617
}
@@ -357,7 +358,7 @@ pub static mut fns: fn_ptrs = {
357358
init
358359
};
359360
#[no_mangle]
360-
pub static mut p: *const fn_ptrs = unsafe { &fns as *const fn_ptrs };
361+
pub static mut p: *const fn_ptrs = unsafe { &raw const fns };
361362
pub const ZSTD_WINDOWLOG_MAX_32: core::ffi::c_int = 30 as core::ffi::c_int;
362363
pub const ZSTD_WINDOWLOG_MAX_64: core::ffi::c_int = 31 as core::ffi::c_int;
363364
#[no_mangle]
@@ -371,7 +372,7 @@ pub unsafe extern "C" fn test_zstd() -> U64 {
371372
#[no_mangle]
372373
pub unsafe extern "C" fn stmt_expr_inc() -> core::ffi::c_int {
373374
let mut a: core::ffi::c_int = 0 as core::ffi::c_int;
374-
let mut b: *mut core::ffi::c_int = &mut a;
375+
let mut b: *mut core::ffi::c_int = &raw mut a;
375376
({
376377
*b += 1;
377378
*b;

tests/arrays/src/test_arrays.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
//! feature_raw_ref_op
2+
13
use crate::arrays::rust_entry;
24
use crate::incomplete_arrays::{rust_check_some_ints, rust_entry2, rust_test_sized_array};
35
use crate::variable_arrays::{rust_alloca_arrays, rust_variable_arrays};

tests/builtins/src/test_builtins.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//! feature_core_intrinsics
1+
//! feature_core_intrinsics, feature_raw_ref_op
22
33
use crate::alloca::rust_alloca_hello;
44
use crate::atomics::{rust_atomics_entry, rust_new_atomics};

tests/casts/src/test_casts.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
//! feature_raw_ref_op
2+
13
use crate::cast_funptr::{rust_entry, rust_get_identity, rust_identity};
24
use crate::casts::rust_cast_stuff;
35

tests/conditionals/src/test_conditionals.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
//! feature_raw_ref_op
2+
13
use crate::binary_conditional::rust_entry3;
24
use crate::conditional::rust_entry;
35
use crate::conditionals::{rust_entry2, rust_ternaries};

0 commit comments

Comments
 (0)