diff --git a/c2rust-transpile/src/translator/literals.rs b/c2rust-transpile/src/translator/literals.rs index 256b225de6..e5587ae307 100644 --- a/c2rust-transpile/src/translator/literals.rs +++ b/c2rust-transpile/src/translator/literals.rs @@ -139,6 +139,64 @@ impl<'c> Translation<'c> { bytes_padded } + /// Convert a C compound literal expression to a Rust expression. + pub fn convert_compound_literal( + &self, + ctx: ExprContext, + qty: CQualTypeId, + val: CExprId, + override_ty: Option, + ) -> TranslationResult>> { + // 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. + if !ctx.needs_address() || ctx.expanding_macro.is_some() { + return self.convert_expr(ctx, val, override_ty); + } + + 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| { + // If we are translating a static variable, + // then the fresh variable should also be static. + if ctx.is_static { + let item = mk().mutbl().static_item(&fresh_name, fresh_ty, val); + let fresh_stmt = mk().item_stmt(item); + let mut val = WithStmts::new(vec![fresh_stmt], mk().ident_expr(fresh_name)); + + // Accessing a static variable is unsafe. + // In the current nightly, this applies also to taking a raw pointer, + // but this requirement was removed in later versions of the + // `raw_ref_op` feature. + if self.tcfg.edition < Edition2024 { + val.set_unsafe(); + } + + Ok(val) + } else { + let mutbl = if qty.qualifiers.is_const { + Mutability::Immutable + } else { + Mutability::Mutable + }; + let local = mk().local( + mk().set_mutbl(mutbl).ident_pat(&fresh_name), + Some(fresh_ty), + Some(val), + ); + let fresh_stmt = mk().local_stmt(Box::new(local)); + Ok(WithStmts::new( + vec![fresh_stmt], + mk().ident_expr(fresh_name), + )) + } + }) + } + /// Convert an initialization list into an expression. These initialization lists can be /// used as array literals, struct literals, and union literals in code. pub fn convert_init_list( diff --git a/c2rust-transpile/src/translator/mod.rs b/c2rust-transpile/src/translator/mod.rs index 13190694a3..1bba9dbb63 100644 --- a/c2rust-transpile/src/translator/mod.rs +++ b/c2rust-transpile/src/translator/mod.rs @@ -1685,7 +1685,6 @@ impl<'c> Translation<'c> { use CExprKind::*; match self.ast_context[expr_id].kind { - DeclRef(_, _, LRValue::LValue) => return true, ImplicitCast(_, _, cast_kind, _, _) | ExplicitCast(_, _, cast_kind, _, _) => { use CastKind::*; match cast_kind { @@ -2143,21 +2142,47 @@ impl<'c> Translation<'c> { ref attrs, .. } if has_static_duration || has_thread_duration => { - if has_thread_duration { - self.use_feature("thread_local"); - } - let new_name = &self .renamer .borrow() .get(&decl_id) .expect("Variables should already be renamed"); + let mut static_def = if is_externally_visible { + mk_linkage(false, new_name, ident, self.tcfg.edition) + .pub_() + .extern_("C") + } else if self.cur_file.get().is_some() { + mk().pub_() + } else { + mk() + }; + + // Force mutability due to the potential for raw pointers occurring in the type + // and because we may be assigning to these variables in the external initializer + static_def = static_def.mutbl(); + + if has_thread_duration { + self.use_feature("thread_local"); + static_def = static_def.single_attr("thread_local"); + } + + // Add static attributes + for attr in attrs { + static_def = match attr { + c_ast::Attribute::Used => static_def.single_attr("used"), + c_ast::Attribute::Section(name) => { + static_def.str_attr("link_section", name) + } + _ => continue, + }; + } + let ctx = ctx.static_(); // Collect problematic static initializers and offload them to sections for the linker // to initialize for us - let (ty, init) = if self.static_initializer_is_uncompilable(initializer, typ) { + if self.static_initializer_is_uncompilable(initializer, typ) { // Note: We don't pass `is_const` through here. Extracted initializers are run // outside of the static initializer, in a non-const context. let ctx = ctx.not_const(); @@ -2186,55 +2211,28 @@ impl<'c> Translation<'c> { self.add_static_initializer_to_section(ctx, new_name, typ, &mut init)?; - (ty, init) + Ok(ConvertedDecl::Item( + static_def.span(span).static_item(new_name, ty, init), + )) } else { let ConvertedVariable { ty, mutbl: _, init } = self.convert_variable(ctx.const_(), initializer, typ)?; let mut init = init?; + let mut items = init.stmts_to_items().ok_or_else(|| { + format_err!("Expected only item statements in static initializer") + })?; + // TODO: Replace this by relying entirely on // WithStmts.is_unsafe() of the translated variable if self.static_initializer_is_unsafe(initializer, typ) { init.set_unsafe() } - let init = init.to_unsafe_pure_expr().ok_or_else(|| { - format_err!("Expected no side-effects in static initializer") - })?; - - (ty, init) - }; + let init = init.to_unsafe_pure_expr().unwrap(); + let item = static_def.span(span).static_item(new_name, ty, init); + items.push(item); - let static_def = if is_externally_visible { - mk_linkage(false, new_name, ident, self.tcfg.edition) - .pub_() - .extern_("C") - } else if self.cur_file.get().is_some() { - mk().pub_() - } else { - mk() - }; - - // Force mutability due to the potential for raw pointers occurring in the type - // and because we may be assigning to these variables in the external initializer - let mut static_def = static_def.span(span).mutbl(); - if has_thread_duration { - static_def = static_def.single_attr("thread_local"); - } - - // Add static attributes - for attr in attrs { - static_def = match attr { - c_ast::Attribute::Used => static_def.single_attr("used"), - c_ast::Attribute::Section(name) => static_def - .unsafety(attr_unsafety(self.tcfg.edition)) - .str_attr("link_section", name) - .unsafety(Unsafety::Normal), - _ => continue, - } + Ok(ConvertedDecl::Items(items)) } - - Ok(ConvertedDecl::Item( - static_def.static_item(new_name, ty, init), - )) } Variable { .. } => Err(TranslationError::generic( @@ -3577,52 +3575,73 @@ impl<'c> Translation<'c> { val = self.volatile_read(val, qual_ty)?; } - // If the variable is actually an `EnumConstant`, we need to add a cast to the - // expected integral type. - if let &CDeclKind::EnumConstant { .. } = decl { - val = self.convert_cast_from_enum(qual_ty.ctype, val)?; - } - - // If we are referring to a function and need its address, we - // need to cast it to fn() to ensure that it has a real address. let mut set_unsafe = false; - if ctx.needs_address() { - if let CDeclKind::Function { parameters, .. } = decl { - let ty = self.convert_type(qual_ty.ctype)?; - let actual_ty = self - .type_converter - .borrow_mut() - .knr_function_type_with_parameters( - &self.ast_context, - qual_ty.ctype, - parameters, - )?; - if let Some(actual_ty) = actual_ty { - if actual_ty != ty { - // If we're casting a concrete function to - // a K&R function pointer type, use transmute - self.import_type(qual_ty.ctype); - - val = transmute_expr(actual_ty, ty, val); - set_unsafe = true; - } - } else { - let decl_kind = &self.ast_context[decl_id].kind; - let kind_with_declared_args = - self.ast_context.fn_decl_ty_with_declared_args(decl_kind); - - if let Some(ty) = self - .ast_context - .type_for_kind(&kind_with_declared_args) - .map(CQualTypeId::new) - { - let ty = self.convert_type(ty.ctype)?; - val = mk().cast_expr(val, ty); + + match decl { + CDeclKind::EnumConstant { .. } => { + // If the variable is actually an `EnumConstant`, we need to add a cast to + // the expected integral type. + val = self.convert_cast_from_enum(qual_ty.ctype, val)?; + } + + CDeclKind::Function { parameters, .. } => { + // If we are referring to a function and need its address, we + // need to cast it to fn() to ensure that it has a real address. + if ctx.needs_address() { + let ty = self.convert_type(qual_ty.ctype)?; + let actual_ty = self + .type_converter + .borrow_mut() + .knr_function_type_with_parameters( + &self.ast_context, + qual_ty.ctype, + parameters, + )?; + if let Some(actual_ty) = actual_ty { + if actual_ty != ty { + // If we're casting a concrete function to + // a K&R function pointer type, use transmute + self.import_type(qual_ty.ctype); + + val = transmute_expr(actual_ty, ty, val); + set_unsafe = true; + } } else { - val = mk().cast_expr(val, ty); + let decl_kind = &self.ast_context[decl_id].kind; + let kind_with_declared_args = + self.ast_context.fn_decl_ty_with_declared_args(decl_kind); + + if let Some(ty) = self + .ast_context + .type_for_kind(&kind_with_declared_args) + .map(CQualTypeId::new) + { + let ty = self.convert_type(ty.ctype)?; + val = mk().cast_expr(val, ty); + } else { + val = mk().cast_expr(val, ty); + } } } } + + CDeclKind::Variable { + has_static_duration, + has_thread_duration, + .. + } => { + // Accessing a static variable is unsafe. + // In the current nightly, this applies also to taking a raw pointer, + // but this requirement was removed in later versions of the + // `raw_ref_op` feature. + if (*has_static_duration || *has_thread_duration) + && (self.tcfg.edition < Edition2024 || !ctx.needs_address()) + { + set_unsafe = true; + } + } + + _ => {} } if let CTypeKind::VariableArray(..) = @@ -4013,43 +4032,7 @@ impl<'c> Translation<'c> { Paren(_, val) => self.convert_expr(ctx, val, override_ty), - CompoundLiteral(qty, val) => { - if !ctx.needs_address() || ctx.is_const { - // consts have their intermediates' lifetimes extended. - 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 { - Mutability::Immutable - } else { - Mutability::Mutable - }; - - let local = mk().local( - mk().set_mutbl(mutbl).ident_pat(&fresh_name), - Some(fresh_ty), - Some(val), - ); - mk().local_stmt(Box::new(local)) - }; - - Ok(WithStmts::new( - vec![fresh_stmt], - mk().ident_expr(fresh_name), - )) - }) - } + CompoundLiteral(qty, val) => self.convert_compound_literal(ctx, qty, val, override_ty), InitList(ty, ref ids, opt_union_field_id, _) => { self.convert_init_list(ctx, ty, ids, opt_union_field_id) diff --git a/c2rust-transpile/src/translator/pointers.rs b/c2rust-transpile/src/translator/pointers.rs index d7f42fb347..e258ca47bc 100644 --- a/c2rust-transpile/src/translator/pointers.rs +++ b/c2rust-transpile/src/translator/pointers.rs @@ -144,11 +144,7 @@ impl<'c> Translation<'c> { // and must be regular-borrowed first. // Borrowing in a const context will extend the lifetime to static. else if arg_is_macro - || ctx.is_const - && matches!( - arg_expr_kind, - Some(CExprKind::Literal(..) | CExprKind::CompoundLiteral(..)) - ) + || ctx.is_const && matches!(arg_expr_kind, Some(CExprKind::Literal(..))) { let arg_cty_kind = &self.ast_context.resolve_type(arg_cty.ctype).kind; diff --git a/c2rust-transpile/src/with_stmts.rs b/c2rust-transpile/src/with_stmts.rs index d1e7428c7f..1bd4cc96ec 100644 --- a/c2rust-transpile/src/with_stmts.rs +++ b/c2rust-transpile/src/with_stmts.rs @@ -1,6 +1,6 @@ use c2rust_ast_builder::mk; use std::iter::FromIterator; -use syn::{Block, Expr, Stmt}; +use syn::{Block, Expr, Item, Stmt}; #[derive(Clone, Debug)] pub struct WithStmts { @@ -17,6 +17,15 @@ impl WithStmts { is_unsafe: false, } } + + pub fn new_unsafe(stmts: Vec, val: T) -> Self { + WithStmts { + stmts, + val, + is_unsafe: true, + } + } + pub fn new_val(val: T) -> Self { WithStmts { stmts: vec![], @@ -90,6 +99,18 @@ impl WithStmts { &mut self.stmts } + /// If all statements in self.stmts are [`Item`] statements, returns the contained [`Item`]s. + /// Otherwise, returns [`None`]. + pub fn stmts_to_items(&mut self) -> Option>> { + std::mem::take(&mut self.stmts) + .into_iter() + .map(|stmt| match stmt { + Stmt::Item(item) => Some(Box::new(item)), + _ => None, + }) + .collect() + } + pub fn is_unsafe(&self) -> bool { self.is_unsafe } diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@arrays.c.2024.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@arrays.c.2024.snap index 511d30a988..fefd5eb2bd 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@arrays.c.2024.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@arrays.c.2024.snap @@ -42,7 +42,7 @@ pub static mut static_char_ptr: *mut ::core::ffi::c_char = b"mystring\0".as_ptr() as *const ::core::ffi::c_char as *mut ::core::ffi::c_char; #[unsafe(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 }; + &raw const static_char_array as *mut ::core::ffi::c_char as *mut ::core::ffi::c_void; #[unsafe(no_mangle)] pub unsafe extern "C" fn entry() { unsafe { diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@compound_literals.c.2021.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@compound_literals.c.2021.snap index ee11fe0448..1153a79f2f 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@compound_literals.c.2021.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@compound_literals.c.2021.snap @@ -14,18 +14,22 @@ expression: cat tests/snapshots/compound_literals.2021.rs #![feature(raw_ref_op)] #[no_mangle] pub static mut static_single_int: ::core::ffi::c_int = 42; +static mut c2rust_fresh0: ::core::ffi::c_int = 42; #[no_mangle] pub static mut static_single_int_ptr: *mut ::core::ffi::c_int = - &42 as *const ::core::ffi::c_int as *mut ::core::ffi::c_int; + unsafe { &raw const c2rust_fresh0 as *mut ::core::ffi::c_int }; +static mut c2rust_fresh1: [::core::ffi::c_int; 2] = [42, 9001]; #[no_mangle] pub static mut static_int_ptr_to_array: *mut ::core::ffi::c_int = - [42, 9001].as_ptr() as *mut ::core::ffi::c_int; + unsafe { &raw const c2rust_fresh1 as *mut ::core::ffi::c_int }; +static mut c2rust_fresh2: [::core::ffi::c_int; 2] = [42, 9001]; #[no_mangle] pub static mut static_volatile_int_ptr_to_array: *mut ::core::ffi::c_int = - [42, 9001].as_ptr() as *mut ::core::ffi::c_int as *mut ::core::ffi::c_int; + unsafe { &raw const c2rust_fresh2 as *mut ::core::ffi::c_int as *mut ::core::ffi::c_int }; +static mut c2rust_fresh3: [::core::ffi::c_int; 2] = [42, 9001]; #[no_mangle] pub static mut static_int_array_ptr: *mut [::core::ffi::c_int; 2] = - &[42, 9001] as *const [::core::ffi::c_int; 2] as *mut [::core::ffi::c_int; 2]; + unsafe { &raw const c2rust_fresh3 as *mut [::core::ffi::c_int; 2] }; pub const SINGLE_INT: ::core::ffi::c_int = 42 as ::core::ffi::c_int; pub const INT_ARRAY: [::core::ffi::c_int; 2] = [42 as ::core::ffi::c_int, 9001 as ::core::ffi::c_int]; @@ -35,22 +39,22 @@ pub const CHAR_ARRAY: [::core::ffi::c_char; 6] = pub unsafe extern "C" fn local_compound_literals() { unsafe { let mut single_int: ::core::ffi::c_int = 42 as ::core::ffi::c_int; - let mut c2rust_fresh0: ::core::ffi::c_int = 42 as ::core::ffi::c_int; - let mut single_int_ptr: *mut ::core::ffi::c_int = &raw mut c2rust_fresh0; - let mut c2rust_fresh1: [::core::ffi::c_int; 2] = + let mut c2rust_fresh4: ::core::ffi::c_int = 42 as ::core::ffi::c_int; + let mut single_int_ptr: *mut ::core::ffi::c_int = &raw mut c2rust_fresh4; + let mut c2rust_fresh5: [::core::ffi::c_int; 2] = [42 as ::core::ffi::c_int, 9001 as ::core::ffi::c_int]; let mut int_ptr_to_array: *mut ::core::ffi::c_int = - &raw mut c2rust_fresh1 as *mut ::core::ffi::c_int; - let mut c2rust_fresh2: [::core::ffi::c_char; 6] = + &raw mut c2rust_fresh5 as *mut ::core::ffi::c_int; + let mut c2rust_fresh6: [::core::ffi::c_char; 6] = ::core::mem::transmute::<[u8; 6], [::core::ffi::c_char; 6]>(*b"hello\0"); let mut char_ptr_to_array: *mut ::core::ffi::c_char = - &raw mut c2rust_fresh2 as *mut ::core::ffi::c_char; - let mut c2rust_fresh3: [::core::ffi::c_int; 2] = + &raw mut c2rust_fresh6 as *mut ::core::ffi::c_char; + let mut c2rust_fresh7: [::core::ffi::c_int; 2] = [42 as ::core::ffi::c_int, 9001 as ::core::ffi::c_int]; - let mut int_array_ptr: *mut [::core::ffi::c_int; 2] = &raw mut c2rust_fresh3; - let mut c2rust_fresh4: [::core::ffi::c_char; 6] = + let mut int_array_ptr: *mut [::core::ffi::c_int; 2] = &raw mut c2rust_fresh7; + let mut c2rust_fresh8: [::core::ffi::c_char; 6] = ::core::mem::transmute::<[u8; 6], [::core::ffi::c_char; 6]>(*b"hello\0"); - let mut char_array_ptr: *mut [::core::ffi::c_char; 6] = &raw mut c2rust_fresh4; + let mut char_array_ptr: *mut [::core::ffi::c_char; 6] = &raw mut c2rust_fresh8; let mut macro_single_int: ::core::ffi::c_int = SINGLE_INT; let mut macro_single_int_ptr: *mut ::core::ffi::c_int = &mut SINGLE_INT as *mut ::core::ffi::c_int; diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@compound_literals.c.2024.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@compound_literals.c.2024.snap index 2ef576ea1b..fed4e77fc3 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@compound_literals.c.2024.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@compound_literals.c.2024.snap @@ -13,18 +13,22 @@ expression: cat tests/snapshots/compound_literals.2024.rs #![deny(unsafe_op_in_unsafe_fn)] #[unsafe(no_mangle)] pub static mut static_single_int: ::core::ffi::c_int = 42; +static mut c2rust_fresh0: ::core::ffi::c_int = 42; #[unsafe(no_mangle)] pub static mut static_single_int_ptr: *mut ::core::ffi::c_int = - &42 as *const ::core::ffi::c_int as *mut ::core::ffi::c_int; + &raw const c2rust_fresh0 as *mut ::core::ffi::c_int; +static mut c2rust_fresh1: [::core::ffi::c_int; 2] = [42, 9001]; #[unsafe(no_mangle)] pub static mut static_int_ptr_to_array: *mut ::core::ffi::c_int = - [42, 9001].as_ptr() as *mut ::core::ffi::c_int; + &raw const c2rust_fresh1 as *mut ::core::ffi::c_int; +static mut c2rust_fresh2: [::core::ffi::c_int; 2] = [42, 9001]; #[unsafe(no_mangle)] pub static mut static_volatile_int_ptr_to_array: *mut ::core::ffi::c_int = - [42, 9001].as_ptr() as *mut ::core::ffi::c_int as *mut ::core::ffi::c_int; + &raw const c2rust_fresh2 as *mut ::core::ffi::c_int as *mut ::core::ffi::c_int; +static mut c2rust_fresh3: [::core::ffi::c_int; 2] = [42, 9001]; #[unsafe(no_mangle)] pub static mut static_int_array_ptr: *mut [::core::ffi::c_int; 2] = - &[42, 9001] as *const [::core::ffi::c_int; 2] as *mut [::core::ffi::c_int; 2]; + &raw const c2rust_fresh3 as *mut [::core::ffi::c_int; 2]; pub const SINGLE_INT: ::core::ffi::c_int = 42 as ::core::ffi::c_int; pub const INT_ARRAY: [::core::ffi::c_int; 2] = [42 as ::core::ffi::c_int, 9001 as ::core::ffi::c_int]; @@ -34,22 +38,22 @@ pub const CHAR_ARRAY: [::core::ffi::c_char; 6] = pub unsafe extern "C" fn local_compound_literals() { unsafe { let mut single_int: ::core::ffi::c_int = 42 as ::core::ffi::c_int; - let mut c2rust_fresh0: ::core::ffi::c_int = 42 as ::core::ffi::c_int; - let mut single_int_ptr: *mut ::core::ffi::c_int = &raw mut c2rust_fresh0; - let mut c2rust_fresh1: [::core::ffi::c_int; 2] = + let mut c2rust_fresh4: ::core::ffi::c_int = 42 as ::core::ffi::c_int; + let mut single_int_ptr: *mut ::core::ffi::c_int = &raw mut c2rust_fresh4; + let mut c2rust_fresh5: [::core::ffi::c_int; 2] = [42 as ::core::ffi::c_int, 9001 as ::core::ffi::c_int]; let mut int_ptr_to_array: *mut ::core::ffi::c_int = - &raw mut c2rust_fresh1 as *mut ::core::ffi::c_int; - let mut c2rust_fresh2: [::core::ffi::c_char; 6] = + &raw mut c2rust_fresh5 as *mut ::core::ffi::c_int; + let mut c2rust_fresh6: [::core::ffi::c_char; 6] = ::core::mem::transmute::<[u8; 6], [::core::ffi::c_char; 6]>(*b"hello\0"); let mut char_ptr_to_array: *mut ::core::ffi::c_char = - &raw mut c2rust_fresh2 as *mut ::core::ffi::c_char; - let mut c2rust_fresh3: [::core::ffi::c_int; 2] = + &raw mut c2rust_fresh6 as *mut ::core::ffi::c_char; + let mut c2rust_fresh7: [::core::ffi::c_int; 2] = [42 as ::core::ffi::c_int, 9001 as ::core::ffi::c_int]; - let mut int_array_ptr: *mut [::core::ffi::c_int; 2] = &raw mut c2rust_fresh3; - let mut c2rust_fresh4: [::core::ffi::c_char; 6] = + let mut int_array_ptr: *mut [::core::ffi::c_int; 2] = &raw mut c2rust_fresh7; + let mut c2rust_fresh8: [::core::ffi::c_char; 6] = ::core::mem::transmute::<[u8; 6], [::core::ffi::c_char; 6]>(*b"hello\0"); - let mut char_array_ptr: *mut [::core::ffi::c_char; 6] = &raw mut c2rust_fresh4; + let mut char_array_ptr: *mut [::core::ffi::c_char; 6] = &raw mut c2rust_fresh8; let mut macro_single_int: ::core::ffi::c_int = SINGLE_INT; let mut macro_single_int_ptr: *mut ::core::ffi::c_int = &mut SINGLE_INT as *mut ::core::ffi::c_int; diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@empty_init.c.2021.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@empty_init.c.2021.snap index 7408430dc1..d2cb0ab838 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@empty_init.c.2021.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@empty_init.c.2021.snap @@ -11,12 +11,14 @@ expression: cat tests/snapshots/empty_init.2021.rs unused_mut )] #![deny(unsafe_op_in_unsafe_fn)] +#![feature(raw_ref_op)] #[derive(Copy, Clone)] #[repr(C)] pub struct Scope { pub next: *mut Scope, } -#[no_mangle] -pub static mut scope: *mut Scope = &Scope { +static mut c2rust_fresh0: Scope = Scope { next: ::core::ptr::null::() as *mut Scope, -} as *const Scope as *mut Scope; +}; +#[no_mangle] +pub static mut scope: *mut Scope = unsafe { &raw const c2rust_fresh0 as *mut Scope }; diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@empty_init.c.2024.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@empty_init.c.2024.snap index 908cf76ca3..b9f17682cd 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@empty_init.c.2024.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@empty_init.c.2024.snap @@ -16,7 +16,8 @@ expression: cat tests/snapshots/empty_init.2024.rs pub struct Scope { pub next: *mut Scope, } -#[unsafe(no_mangle)] -pub static mut scope: *mut Scope = &Scope { +static mut c2rust_fresh0: Scope = Scope { next: ::core::ptr::null::() as *mut Scope, -} as *const Scope as *mut Scope; +}; +#[unsafe(no_mangle)] +pub static mut scope: *mut Scope = &raw const c2rust_fresh0 as *mut Scope; diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@macros.c.2024.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@macros.c.2024.snap index a79d19245f..0411e1a0dd 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@macros.c.2024.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@macros.c.2024.snap @@ -375,7 +375,7 @@ pub static mut fns: fn_ptrs = fn_ptrs { fn2: None, }; #[unsafe(no_mangle)] -pub static mut p: *const fn_ptrs = unsafe { &raw const fns }; +pub static mut p: *const fn_ptrs = &raw const fns; pub const ZSTD_WINDOWLOG_MAX_32: ::core::ffi::c_int = 30 as ::core::ffi::c_int; pub const ZSTD_WINDOWLOG_MAX_64: ::core::ffi::c_int = 31 as ::core::ffi::c_int; #[unsafe(no_mangle)]