Skip to content

Commit f7899f2

Browse files
authored
transpile: Move some translation from convert_address_of_common to convert_literal (#1633)
Rather than `convert_address_of_common` completely discarding the previously translated `val` for string literals, it now does part of the correct translation in `convert_literal` so that no discarding is needed. This will probably be needed to get #1628 working, since `add_feature` (for const blocks) will have an effect even if code is discarded. Also, `as_ptr` is now used, to be consistent with other kinds of array.
2 parents 1aed6ee + 6659130 commit f7899f2

13 files changed

Lines changed: 64 additions & 61 deletions

c2rust-transpile/src/c_ast/mod.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,14 @@ impl TypedAstContext {
611611
}
612612
}
613613

614+
/// Returns the length of an array type, or panics.
615+
pub fn array_len(&self, typ: CTypeId) -> usize {
616+
match self.resolve_type(typ).kind {
617+
CTypeKind::ConstantArray(_, len) => len,
618+
ref kind => panic!("CTypeId {typ:?} is {kind:?}, not a ConstantArray"),
619+
}
620+
}
621+
614622
/// Can the given field decl be a flexible array member?
615623
pub fn maybe_flexible_array(&self, typ: CTypeId) -> bool {
616624
let field_ty = self.resolve_type(typ);

c2rust-transpile/src/translator/literals.rs

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -108,37 +108,34 @@ impl<'c> Translation<'c> {
108108

109109
CLiteral::String(ref bytes, element_size) => {
110110
let bytes_padded = self.string_literal_bytes(ty.ctype, bytes, element_size);
111+
let len = bytes_padded.len();
112+
let val = mk().lit_expr(bytes_padded);
111113

112-
// std::mem::transmute::<[u8; size], ctype>(*b"xxxx")
113-
let array_ty = mk().array_ty(
114-
mk().ident_ty("u8"),
115-
mk().lit_expr(bytes_padded.len() as u128),
116-
);
117-
let val = transmute_expr(
118-
array_ty,
119-
self.convert_type(ty.ctype)?,
120-
mk().unary_expr(UnOp::Deref(Default::default()), mk().lit_expr(bytes_padded)),
121-
);
122-
Ok(WithStmts::new_unsafe_val(val))
114+
if ctx.needs_address && element_size == 1 {
115+
// Unlike in C, Rust string literals are already references by default.
116+
// So if the address needs to be taken, just make a bare literal.
117+
Ok(WithStmts::new_val(val))
118+
} else {
119+
// std::mem::transmute::<[u8; size], ctype>(*b"xxxx")
120+
let array_ty = mk().array_ty(mk().ident_ty("u8"), mk().lit_expr(len as u128));
121+
let val = transmute_expr(
122+
array_ty,
123+
self.convert_type(ty.ctype)?,
124+
mk().unary_expr(UnOp::Deref(Default::default()), val),
125+
);
126+
Ok(WithStmts::new_unsafe_val(val))
127+
}
123128
}
124129
}
125130
}
126131

127132
/// Returns the bytes of a string literal, including any additional zero bytes to pad the
128133
/// literal to the expected size.
129134
pub fn string_literal_bytes(&self, ctype: CTypeId, bytes: &[u8], element_size: u8) -> Vec<u8> {
130-
let num_elems = match self.ast_context.resolve_type(ctype).kind {
131-
CTypeKind::ConstantArray(_, num_elems) => num_elems,
132-
ref kind => {
133-
panic!("String literal with unknown size: {bytes:?}, kind = {kind:?}")
134-
}
135-
};
136-
137-
let size = num_elems * (element_size as usize);
135+
let size = self.ast_context.array_len(ctype) * element_size as usize;
138136
let mut bytes_padded = Vec::with_capacity(size);
139137
bytes_padded.extend(bytes);
140138
bytes_padded.resize(size, 0);
141-
142139
bytes_padded
143140
}
144141

