Skip to content

Commit d6de3dd

Browse files
committed
transpile: Use raw borrows instead of normal borrows
1 parent 217ae42 commit d6de3dd

File tree

25 files changed

+174
-137
lines changed

25 files changed

+174
-137
lines changed

c2rust-ast-builder/src/builder.rs

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use syn::{__private::ToTokens, punctuated::Punctuated, *};
99

1010
pub mod properties {
1111
use proc_macro2::Span;
12-
use syn::{StaticMutability, Token};
12+
use syn::{PointerMutability, StaticMutability, Token};
1313

1414
pub trait ToToken {
1515
type Token;
@@ -33,6 +33,13 @@ pub mod properties {
3333
}
3434

3535
impl Mutability {
36+
pub fn to_pointer_mutability(&self, span: Span) -> PointerMutability {
37+
match self {
38+
Mutability::Mutable => PointerMutability::Mut(Token![mut](span)),
39+
Mutability::Immutable => PointerMutability::Const(Token![const](span)),
40+
}
41+
}
42+
3643
pub fn to_static_mutability(&self, span: Span) -> StaticMutability {
3744
match self {
3845
Mutability::Mutable => StaticMutability::Mut(Token![mut](span)),
@@ -953,7 +960,7 @@ impl Builder {
953960
self.path_expr(vec![name])
954961
}
955962

956-
pub fn addr_of_expr(self, e: Box<Expr>) -> Box<Expr> {
963+
pub fn borrow_expr(self, e: Box<Expr>) -> Box<Expr> {
957964
Box::new(parenthesize_if_necessary(Expr::Reference(ExprReference {
958965
attrs: self.attrs,
959966
and_token: Token![&](self.span),
@@ -962,6 +969,16 @@ impl Builder {
962969
})))
963970
}
964971

972+
pub fn raw_borrow_expr(self, e: Box<Expr>) -> Box<Expr> {
973+
Box::new(parenthesize_if_necessary(Expr::RawAddr(ExprRawAddr {
974+
attrs: self.attrs,
975+
and_token: Token![&](self.span),
976+
raw: Token![raw](self.span),
977+
mutability: self.mutbl.to_pointer_mutability(self.span),
978+
expr: e,
979+
})))
980+
}
981+
965982
pub fn mac_expr(self, mac: Macro) -> Box<Expr> {
966983
Box::new(Expr::Macro(ExprMacro {
967984
attrs: self.attrs,

c2rust-transpile/src/rust_ast/set_span.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ impl SetSpan for Expr {
140140
RangeLimits::Closed(mut r) => r.spans[0] = s,
141141
RangeLimits::HalfOpen(mut r) => r.spans[0] = s,
142142
},
143+
Expr::RawAddr(e) => e.and_token.span = s,
143144
Expr::Reference(e) => e.and_token.span = s,
144145
Expr::Return(e) => e.return_token.span = s,
145146
Expr::Try(e) => e.question_token.span = s,

c2rust-transpile/src/translator/assembly.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -819,7 +819,7 @@ impl<'c> Translation<'c> {
819819
// c2rust-ast-exporter added it (there's no gcc equivalent);
820820
// in this case, we need to do what clang does and pass in
821821
// the operand by-address instead of by-value
822-
out_expr = mk().mutbl().addr_of_expr(out_expr);
822+
out_expr = mk().mutbl().borrow_expr(out_expr);
823823
}
824824

825825
if let Some(_tied_operand) = tied_operands.get(&(output_idx, true)) {
@@ -836,7 +836,7 @@ impl<'c> Translation<'c> {
836836
let output_local = mk().local(
837837
mk().ident_pat(&output_name),
838838
None,
839-
Some(mk().mutbl().addr_of_expr(out_expr)),
839+
Some(mk().mutbl().borrow_expr(out_expr)),
840840
);
841841
stmts.push(mk().local_stmt(Box::new(output_local)));
842842

@@ -860,7 +860,7 @@ impl<'c> Translation<'c> {
860860
let mut in_expr = in_expr.into_value();
861861

862862
if operand.mem_only {
863-
in_expr = mk().addr_of_expr(in_expr);
863+
in_expr = mk().borrow_expr(in_expr);
864864
}
865865
if let Some(tied_operand) = tied_operands.get(&(input_idx, false)) {
866866
self.use_crate(ExternCrate::C2RustAsmCasts);

c2rust-transpile/src/translator/mod.rs

Lines changed: 26 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -3004,12 +3004,8 @@ impl<'c> Translation<'c> {
30043004
}
30053005
}
30063006
_ => {
3007-
let addr_lhs = mk().set_mutbl(mutbl).addr_of_expr(lhs);
3008-
3009-
let lhs_type = self.convert_type(lhs_type.ctype)?;
3010-
let ty = mk().set_mutbl(mutbl).ptr_ty(lhs_type);
3011-
3012-
mk().cast_expr(addr_lhs, ty)
3007+
self.use_feature("raw_ref_op");
3008+
mk().set_mutbl(mutbl).raw_borrow_expr(lhs)
30133009
}
30143010
};
30153011
Ok(addr_lhs)
@@ -4548,41 +4544,36 @@ impl<'c> Translation<'c> {
45484544
_ => {
45494545
// Variable length arrays are already represented as pointers.
45504546
if let CTypeKind::VariableArray(..) = source_ty_kind {
4551-
Ok(val)
4547+
return Ok(val);
4548+
}
4549+
4550+
let mutbl = if is_const {
4551+
Mutability::Immutable
45524552
} else {
4553-
let method = if is_const || ctx.is_static {
4554-
"as_ptr"
4555-
} else {
4556-
"as_mut_ptr"
4557-
};
4553+
Mutability::Mutable
4554+
};
45584555

4559-
let call = val.map(|x| mk().method_call_expr(x, method, vec![]));
4556+
let target_element_ty = self.convert_type(target_cty.ctype)?;
45604557

4561-
// If the target pointee type is different from the source element type,
4562-
// then we need to cast the ptr type as well.
4563-
let call = match source_ty_kind.element_ty() {
4564-
None => call,
4565-
Some(source_element_ty) if source_element_ty == pointee.ctype => {
4566-
call
4567-
}
4568-
Some(_) => {
4569-
let target_ty = self.convert_type(target_cty.ctype)?;
4570-
call.map(|ptr| mk().cast_expr(ptr, target_ty))
4571-
}
4572-
};
4558+
Ok(val.map(|mut val| {
4559+
self.use_feature("raw_ref_op");
45734560

4574-
// Static arrays can now use as_ptr. Can also cast that const ptr to a
4575-
// mutable pointer as we do here:
4576-
if ctx.is_static && !is_const {
4577-
return Ok(call.map(|val| {
4578-
let inferred_type = mk().infer_ty();
4579-
let ptr_type = mk().mutbl().ptr_ty(inferred_type);
4580-
mk().cast_expr(val, ptr_type)
4581-
}));
4561+
// TODO: The currently used nightly doesn't allow `&raw mut` in
4562+
// static initialisers, but it's allowed since version 1.83.
4563+
// So we take a `&raw const` and then cast.
4564+
// Remove this exemption when the version is updated.
4565+
if ctx.is_static && matches!(mutbl, Mutability::Mutable) {
4566+
val = mk().raw_borrow_expr(val);
4567+
} else {
4568+
val = mk().set_mutbl(mutbl).raw_borrow_expr(val);
45824569
}
45834570

4584-
Ok(call)
4585-
}
4571+
// Cast to element type.
4572+
// TODO: Change to call `ptr::as_[mut]_ptr` once that is available,
4573+
// and cast only if `source_ty_kind.element_ty() != pointee.ctype`
4574+
// (`array_ptr_get` feature added to nightly in January 2024)
4575+
mk().cast_expr(val, target_element_ty)
4576+
}))
45864577
}
45874578
}
45884579
}

c2rust-transpile/src/translator/operators.rs

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

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

942942
if self.ast_context.is_function_pointer(ctype) {
943-
Ok(arg.map(|x| mk().call_expr(mk().ident_expr("Some"), vec![x])))
943+
return Ok(val.map(|x| mk().call_expr(mk().ident_expr("Some"), vec![x])));
944+
}
945+
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
944955
} else {
945-
let pointee_ty =
946-
self.ast_context
947-
.get_pointee_qual_type(ctype)
948-
.ok_or_else(|| {
949-
TranslationError::generic("Address-of should return a pointer")
950-
})?;
951-
952-
let mutbl = if pointee_ty.qualifiers.is_const {
953-
Mutability::Immutable
954-
} else {
955-
Mutability::Mutable
956-
};
956+
Mutability::Mutable
957+
};
957958

958-
arg.result_map(|a| {
959-
let mut addr_of_arg: Box<Expr>;
960-
961-
if ctx.is_static {
962-
// static variable initializers aren't able to use &mut,
963-
// so we work around that by using & and an extra cast
964-
// through & to *const to *mut
965-
addr_of_arg = mk().addr_of_expr(a);
966-
if let Mutability::Mutable = mutbl {
967-
let mut qtype = pointee_ty;
968-
qtype.qualifiers.is_const = true;
969-
let ty_ = self
970-
.type_converter
971-
.borrow_mut()
972-
.convert_pointer(&self.ast_context, qtype)?;
973-
addr_of_arg = mk().cast_expr(addr_of_arg, ty_);
974-
}
959+
Ok(val.map(|mut val| {
960+
if matches!(
961+
arg_kind,
962+
CExprKind::Literal(..) | CExprKind::CompoundLiteral(..)
963+
) {
964+
// Rust does not extend the lifetime of temporaries with a raw borrow,
965+
// but will do so with a regular borrow.
966+
val = mk().set_mutbl(mutbl).borrow_expr(val);
967+
968+
if ctx.decay_ref.is_yes() {
969+
val = mk().cast_expr(val, ty)
970+
}
971+
} else {
972+
self.use_feature("raw_ref_op");
973+
974+
// TODO: The currently used nightly doesn't allow `&raw mut` in
975+
// static initialisers, but it's allowed since version 1.83.
976+
// So we take a `&raw const` and then cast.
977+
// Remove this exemption when the version is updated.
978+
if ctx.is_static && matches!(mutbl, Mutability::Mutable) {
979+
val = mk().raw_borrow_expr(val);
980+
val = mk().cast_expr(val, ty);
975981
} else {
976-
// Normal case is allowed to use &mut if needed
977-
addr_of_arg = mk().set_mutbl(mutbl).addr_of_expr(a);
978-
979-
// Avoid unnecessary reference to pointer decay in fn call args:
980-
if ctx.decay_ref.is_no() {
981-
return Ok(addr_of_arg);
982-
}
982+
val = mk().set_mutbl(mutbl).raw_borrow_expr(val);
983983
}
984+
}
984985

985-
Ok(mk().cast_expr(addr_of_arg, ty))
986-
})
987-
}
986+
val
987+
}))
988988
}
989989
c_ast::UnOp::PreIncrement => self.convert_pre_increment(ctx, cqual_type, true, arg),
990990
c_ast::UnOp::PreDecrement => self.convert_pre_increment(ctx, cqual_type, false, 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
[std::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 std::ffi::c_char = &mut *simple
82-
.as_mut_ptr()
83-
.offset(::core::mem::size_of::<[std::ffi::c_char; 9]>() as isize)
84-
as *mut std::ffi::c_char;
85-
past_end = &mut *foo.offset(8 as std::ffi::c_int as isize) as *mut std::ffi::c_char;
82+
let mut past_end: *mut std::ffi::c_char = &raw mut *(&raw mut simple as *mut std::ffi::c_char)
83+
.offset(::core::mem::size_of::<[std::ffi::c_char; 9]>() as isize);
84+
past_end = &raw mut *foo.offset(8 as std::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: std::ffi::c_int) -> std::ffi::c_int {
17-
*&mut x = 0 as std::ffi::c_int;
18-
::core::intrinsics::atomic_store_seqcst(&mut x, 1 as std::ffi::c_int);
19-
::core::intrinsics::atomic_load_seqcst(&mut x);
20-
::core::intrinsics::atomic_xadd_seqcst(&mut x, 2 as std::ffi::c_int);
21-
::core::intrinsics::atomic_xsub_seqcst(&mut x, 1 as std::ffi::c_int);
22-
::core::intrinsics::atomic_and_seqcst(&mut x, 0xf as std::ffi::c_int);
23-
::core::intrinsics::atomic_or_seqcst(&mut x, 0x10 as std::ffi::c_int);
24-
::core::intrinsics::atomic_nand_seqcst(&mut x, 0xff as std::ffi::c_int);
25-
::core::intrinsics::atomic_xchg_seqcst(&mut x, 42 as std::ffi::c_int);
17+
*&raw mut x = 0 as std::ffi::c_int;
18+
::core::intrinsics::atomic_store_seqcst(&raw mut x, 1 as std::ffi::c_int);
19+
::core::intrinsics::atomic_load_seqcst(&raw mut x);
20+
::core::intrinsics::atomic_xadd_seqcst(&raw mut x, 2 as std::ffi::c_int);
21+
::core::intrinsics::atomic_xsub_seqcst(&raw mut x, 1 as std::ffi::c_int);
22+
::core::intrinsics::atomic_and_seqcst(&raw mut x, 0xf as std::ffi::c_int);
23+
::core::intrinsics::atomic_or_seqcst(&raw mut x, 0x10 as std::ffi::c_int);
24+
::core::intrinsics::atomic_nand_seqcst(&raw mut x, 0xff as std::ffi::c_int);
25+
::core::intrinsics::atomic_xchg_seqcst(&raw mut x, 42 as std::ffi::c_int);
2626
let mut expected: std::ffi::c_int = 42 as std::ffi::c_int;
2727
let mut desired: std::ffi::c_int = 100 as std::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 std::ffi::c_int;
3233
desired = 200 as std::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 std::ffi::c_char) -> std::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 std::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 std::ffi::c_int;
46-
&*(b"\0" as *const u8 as *const std::ffi::c_char).offset(::core::mem::transmute::<
47+
&raw const *(b"\0" as *const u8 as *const std::ffi::c_char).offset(::core::mem::transmute::<
4748
unsafe extern "C" fn() -> std::ffi::c_int,
4849
unsafe extern "C" fn() -> std::ffi::c_int,
49-
>(side_effect)() as isize) as *const std::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)