Skip to content

Commit 7a15b80

Browse files
Ruakkysen
authored andcommitted
transpile: Extend lifetime of compound literals whose address is taken
1 parent 33923cf commit 7a15b80

File tree

2 files changed

+45
-8
lines changed

2 files changed

+45
-8
lines changed

c2rust-transpile/src/translator/mod.rs

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3562,7 +3562,9 @@ impl<'c> Translation<'c> {
35623562
CastKind::BitCast | CastKind::PointerToIntegral | CastKind::NoOp => {
35633563
ctx.decay_ref = DecayRef::Yes
35643564
}
3565-
CastKind::FunctionToPointerDecay | CastKind::BuiltinFnToFnPtr => {
3565+
CastKind::ArrayToPointerDecay
3566+
| CastKind::FunctionToPointerDecay
3567+
| CastKind::BuiltinFnToFnPtr => {
35663568
ctx.needs_address = true;
35673569
}
35683570
_ => {}
@@ -4070,7 +4072,41 @@ impl<'c> Translation<'c> {
40704072

40714073
Paren(_, val) => self.convert_expr(ctx, val, override_ty),
40724074

4073-
CompoundLiteral(_, val) => self.convert_expr(ctx, val, override_ty),
4075+
CompoundLiteral(qty, val) => {
4076+
let val = self.convert_expr(ctx, val, override_ty)?;
4077+
4078+
if !ctx.needs_address() || ctx.is_static || ctx.is_const {
4079+
// Statics and consts have their intermediates' lifetimes extended.
4080+
return Ok(val);
4081+
}
4082+
4083+
// C compound literals are lvalues, but equivalent Rust expressions generally are not.
4084+
// So if an address is needed, store it in an intermediate variable first.
4085+
let fresh_name = self.renamer.borrow_mut().fresh();
4086+
let fresh_ty = self.convert_type(override_ty.unwrap_or(qty).ctype)?;
4087+
4088+
val.and_then(|val| {
4089+
let fresh_stmt = {
4090+
let mutbl = if qty.qualifiers.is_const {
4091+
Mutability::Immutable
4092+
} else {
4093+
Mutability::Mutable
4094+
};
4095+
4096+
let local = mk().local(
4097+
mk().set_mutbl(mutbl).ident_pat(&fresh_name),
4098+
Some(fresh_ty),
4099+
Some(val),
4100+
);
4101+
mk().local_stmt(Box::new(local))
4102+
};
4103+
4104+
Ok(WithStmts::new(
4105+
vec![fresh_stmt],
4106+
mk().ident_expr(fresh_name),
4107+
))
4108+
})
4109+
}
40744110

40754111
InitList(ty, ref ids, opt_union_field_id, _) => {
40764112
self.convert_init_list(ctx, ty, ids, opt_union_field_id)

c2rust-transpile/tests/snapshots/snapshots__transpile@compound_literals.c.snap

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,13 @@ pub const CHAR_ARRAY: [core::ffi::c_char; 6] =
2525
#[no_mangle]
2626
pub unsafe extern "C" fn local_compound_literals() {
2727
let mut single_int: core::ffi::c_int = 42 as core::ffi::c_int;
28-
let mut single_int_ptr: *mut core::ffi::c_int =
29-
&mut (42 as core::ffi::c_int) as *mut core::ffi::c_int;
30-
let mut int_array_ptr: *mut core::ffi::c_int =
31-
[42 as core::ffi::c_int, 9001 as core::ffi::c_int].as_mut_ptr();
32-
let mut char_array_ptr: *mut core::ffi::c_char =
33-
(::core::mem::transmute::<[u8; 6], [core::ffi::c_char; 6]>(*b"hello\0")).as_mut_ptr();
28+
let mut fresh0: core::ffi::c_int = 42 as core::ffi::c_int;
29+
let mut single_int_ptr: *mut core::ffi::c_int = &mut fresh0 as *mut core::ffi::c_int;
30+
let mut fresh1: [core::ffi::c_int; 2] = [42 as core::ffi::c_int, 9001 as core::ffi::c_int];
31+
let mut int_array_ptr: *mut core::ffi::c_int = fresh1.as_mut_ptr();
32+
let mut fresh2: [core::ffi::c_char; 6] =
33+
::core::mem::transmute::<[u8; 6], [core::ffi::c_char; 6]>(*b"hello\0");
34+
let mut char_array_ptr: *mut core::ffi::c_char = fresh2.as_mut_ptr();
3435
let mut macro_single_int: core::ffi::c_int = SINGLE_INT;
3536
let mut macro_single_int_ptr: *mut core::ffi::c_int = &mut SINGLE_INT as *mut core::ffi::c_int;
3637
let mut macro_int_array_ptr: *mut core::ffi::c_int = INT_ARRAY.as_mut_ptr();

0 commit comments

Comments
 (0)