Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions c2rust-transpile/src/c_ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,14 @@ impl TypedAstContext {
}
}

/// Returns the length of an array type, or panics.
pub fn array_len(&self, typ: CTypeId) -> usize {
match self.resolve_type(typ).kind {
CTypeKind::ConstantArray(_, len) => len,
ref kind => panic!("CTypeId {typ:?} is {kind:?}, not a ConstantArray"),
}
}

/// Can the given field decl be a flexible array member?
pub fn maybe_flexible_array(&self, typ: CTypeId) -> bool {
let field_ty = self.resolve_type(typ);
Expand Down
37 changes: 17 additions & 20 deletions c2rust-transpile/src/translator/literals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,37 +108,34 @@ impl<'c> Translation<'c> {

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

// std::mem::transmute::<[u8; size], ctype>(*b"xxxx")
let array_ty = mk().array_ty(
mk().ident_ty("u8"),
mk().lit_expr(bytes_padded.len() as u128),
);
let val = transmute_expr(
array_ty,
self.convert_type(ty.ctype)?,
mk().unary_expr(UnOp::Deref(Default::default()), mk().lit_expr(bytes_padded)),
);
Ok(WithStmts::new_unsafe_val(val))
if ctx.needs_address && element_size == 1 {
// Unlike in C, Rust string literals are already references by default.
// So if the address needs to be taken, just make a bare literal.
Ok(WithStmts::new_val(val))
} else {
// std::mem::transmute::<[u8; size], ctype>(*b"xxxx")
let array_ty = mk().array_ty(mk().ident_ty("u8"), mk().lit_expr(len as u128));
let val = transmute_expr(
array_ty,
self.convert_type(ty.ctype)?,
mk().unary_expr(UnOp::Deref(Default::default()), val),
);
Ok(WithStmts::new_unsafe_val(val))
}
}
}
}

/// Returns the bytes of a string literal, including any additional zero bytes to pad the
/// literal to the expected size.
pub fn string_literal_bytes(&self, ctype: CTypeId, bytes: &[u8], element_size: u8) -> Vec<u8> {
let num_elems = match self.ast_context.resolve_type(ctype).kind {
CTypeKind::ConstantArray(_, num_elems) => num_elems,
ref kind => {
panic!("String literal with unknown size: {bytes:?}, kind = {kind:?}")
}
};

let size = num_elems * (element_size as usize);
let size = self.ast_context.array_len(ctype) * element_size as usize;
let mut bytes_padded = Vec::with_capacity(size);
bytes_padded.extend(bytes);
bytes_padded.resize(size, 0);

bytes_padded
}

