Skip to content

Commit 2188649

Browse files
committed
transpile: Extend lifetime of compound literals whose address is taken
1 parent 14713ae commit 2188649

File tree

3 files changed

+66
-10
lines changed

3 files changed

+66
-10
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 {
4079+
// Statics 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)
Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,22 @@
11
int static_single_int = (int) { 42 };
22
int *static_single_int_ptr = &((int) { 42 });
33
int *static_int_array_ptr = (int[]) { 42, 9001 };
4-
//char *static_char_ptr = (char[]) { "hello" };
4+
// Currently generates broken Rust code, see
5+
// https://github.com/immunant/c2rust/issues/1410
6+
//char *static_char_array_ptr = (char[]) { "hello" };
7+
8+
#define SINGLE_INT ((int) { 42 })
9+
#define INT_ARRAY ((int[]) { 42, 9001 })
10+
#define CHAR_ARRAY ((char[]) { "hello" })
511

612
void local_compound_literals() {
713
int single_int = (int) { 42 };
814
int *single_int_ptr = &((int) { 42 });
915
int *int_array_ptr = (int[]) { 42, 9001 };
10-
char *char_ptr = (char[]) { "hello" };
16+
char *char_array_ptr = (char[]) { "hello" };
17+
18+
int macro_single_int = SINGLE_INT;
19+
int *macro_single_int_ptr = &SINGLE_INT;
20+
int *macro_int_array_ptr = INT_ARRAY;
21+
char *macro_char_array_ptr = CHAR_ARRAY;
1122
}

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

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,22 @@ pub static mut static_single_int_ptr: *mut core::ffi::c_int =
1818
&42 as *const core::ffi::c_int as *mut core::ffi::c_int;
1919
#[no_mangle]
2020
pub static mut static_int_array_ptr: *mut core::ffi::c_int = [42, 9001].as_ptr() as *mut _;
21+
pub const SINGLE_INT: core::ffi::c_int = 42 as core::ffi::c_int;
22+
pub const INT_ARRAY: [core::ffi::c_int; 2] = [42 as core::ffi::c_int, 9001 as core::ffi::c_int];
23+
pub const CHAR_ARRAY: [core::ffi::c_char; 6] =
24+
unsafe { ::core::mem::transmute::<[u8; 6], [core::ffi::c_char; 6]>(*b"hello\0") };
2125
#[no_mangle]
2226
pub unsafe extern "C" fn local_compound_literals() {
2327
let mut single_int: core::ffi::c_int = 42 as core::ffi::c_int;
24-
let mut single_int_ptr: *mut core::ffi::c_int =
25-
&mut (42 as core::ffi::c_int) as *mut core::ffi::c_int;
26-
let mut int_array_ptr: *mut core::ffi::c_int =
27-
[42 as core::ffi::c_int, 9001 as core::ffi::c_int].as_mut_ptr();
28-
let mut char_ptr: *mut core::ffi::c_char =
29-
(::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();
35+
let mut macro_single_int: core::ffi::c_int = SINGLE_INT;
36+
let mut macro_single_int_ptr: *mut core::ffi::c_int = &mut SINGLE_INT as *mut core::ffi::c_int;
37+
let mut macro_int_array_ptr: *mut core::ffi::c_int = INT_ARRAY.as_mut_ptr();
38+
let mut macro_char_array_ptr: *mut core::ffi::c_char = CHAR_ARRAY.as_mut_ptr();
3039
}

0 commit comments

Comments
 (0)