diff --git a/c2rust-transpile/src/c_ast/mod.rs b/c2rust-transpile/src/c_ast/mod.rs index d03d1e88b0..c01937bf6c 100644 --- a/c2rust-transpile/src/c_ast/mod.rs +++ b/c2rust-transpile/src/c_ast/mod.rs @@ -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); diff --git a/c2rust-transpile/src/translator/literals.rs b/c2rust-transpile/src/translator/literals.rs index b23034f062..28fc05d0e3 100644 --- a/c2rust-transpile/src/translator/literals.rs +++ b/c2rust-transpile/src/translator/literals.rs @@ -108,18 +108,23 @@ 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)) + } } } } @@ -127,18 +132,10 @@ impl<'c> Translation<'c> { /// 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 { - 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 } diff --git a/c2rust-transpile/src/translator/mod.rs b/c2rust-transpile/src/translator/mod.rs index f729d198c7..c014935ccf 100644 --- a/c2rust-transpile/src/translator/mod.rs +++ b/c2rust-transpile/src/translator/mod.rs @@ -4083,11 +4083,9 @@ 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. @@ -4095,6 +4093,10 @@ impl<'c> Translation<'c> { 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 { diff --git a/c2rust-transpile/src/translator/pointers.rs b/c2rust-transpile/src/translator/pointers.rs index 63d567a37f..763aefe6e2 100644 --- a/c2rust-transpile/src/translator/pointers.rs +++ b/c2rust-transpile/src/translator/pointers.rs @@ -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; } diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile-aarch64-macos@varargs.c.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile-aarch64-macos@varargs.c.snap index 73201ffa64..cccaa6d6bf 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile-aarch64-macos@varargs.c.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile-aarch64-macos@varargs.c.snap @@ -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, ); diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile-linux@call_only_once.c.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile-linux@call_only_once.c.snap index 8cf18b5540..e7b41508e3 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile-linux@call_only_once.c.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile-linux@call_only_once.c.snap @@ -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(), ); diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile-macos@call_only_once.c.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile-macos@call_only_once.c.snap index f323d9fc83..bf22723217 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile-macos@call_only_once.c.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile-macos@call_only_once.c.snap @@ -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 { }; diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile-x86_64-linux@varargs.c.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile-x86_64-linux@varargs.c.snap index 4e966fb376..fe305a4861 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile-x86_64-linux@varargs.c.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile-x86_64-linux@varargs.c.snap @@ -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, ); @@ -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>(), ); } @@ -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>(), ); } diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@arrays.c.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@arrays.c.snap index 4eb7076a19..5541f3c2dd 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@arrays.c.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@arrays.c.snap @@ -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 }; @@ -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]; diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.snap index bfeb37a9ce..e5df52b02a 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.snap @@ -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] @@ -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); @@ -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); } diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@macros.c.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@macros.c.snap index 016c274c86..36f2b73260 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@macros.c.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@macros.c.snap @@ -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 = @@ -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; @@ -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") }; @@ -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") diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@predefined.c.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@predefined.c.snap index 3a07393813..fe6a4cc665 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@predefined.c.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@predefined.c.snap @@ -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; } diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@str_init.c.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@str_init.c.snap index d213d1b891..8fd0d97583 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@str_init.c.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@str_init.c.snap @@ -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() { @@ -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() { @@ -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>(), ];