Expand Down
8 changes: 5 additions & 3 deletions c2rust-transpile/src/translator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4083,18 +4083,20 @@ impl<'c> Translation<'c> {
Paren(_, val) => self.convert_expr(ctx, val, override_ty),

CompoundLiteral(qty, val) => {
let val = self.convert_expr(ctx, val, override_ty)?;

if !ctx.needs_address() || ctx.is_const {
// consts have their intermediates' lifetimes extended.
return Ok(val);
return self.convert_expr(ctx, val, override_ty);
}

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

// Translate the expression to be assigned to the fresh variable.
// It will be assigned by value, so we don't need its address anymore.
let val = self.convert_expr(ctx.set_needs_address(false), val, override_ty)?;

val.and_then(|val| {
let fresh_stmt = {
let mutbl = if qty.qualifiers.is_const {
Expand Down
16 changes: 6 additions & 10 deletions c2rust-transpile/src/translator/pointers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,23 +123,19 @@ impl<'c> Translation<'c> {
Mutability::Mutable
};

// String literals are translated with a transmute, which produces a temporary.
// Taking the address of a temporary leaves a dangling pointer. So instead,
// cast the string literal directly so that its 'static lifetime is preserved.
// Narrow string literals are translated directly as `[u8; N]` literals when their address
// is taken, without the transmute. String/byte literals are already references in Rust.
if let (
Some(&CExprKind::Literal(literal_cty, CLiteral::String(ref bytes, element_size @ 1))),
Some(&CExprKind::Literal(literal_cty, CLiteral::String(_, element_size @ 1))),
false,
) = (arg_expr_kind, arg_is_macro)
{
let bytes_padded = self.string_literal_bytes(literal_cty.ctype, bytes, element_size);
let len = bytes_padded.len();
val = WithStmts::new_val(mk().lit_expr(bytes_padded));

if is_array_decay {
ref_cast_pointee_ty = Some(mk().ident_ty("u8"));
val = val.map(|val| mk().method_call_expr(val, "as_ptr", vec![]));
} else {
let size = self.ast_context.array_len(literal_cty.ctype) * element_size as usize;
ref_cast_pointee_ty =
Some(mk().array_ty(mk().ident_ty("u8"), mk().lit_expr(len as u128)));
Some(mk().array_ty(mk().ident_ty("u8"), mk().lit_expr(size as u128)));
}
needs_cast = true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ extern "C" {
#[no_mangle]
pub unsafe extern "C" fn call_printf() {
printf(
b"%d, %f\n\0" as *const u8 as *const ::core::ffi::c_char,
b"%d, %f\n\0".as_ptr() as *const ::core::ffi::c_char,
10 as ::core::ffi::c_int,
1.5f64,
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ pub unsafe extern "C" fn assert_call_only_once() -> ::core::ffi::c_int {
if called_only_once() != 0 {
} else {
__assert_fail(
b"called_only_once()\0" as *const u8 as *const ::core::ffi::c_char,
b"called_only_once()\0".as_ptr() as *const ::core::ffi::c_char,
b"./tests/snapshots/os-specific/call_only_once.c\0"
as *const u8 as *const ::core::ffi::c_char,
.as_ptr() as *const ::core::ffi::c_char,
12 as ::core::ffi::c_uint,
__ASSERT_FUNCTION.as_ptr(),
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ unsafe extern "C" fn called_only_once() -> ::core::ffi::c_int {
pub unsafe extern "C" fn assert_call_only_once() -> ::core::ffi::c_int {
if (called_only_once() == 0) as ::core::ffi::c_int as ::core::ffi::c_long != 0 {
__assert_rtn(
b"assert_call_only_once\0" as *const u8 as *const ::core::ffi::c_char,
b"call_only_once.c\0" as *const u8 as *const ::core::ffi::c_char,
b"assert_call_only_once\0".as_ptr() as *const ::core::ffi::c_char,
b"call_only_once.c\0".as_ptr() as *const ::core::ffi::c_char,
12 as ::core::ffi::c_int,
b"called_only_once()\0" as *const u8 as *const ::core::ffi::c_char,
b"called_only_once()\0".as_ptr() as *const ::core::ffi::c_char,
);
} else {
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ pub struct vastruct<'a> {
#[no_mangle]
pub unsafe extern "C" fn call_printf() {
printf(
b"%d, %f\n\0" as *const u8 as *const ::core::ffi::c_char,
b"%d, %f\n\0".as_ptr() as *const ::core::ffi::c_char,
10 as ::core::ffi::c_int,
1.5f64,
);
Expand Down Expand Up @@ -72,19 +72,19 @@ pub unsafe extern "C" fn my_printf(mut fmt: *const ::core::ffi::c_char, mut c2ru
match *fmt as ::core::ffi::c_int {
105 | 100 => {
printf(
b"%d\0" as *const u8 as *const ::core::ffi::c_char,
b"%d\0".as_ptr() as *const ::core::ffi::c_char,
ap.arg::<::core::ffi::c_int>(),
);
}
102 => {
printf(
b"%f\0" as *const u8 as *const ::core::ffi::c_char,
b"%f\0".as_ptr() as *const ::core::ffi::c_char,
ap.arg::<::core::ffi::c_double>(),
);
}
115 => {
printf(
b"%s\0" as *const u8 as *const ::core::ffi::c_char,
b"%s\0".as_ptr() as *const ::core::ffi::c_char,
ap.arg::<*mut ::core::ffi::c_char>(),
);
}
Expand Down Expand Up @@ -153,7 +153,7 @@ pub unsafe extern "C" fn restart_valist(mut fmt: *const ::core::ffi::c_char, mut
#[no_mangle]
pub unsafe extern "C" fn print_int(mut ap: *mut ::core::ffi::VaListImpl) {
printf(
b"%d\0" as *const u8 as *const ::core::ffi::c_char,
b"%d\0".as_ptr() as *const ::core::ffi::c_char,
(*ap).arg::<::core::ffi::c_int>(),
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ pub static mut static_char_array: [::core::ffi::c_char; 9] =
unsafe { ::core::mem::transmute::<[u8; 9], [::core::ffi::c_char; 9]>(*b"mystring\0") };
#[no_mangle]
pub static mut static_char_ptr: *mut ::core::ffi::c_char =
b"mystring\0" as *const u8 as *const ::core::ffi::c_char as *mut ::core::ffi::c_char;
b"mystring\0".as_ptr() as *const ::core::ffi::c_char as *mut ::core::ffi::c_char;
#[no_mangle]
pub static mut static_void_ptr: *mut ::core::ffi::c_void =
unsafe { &raw const static_char_array as *mut ::core::ffi::c_char as *mut ::core::ffi::c_void };
Expand Down Expand Up @@ -89,11 +89,11 @@ pub unsafe extern "C" fn entry() {
&raw mut char_with_string as *mut ::core::ffi::c_char;
let mut char_var_array_ptr: *mut [::core::ffi::c_char; 4] = &raw mut char_with_string;
let mut const_char_lit_ptr: *const ::core::ffi::c_char =
b"abc\0" as *const u8 as *const ::core::ffi::c_char;
b"abc\0".as_ptr() as *const ::core::ffi::c_char;
let mut const_char_lit_array_ptr: *const [::core::ffi::c_char; 4] =
b"abc\0" as *const [u8; 4] as *const [::core::ffi::c_char; 4];
let mut char_lit_ptr: *mut ::core::ffi::c_char =
b"abc\0" as *const u8 as *const ::core::ffi::c_char as *mut ::core::ffi::c_char;
b"abc\0".as_ptr() as *const ::core::ffi::c_char as *mut ::core::ffi::c_char;
let mut char_lit_array_ptr: *mut [::core::ffi::c_char; 4] = b"abc\0" as *const [u8; 4]
as *const [::core::ffi::c_char; 4]
as *mut [::core::ffi::c_char; 4];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ pub const C: C2Rust_Unnamed = 2;
pub const B: C2Rust_Unnamed = 1;
pub const A: C2Rust_Unnamed = 0;
unsafe extern "C" fn side_effect() -> ::core::ffi::c_int {
puts(b"the return of side effect\0" as *const u8 as *const ::core::ffi::c_char);
puts(b"the return of side effect\0".as_ptr() as *const ::core::ffi::c_char);
return 10 as ::core::ffi::c_int;
}
#[no_mangle]
Expand All @@ -44,7 +44,7 @@ pub unsafe extern "C" fn unary_with_side_effect() {
side_effect();
!side_effect();
(side_effect() == 0) as ::core::ffi::c_int;
(b"\0" as *const u8 as *const ::core::ffi::c_char).offset(side_effect() as isize)
(b"\0".as_ptr() as *const ::core::ffi::c_char).offset(side_effect() as isize)
as *const ::core::ffi::c_char;
*arr[side_effect() as usize];
arr[side_effect() as usize] = arr[side_effect() as usize].offset(1);
Expand All @@ -59,8 +59,8 @@ pub unsafe extern "C" fn compound_literal() {
#[no_mangle]
pub unsafe extern "C" fn statement_expr() {
'_c2rust_label: {
puts(b"should execute\0" as *const u8 as *const ::core::ffi::c_char);
puts(b"should execute\0".as_ptr() as *const ::core::ffi::c_char);
return;
};
puts(b"should be unreachable!\0" as *const u8 as *const ::core::ffi::c_char);
puts(b"should be unreachable!\0".as_ptr() as *const ::core::ffi::c_char);
}
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ pub unsafe extern "C" fn local_muts() {
let mut indexing: ::core::ffi::c_char =
NESTED_STR[LITERAL_FLOAT as ::core::ffi::c_int as usize];
let mut str_concatenation_ptr: *const ::core::ffi::c_char =
b"hello hello world\0" as *const u8 as *const ::core::ffi::c_char;
b"hello hello world\0".as_ptr() as *const ::core::ffi::c_char;
let mut str_concatenation: [::core::ffi::c_char; 18] =
::core::mem::transmute::<[u8; 18], [::core::ffi::c_char; 18]>(*b"hello hello world\0");
let mut builtin: ::core::ffi::c_int =
Expand Down Expand Up @@ -172,7 +172,7 @@ pub unsafe extern "C" fn local_consts() {
let conversion_cast: ::core::ffi::c_double = CONVERSION_CAST;
let indexing: ::core::ffi::c_char = NESTED_STR[LITERAL_FLOAT as ::core::ffi::c_int as usize];
let str_concatenation_ptr: *const ::core::ffi::c_char =
b"hello hello world\0" as *const u8 as *const ::core::ffi::c_char;
b"hello hello world\0".as_ptr() as *const ::core::ffi::c_char;
let str_concatenation: [::core::ffi::c_char; 18] =
::core::mem::transmute::<[u8; 18], [::core::ffi::c_char; 18]>(*b"hello hello world\0");
let builtin: ::core::ffi::c_int = (LITERAL_INT as ::core::ffi::c_uint).leading_zeros() as i32;
Expand Down Expand Up @@ -246,7 +246,7 @@ static mut global_static_const_narrowing_cast: ::core::ffi::c_char =
static mut global_static_const_conversion_cast: ::core::ffi::c_double = CONVERSION_CAST;
static mut global_static_const_indexing: ::core::ffi::c_char = 0;
static mut global_static_const_str_concatenation_ptr: *const ::core::ffi::c_char =
b"hello hello world\0" as *const u8 as *const ::core::ffi::c_char;
b"hello hello world\0".as_ptr() as *const ::core::ffi::c_char;
static mut global_static_const_str_concatenation: [::core::ffi::c_char; 18] = unsafe {
::core::mem::transmute::<[u8; 18], [::core::ffi::c_char; 18]>(*b"hello hello world\0")
};
Expand Down Expand Up @@ -324,7 +324,7 @@ pub static mut global_const_conversion_cast: ::core::ffi::c_double = CONVERSION_
pub static mut global_const_indexing: ::core::ffi::c_char = 0;
#[no_mangle]
pub static mut global_const_str_concatenation_ptr: *const ::core::ffi::c_char =
b"hello hello world\0" as *const u8 as *const ::core::ffi::c_char;
b"hello hello world\0".as_ptr() as *const ::core::ffi::c_char;
#[no_mangle]
pub static mut global_const_str_concatenation: [::core::ffi::c_char; 18] = unsafe {
::core::mem::transmute::<[u8; 18], [::core::ffi::c_char; 18]>(*b"hello hello world\0")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ input_file: c2rust-transpile/tests/snapshots/predefined.c
pub unsafe extern "C" fn predefined() {
let mut line: ::core::ffi::c_int = 2 as ::core::ffi::c_int;
let mut file_name: *const ::core::ffi::c_char =
b"predefined.c\0" as *const u8 as *const ::core::ffi::c_char;
b"predefined.c\0".as_ptr() as *const ::core::ffi::c_char;
let mut func: *const ::core::ffi::c_char =
b"predefined\0" as *const u8 as *const ::core::ffi::c_char;
b"predefined\0".as_ptr() as *const ::core::ffi::c_char;
}
#[no_mangle]
pub unsafe extern "C" fn extension_operator() -> *const ::core::ffi::c_char {
return b"const char *extension_operator()\0" as *const u8 as *const ::core::ffi::c_char;
return b"const char *extension_operator()\0".as_ptr() as *const ::core::ffi::c_char;
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ pub struct alpn_spec {
}
#[no_mangle]
pub unsafe extern "C" fn ptr() {
let mut _s: *const ::core::ffi::c_char = b"hello\0" as *const u8 as *const ::core::ffi::c_char;
let mut _s: *const ::core::ffi::c_char = b"hello\0".as_ptr() as *const ::core::ffi::c_char;
}
#[no_mangle]
pub unsafe extern "C" fn array_deduced_length() {
Expand Down Expand Up @@ -57,7 +57,7 @@ pub unsafe extern "C" fn int_array_extra_braces() {
}
#[no_mangle]
pub unsafe extern "C" fn ptr_extra_braces() {
let mut _s: *const ::core::ffi::c_char = b"hello\0" as *const u8 as *const ::core::ffi::c_char;
let mut _s: *const ::core::ffi::c_char = b"hello\0".as_ptr() as *const ::core::ffi::c_char;
}
#[no_mangle]
pub unsafe extern "C" fn array_extra_braces() {
Expand All @@ -67,7 +67,7 @@ pub unsafe extern "C" fn array_extra_braces() {
#[no_mangle]
pub unsafe extern "C" fn array_of_ptrs() {
let mut _s: [*const ::core::ffi::c_char; 3] = [
b"hello\0" as *const u8 as *const ::core::ffi::c_char,
b"hello\0".as_ptr() as *const ::core::ffi::c_char,
::core::ptr::null::<::core::ffi::c_char>(),
::core::ptr::null::<::core::ffi::c_char>(),
];
Expand Down