c2rust-transpile/src/translator/mod.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4083,18 +4083,20 @@ impl<'c> Translation<'c> {
40834083
Paren(_, val) => self.convert_expr(ctx, val, override_ty),
40844084

40854085
CompoundLiteral(qty, val) => {
4086-
let val = self.convert_expr(ctx, val, override_ty)?;
4087-
40884086
if !ctx.needs_address() || ctx.is_const {
40894087
// consts have their intermediates' lifetimes extended.
4090-
return Ok(val);
4088+
return self.convert_expr(ctx, val, override_ty);
40914089
}
40924090

40934091
// C compound literals are lvalues, but equivalent Rust expressions generally are not.
40944092
// So if an address is needed, store it in an intermediate variable first.
40954093
let fresh_name = self.renamer.borrow_mut().fresh();
40964094
let fresh_ty = self.convert_type(override_ty.unwrap_or(qty).ctype)?;
40974095

4096+
// Translate the expression to be assigned to the fresh variable.
4097+
// It will be assigned by value, so we don't need its address anymore.
4098+
let val = self.convert_expr(ctx.set_needs_address(false), val, override_ty)?;
4099+
40984100
val.and_then(|val| {
40994101
let fresh_stmt = {
41004102
let mutbl = if qty.qualifiers.is_const {

c2rust-transpile/src/translator/pointers.rs

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -123,23 +123,19 @@ impl<'c> Translation<'c> {
123123
Mutability::Mutable
124124
};
125125

126-
// String literals are translated with a transmute, which produces a temporary.
127-
// Taking the address of a temporary leaves a dangling pointer. So instead,
128-
// cast the string literal directly so that its 'static lifetime is preserved.
126+
// Narrow string literals are translated directly as `[u8; N]` literals when their address
127+
// is taken, without the transmute. String/byte literals are already references in Rust.
129128
if let (
130-
Some(&CExprKind::Literal(literal_cty, CLiteral::String(ref bytes, element_size @ 1))),
129+
Some(&CExprKind::Literal(literal_cty, CLiteral::String(_, element_size @ 1))),
131130
false,
132131
) = (arg_expr_kind, arg_is_macro)
133132
{
134-
let bytes_padded = self.string_literal_bytes(literal_cty.ctype, bytes, element_size);
135-
let len = bytes_padded.len();
136-
val = WithStmts::new_val(mk().lit_expr(bytes_padded));
137-
138133
if is_array_decay {
139-
ref_cast_pointee_ty = Some(mk().ident_ty("u8"));
134+
val = val.map(|val| mk().method_call_expr(val, "as_ptr", vec![]));
140135
} else {
136+
let size = self.ast_context.array_len(literal_cty.ctype) * element_size as usize;
141137
ref_cast_pointee_ty =
142-
Some(mk().array_ty(mk().ident_ty("u8"), mk().lit_expr(len as u128)));
138+
Some(mk().array_ty(mk().ident_ty("u8"), mk().lit_expr(size as u128)));
143139
}
144140
needs_cast = true;
145141
}

c2rust-transpile/tests/snapshots/snapshots__transpile-aarch64-macos@varargs.c.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ extern "C" {
1717
#[no_mangle]
1818
pub unsafe extern "C" fn call_printf() {
1919
printf(
20-
b"%d, %f\n\0" as *const u8 as *const ::core::ffi::c_char,
20+
b"%d, %f\n\0".as_ptr() as *const ::core::ffi::c_char,
2121
10 as ::core::ffi::c_int,
2222
1.5f64,
2323
);

c2rust-transpile/tests/snapshots/snapshots__transpile-linux@call_only_once.c.snap

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,9 @@ pub unsafe extern "C" fn assert_call_only_once() -> ::core::ffi::c_int {
3737
if called_only_once() != 0 {
3838
} else {
3939
__assert_fail(
40-
b"called_only_once()\0" as *const u8 as *const ::core::ffi::c_char,
40+
b"called_only_once()\0".as_ptr() as *const ::core::ffi::c_char,
4141
b"./tests/snapshots/os-specific/call_only_once.c\0"
42-
as *const u8 as *const ::core::ffi::c_char,
42+
.as_ptr() as *const ::core::ffi::c_char,
4343
12 as ::core::ffi::c_uint,
4444
__ASSERT_FUNCTION.as_ptr(),
4545
);

c2rust-transpile/tests/snapshots/snapshots__transpile-macos@call_only_once.c.snap

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,10 @@ unsafe extern "C" fn called_only_once() -> ::core::ffi::c_int {
2828
pub unsafe extern "C" fn assert_call_only_once() -> ::core::ffi::c_int {
2929
if (called_only_once() == 0) as ::core::ffi::c_int as ::core::ffi::c_long != 0 {
3030
__assert_rtn(
31-
b"assert_call_only_once\0" as *const u8 as *const ::core::ffi::c_char,
32-
b"call_only_once.c\0" as *const u8 as *const ::core::ffi::c_char,
31+
b"assert_call_only_once\0".as_ptr() as *const ::core::ffi::c_char,
32+
b"call_only_once.c\0".as_ptr() as *const ::core::ffi::c_char,
3333
12 as ::core::ffi::c_int,
34-
b"called_only_once()\0" as *const u8 as *const ::core::ffi::c_char,
34+
b"called_only_once()\0".as_ptr() as *const ::core::ffi::c_char,
3535
);
3636
} else {
3737
};

c2rust-transpile/tests/snapshots/snapshots__transpile-x86_64-linux@varargs.c.snap

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ pub struct vastruct<'a> {
3939
#[no_mangle]
4040
pub unsafe extern "C" fn call_printf() {
4141
printf(
42-
b"%d, %f\n\0" as *const u8 as *const ::core::ffi::c_char,
42+
b"%d, %f\n\0".as_ptr() as *const ::core::ffi::c_char,
4343
10 as ::core::ffi::c_int,
4444
1.5f64,
4545
);
@@ -72,19 +72,19 @@ pub unsafe extern "C" fn my_printf(mut fmt: *const ::core::ffi::c_char, mut c2ru
7272
match *fmt as ::core::ffi::c_int {
7373
105 | 100 => {
7474
printf(
75-
b"%d\0" as *const u8 as *const ::core::ffi::c_char,
75+
b"%d\0".as_ptr() as *const ::core::ffi::c_char,
7676
ap.arg::<::core::ffi::c_int>(),
7777
);
7878
}
7979
102 => {
8080
printf(
81-
b"%f\0" as *const u8 as *const ::core::ffi::c_char,
81+
b"%f\0".as_ptr() as *const ::core::ffi::c_char,
8282
ap.arg::<::core::ffi::c_double>(),
8383
);
8484
}
8585
115 => {
8686
printf(
87-
b"%s\0" as *const u8 as *const ::core::ffi::c_char,
87+
b"%s\0".as_ptr() as *const ::core::ffi::c_char,
8888
ap.arg::<*mut ::core::ffi::c_char>(),
8989
);
9090
}
@@ -153,7 +153,7 @@ pub unsafe extern "C" fn restart_valist(mut fmt: *const ::core::ffi::c_char, mut
153153
#[no_mangle]
154154
pub unsafe extern "C" fn print_int(mut ap: *mut ::core::ffi::VaListImpl) {
155155
printf(
156-
b"%d\0" as *const u8 as *const ::core::ffi::c_char,
156+
b"%d\0".as_ptr() as *const ::core::ffi::c_char,
157157
(*ap).arg::<::core::ffi::c_int>(),
158158
);
159159
}

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ pub static mut static_char_array: [::core::ffi::c_char; 9] =
4040
unsafe { ::core::mem::transmute::<[u8; 9], [::core::ffi::c_char; 9]>(*b"mystring\0") };
4141
#[no_mangle]
4242
pub static mut static_char_ptr: *mut ::core::ffi::c_char =
43-
b"mystring\0" as *const u8 as *const ::core::ffi::c_char as *mut ::core::ffi::c_char;
43+
b"mystring\0".as_ptr() as *const ::core::ffi::c_char as *mut ::core::ffi::c_char;
4444
#[no_mangle]
4545
pub static mut static_void_ptr: *mut ::core::ffi::c_void =
4646
unsafe { &raw const static_char_array as *mut ::core::ffi::c_char as *mut ::core::ffi::c_void };
@@ -89,11 +89,11 @@ pub unsafe extern "C" fn entry() {
8989
&raw mut char_with_string as *mut ::core::ffi::c_char;
9090
let mut char_var_array_ptr: *mut [::core::ffi::c_char; 4] = &raw mut char_with_string;
9191
let mut const_char_lit_ptr: *const ::core::ffi::c_char =
92-
b"abc\0" as *const u8 as *const ::core::ffi::c_char;
92+
b"abc\0".as_ptr() as *const ::core::ffi::c_char;
9393
let mut const_char_lit_array_ptr: *const [::core::ffi::c_char; 4] =
9494
b"abc\0" as *const [u8; 4] as *const [::core::ffi::c_char; 4];
9595
let mut char_lit_ptr: *mut ::core::ffi::c_char =
96-
b"abc\0" as *const u8 as *const ::core::ffi::c_char as *mut ::core::ffi::c_char;
96+
b"abc\0".as_ptr() as *const ::core::ffi::c_char as *mut ::core::ffi::c_char;
9797
let mut char_lit_array_ptr: *mut [::core::ffi::c_char; 4] = b"abc\0" as *const [u8; 4]
9898
as *const [::core::ffi::c_char; 4]
9999
as *mut [::core::ffi::c_char; 4];

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ pub const C: C2Rust_Unnamed = 2;
2020
pub const B: C2Rust_Unnamed = 1;
2121
pub const A: C2Rust_Unnamed = 0;
2222
unsafe extern "C" fn side_effect() -> ::core::ffi::c_int {
23-
puts(b"the return of side effect\0" as *const u8 as *const ::core::ffi::c_char);
23+
puts(b"the return of side effect\0".as_ptr() as *const ::core::ffi::c_char);
2424
return 10 as ::core::ffi::c_int;
2525
}
2626
#[no_mangle]
@@ -44,7 +44,7 @@ pub unsafe extern "C" fn unary_with_side_effect() {
4444
side_effect();
4545
!side_effect();
4646
(side_effect() == 0) as ::core::ffi::c_int;
47-
(b"\0" as *const u8 as *const ::core::ffi::c_char).offset(side_effect() as isize)
47+
(b"\0".as_ptr() as *const ::core::ffi::c_char).offset(side_effect() as isize)
4848
as *const ::core::ffi::c_char;
4949
*arr[side_effect() as usize];
5050
arr[side_effect() as usize] = arr[side_effect() as usize].offset(1);
@@ -59,8 +59,8 @@ pub unsafe extern "C" fn compound_literal() {
5959
#[no_mangle]
6060
pub unsafe extern "C" fn statement_expr() {
6161
'_c2rust_label: {
62-
puts(b"should execute\0" as *const u8 as *const ::core::ffi::c_char);
62+
puts(b"should execute\0".as_ptr() as *const ::core::ffi::c_char);
6363
return;
6464
};
65-
puts(b"should be unreachable!\0" as *const u8 as *const ::core::ffi::c_char);
65+
puts(b"should be unreachable!\0".as_ptr() as *const ::core::ffi::c_char);
6666
}

0 commit comments

Comments
 (0)