From 04a9c59484ac24a47bacb0c6c85b828cc10e7f72 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Sat, 16 May 2026 18:00:28 +0100 Subject: [PATCH 1/5] Wrap initialization of global variables in unsafe --- cpp2rust/converter/converter.cpp | 31 +++++++++++++++++++++++-------- cpp2rust/converter/converter.h | 2 ++ 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index e0e26086..c880a9cb 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -437,25 +437,40 @@ bool Converter::ConvertLambdaVarDecl(clang::VarDecl *decl) { return false; } +void ConvertVarDeclInitializer(clang::VarDecl *decl) { + if (decl->hasInit()) { + ConvertVarInit(decl->getType(), decl->getInit()); + } else if (!clang::isa(decl)) { + StrCat(ConvertVarDefaultInit(decl->getType())); + } +} + void Converter::ConvertVarDecl(clang::VarDecl *decl) { if (!ConvertVarDeclSkipInit(decl)) { // Skip global variables declared extern return; } - auto qual_type = decl->getType(); PushConstInitializer static_init(*this, decl->isFileVarDecl() || decl->isStaticLocal()); - if (decl->hasInit()) { - StrCat(token::kAssign); - ConvertVarInit(qual_type, decl->getInit()); - } else if (!clang::isa(decl)) { - StrCat(token::kAssign, ConvertVarDefaultInit(qual_type)); - } + StrCat(token::kAssign); + ConvertVarDeclInitializer(decl); StrCat(token::kSemiColon); } void Converter::ConvertGlobalVarDecl(clang::VarDecl *decl) { - ConvertVarDecl(decl); + if (!ConvertVarDeclSkipInit(decl)) { + // Skip global variables declared extern + return; + } + PushConstInitializer static_init(*this, decl->isFileVarDecl() || + decl->isStaticLocal()); + StrCat(token::kAssign); + StrCat(keyword_unsafe_); + { + PushBrace push(*this); + ConvertVarDeclInitializer(decl); + } + StrCat(token::kSemiColon); } bool Converter::VisitVarDecl(clang::VarDecl *decl) { diff --git a/cpp2rust/converter/converter.h b/cpp2rust/converter/converter.h index 83ce8850..2bccb764 100644 --- a/cpp2rust/converter/converter.h +++ b/cpp2rust/converter/converter.h @@ -88,6 +88,8 @@ class Converter : public clang::RecursiveASTVisitor { void ConvertVarDecl(clang::VarDecl *decl); + void ConvertVarDeclInitializer(clang::VarDecl *decl); + virtual void ConvertGlobalVarDecl(clang::VarDecl *decl); virtual void ConvertVaListVarDecl(clang::VarDecl *decl); From fdbfab3948a949b420c0fc2ae58a38a667b8ca73 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Sat, 16 May 2026 18:00:42 +0100 Subject: [PATCH 2/5] Update tests --- tests/unit/out/unsafe/addr_of_global.rs | 32 +++--- .../unit/out/unsafe/bool_condition_logical.rs | 2 +- .../out/unsafe/bool_condition_logical_c.rs | 2 +- tests/unit/out/unsafe/default_in_statics.rs | 100 ++++++++++-------- tests/unit/out/unsafe/enum_int_interop.rs | 42 ++++---- tests/unit/out/unsafe/enum_int_interop_c.rs | 42 ++++---- tests/unit/out/unsafe/fn_ptr_global.rs | 2 +- tests/unit/out/unsafe/fn_ptr_vtable.rs | 2 +- tests/unit/out/unsafe/global_pointers.rs | 40 ++++--- .../out/unsafe/global_without_initializer.rs | 6 +- tests/unit/out/unsafe/null_in_statics.rs | 16 +-- tests/unit/out/unsafe/static_local.rs | 10 +- tests/unit/out/unsafe/string_escape.rs | 14 +-- .../out/unsafe/union_tagged_struct_arms.rs | 12 ++- tests/unit/out/unsafe/void_cast.rs | 68 +++++------- 15 files changed, 200 insertions(+), 190 deletions(-) diff --git a/tests/unit/out/unsafe/addr_of_global.rs b/tests/unit/out/unsafe/addr_of_global.rs index 97bc3761..c824be23 100644 --- a/tests/unit/out/unsafe/addr_of_global.rs +++ b/tests/unit/out/unsafe/addr_of_global.rs @@ -16,15 +16,19 @@ pub struct Inner { pub struct Outer { pub p: *mut Inner, } -pub static mut alpha: Inner = Inner { value: 1 }; -pub static mut beta: Inner = Inner { value: 2 }; -pub static mut shared: Inner = Inner { value: 42 }; -pub static mut items: [*mut Inner; 2] = [ - (&raw mut alpha as *mut Inner), - (&raw mut beta as *mut Inner), -]; -pub static mut obj: Outer = Outer { - p: (&raw mut shared as *mut Inner), +pub static mut alpha: Inner = unsafe { Inner { value: 1 } }; +pub static mut beta: Inner = unsafe { Inner { value: 2 } }; +pub static mut shared: Inner = unsafe { Inner { value: 42 } }; +pub static mut items: [*mut Inner; 2] = unsafe { + [ + (&raw mut alpha as *mut Inner), + (&raw mut beta as *mut Inner), + ] +}; +pub static mut obj: Outer = unsafe { + Outer { + p: (&raw mut shared as *mut Inner), + } }; pub fn main() { unsafe { @@ -35,10 +39,12 @@ unsafe fn main_0() -> i32 { assert!((((*items[(0) as usize]).value) == (1))); assert!((((*items[(1) as usize]).value) == (2))); assert!((((*obj.p).value) == (42))); - static mut cache: [*mut Inner; 2] = [ - (&raw mut alpha as *mut Inner), - (&raw mut beta as *mut Inner), - ];; + static mut cache: [*mut Inner; 2] = unsafe { + [ + (&raw mut alpha as *mut Inner), + (&raw mut beta as *mut Inner), + ] + };; assert!((((*cache[(0) as usize]).value) == (1))); assert!((((*cache[(1) as usize]).value) == (2))); return 0; diff --git a/tests/unit/out/unsafe/bool_condition_logical.rs b/tests/unit/out/unsafe/bool_condition_logical.rs index bc1fdcd7..8f0a8cfe 100644 --- a/tests/unit/out/unsafe/bool_condition_logical.rs +++ b/tests/unit/out/unsafe/bool_condition_logical.rs @@ -23,7 +23,7 @@ impl From for Code { } } } -pub static mut side_effect: i32 = 0; +pub static mut side_effect: i32 = unsafe { 0 }; pub unsafe fn observe_0(mut v: i32) -> i32 { side_effect.prefix_inc(); return v; diff --git a/tests/unit/out/unsafe/bool_condition_logical_c.rs b/tests/unit/out/unsafe/bool_condition_logical_c.rs index 14c77990..7e72704c 100644 --- a/tests/unit/out/unsafe/bool_condition_logical_c.rs +++ b/tests/unit/out/unsafe/bool_condition_logical_c.rs @@ -23,7 +23,7 @@ impl From for Code { } } } -pub static mut side_effect: i32 = 0; +pub static mut side_effect: i32 = unsafe { 0 }; pub unsafe fn observe_0(mut v: i32) -> i32 { side_effect.prefix_inc(); return v; diff --git a/tests/unit/out/unsafe/default_in_statics.rs b/tests/unit/out/unsafe/default_in_statics.rs index 4f21ffe7..e6916de2 100644 --- a/tests/unit/out/unsafe/default_in_statics.rs +++ b/tests/unit/out/unsafe/default_in_statics.rs @@ -58,49 +58,9 @@ impl Default for Foo { } } } -pub static mut static_fn: Option i32> = None; -pub static mut static_outer: Outer = Outer { - p1: std::ptr::null_mut(), - p2: std::ptr::null(), - arr: [std::ptr::null_mut(); 3], - cp: std::ptr::null(), - pp: std::ptr::null_mut(), - inner: Inner { - v: 0_i32, - name: std::ptr::null(), - }, - x: 0_i32, - fn_: None, -}; -pub static mut static_inner_array: [Inner; 2] = [Inner { - v: 0_i32, - name: std::ptr::null(), -}; 2]; -pub static mut static_foo: Foo = Foo { - s1: b"hello\0".as_ptr(), - s2: std::ptr::null(), - fn1: None, - fn2: None, - n: 42, -}; -pub static mut static_foo_array: [Foo; 2] = [ - Foo { - s1: b"first\0".as_ptr(), - s2: std::ptr::null(), - fn1: None, - fn2: None, - n: 1, - }, - Foo { - s1: b"second\0".as_ptr(), - s2: std::ptr::null(), - fn1: None, - fn2: None, - n: 2, - }, -]; -pub unsafe fn check_local_static_0() { - static mut local_outer: Outer = Outer { +pub static mut static_fn: Option i32> = unsafe { None }; +pub static mut static_outer: Outer = unsafe { + Outer { p1: std::ptr::null_mut(), p2: std::ptr::null(), arr: [std::ptr::null_mut(); 3], @@ -112,9 +72,59 @@ pub unsafe fn check_local_static_0() { }, x: 0_i32, fn_: None, + } +}; +pub static mut static_inner_array: [Inner; 2] = unsafe { + [Inner { + v: 0_i32, + name: std::ptr::null(), + }; 2] +}; +pub static mut static_foo: Foo = unsafe { + Foo { + s1: b"hello\0".as_ptr(), + s2: std::ptr::null(), + fn1: None, + fn2: None, + n: 42, + } +}; +pub static mut static_foo_array: [Foo; 2] = unsafe { + [ + Foo { + s1: b"first\0".as_ptr(), + s2: std::ptr::null(), + fn1: None, + fn2: None, + n: 1, + }, + Foo { + s1: b"second\0".as_ptr(), + s2: std::ptr::null(), + fn1: None, + fn2: None, + n: 2, + }, + ] +}; +pub unsafe fn check_local_static_0() { + static mut local_outer: Outer = unsafe { + Outer { + p1: std::ptr::null_mut(), + p2: std::ptr::null(), + arr: [std::ptr::null_mut(); 3], + cp: std::ptr::null(), + pp: std::ptr::null_mut(), + inner: Inner { + v: 0_i32, + name: std::ptr::null(), + }, + x: 0_i32, + fn_: None, + } };; - static mut local_fn: Option i32> = None;; - static mut local_p: *mut i32 = std::ptr::null_mut();; + static mut local_fn: Option i32> = unsafe { None };; + static mut local_p: *mut i32 = unsafe { std::ptr::null_mut() };; assert!((local_outer.p1).is_null()); assert!((local_outer.fn_).is_none()); assert!((local_fn).is_none()); diff --git a/tests/unit/out/unsafe/enum_int_interop.rs b/tests/unit/out/unsafe/enum_int_interop.rs index 74695cda..756eef9c 100644 --- a/tests/unit/out/unsafe/enum_int_interop.rs +++ b/tests/unit/out/unsafe/enum_int_interop.rs @@ -66,26 +66,28 @@ pub struct Entry { pub color: Color, pub opt: Option, } -pub static mut global_color: Color = Color::GREEN; -pub static mut global_opt: Option = Option::OPT_B; -pub static mut global_tag: Tag = Tag::TAG_TWO; -pub static mut entries: [Entry; 3] = [ - Entry { - name: b"first\0".as_ptr(), - color: Color::RED, - opt: Option::OPT_NONE, - }, - Entry { - name: b"second\0".as_ptr(), - color: Color::GREEN, - opt: Option::OPT_A, - }, - Entry { - name: b"third\0".as_ptr(), - color: Color::BLUE, - opt: Option::OPT_C, - }, -]; +pub static mut global_color: Color = unsafe { Color::GREEN }; +pub static mut global_opt: Option = unsafe { Option::OPT_B }; +pub static mut global_tag: Tag = unsafe { Tag::TAG_TWO }; +pub static mut entries: [Entry; 3] = unsafe { + [ + Entry { + name: b"first\0".as_ptr(), + color: Color::RED, + opt: Option::OPT_NONE, + }, + Entry { + name: b"second\0".as_ptr(), + color: Color::GREEN, + opt: Option::OPT_A, + }, + Entry { + name: b"third\0".as_ptr(), + color: Color::BLUE, + opt: Option::OPT_C, + }, + ] +}; pub unsafe fn as_int_0(mut c: Color) -> i32 { return (c as i32); } diff --git a/tests/unit/out/unsafe/enum_int_interop_c.rs b/tests/unit/out/unsafe/enum_int_interop_c.rs index 11c992e0..736a1341 100644 --- a/tests/unit/out/unsafe/enum_int_interop_c.rs +++ b/tests/unit/out/unsafe/enum_int_interop_c.rs @@ -66,26 +66,28 @@ pub struct Entry { pub color: Color, pub opt: Option, } -pub static mut global_color: Color = Color::GREEN; -pub static mut global_opt: Option = Option::OPT_B; -pub static mut global_tag: Tag = Tag::TAG_TWO; -pub static mut entries: [Entry; 3] = [ - Entry { - name: b"first\0".as_ptr().cast_mut().cast_const(), - color: Color::RED, - opt: Option::OPT_NONE, - }, - Entry { - name: b"second\0".as_ptr().cast_mut().cast_const(), - color: Color::GREEN, - opt: Option::OPT_A, - }, - Entry { - name: b"third\0".as_ptr().cast_mut().cast_const(), - color: Color::BLUE, - opt: Option::OPT_C, - }, -]; +pub static mut global_color: Color = unsafe { Color::GREEN }; +pub static mut global_opt: Option = unsafe { Option::OPT_B }; +pub static mut global_tag: Tag = unsafe { Tag::TAG_TWO }; +pub static mut entries: [Entry; 3] = unsafe { + [ + Entry { + name: b"first\0".as_ptr().cast_mut().cast_const(), + color: Color::RED, + opt: Option::OPT_NONE, + }, + Entry { + name: b"second\0".as_ptr().cast_mut().cast_const(), + color: Color::GREEN, + opt: Option::OPT_A, + }, + Entry { + name: b"third\0".as_ptr().cast_mut().cast_const(), + color: Color::BLUE, + opt: Option::OPT_C, + }, + ] +}; pub unsafe fn as_int_0(mut c: Color) -> i32 { return (c as i32); } diff --git a/tests/unit/out/unsafe/fn_ptr_global.rs b/tests/unit/out/unsafe/fn_ptr_global.rs index 109438d5..dc4ffb56 100644 --- a/tests/unit/out/unsafe/fn_ptr_global.rs +++ b/tests/unit/out/unsafe/fn_ptr_global.rs @@ -12,7 +12,7 @@ pub unsafe fn double_it_0(mut x: i32) -> i32 { pub unsafe fn triple_it_1(mut x: i32) -> i32 { return ((x) * (3)); } -pub static mut g_op: Option i32> = None; +pub static mut g_op: Option i32> = unsafe { None }; pub unsafe fn set_op_2(mut fn_: Option i32>) { g_op = fn_; } diff --git a/tests/unit/out/unsafe/fn_ptr_vtable.rs b/tests/unit/out/unsafe/fn_ptr_vtable.rs index e8db9f2d..2c2a2eb9 100644 --- a/tests/unit/out/unsafe/fn_ptr_vtable.rs +++ b/tests/unit/out/unsafe/fn_ptr_vtable.rs @@ -22,7 +22,7 @@ impl Default for Vtable { } } } -pub static mut storage: i32 = 0_i32; +pub static mut storage: i32 = unsafe { 0_i32 }; pub unsafe fn int_create_0(mut val: i32) -> *mut ::libc::c_void { storage = val; return ((&raw mut storage as *mut i32) as *mut i32 as *mut ::libc::c_void); diff --git a/tests/unit/out/unsafe/global_pointers.rs b/tests/unit/out/unsafe/global_pointers.rs index e4d2d303..7ee0241d 100644 --- a/tests/unit/out/unsafe/global_pointers.rs +++ b/tests/unit/out/unsafe/global_pointers.rs @@ -12,25 +12,31 @@ pub struct Entry { pub name: *const u8, pub p: *mut i32, } -pub static mut single_entry: Entry = Entry { - name: b"alone\0".as_ptr(), - p: std::ptr::null_mut(), -}; -pub static mut entries: [Entry; 2] = [ - Entry { - name: b"first\0".as_ptr(), - p: std::ptr::null_mut(), - }, +pub static mut single_entry: Entry = unsafe { Entry { - name: b"second\0".as_ptr(), + name: b"alone\0".as_ptr(), p: std::ptr::null_mut(), - }, -]; -pub static mut arr_of_pointers: [*mut u8; 3] = [ - std::ptr::null_mut(), - std::ptr::null_mut(), - std::ptr::null_mut(), -]; + } +}; +pub static mut entries: [Entry; 2] = unsafe { + [ + Entry { + name: b"first\0".as_ptr(), + p: std::ptr::null_mut(), + }, + Entry { + name: b"second\0".as_ptr(), + p: std::ptr::null_mut(), + }, + ] +}; +pub static mut arr_of_pointers: [*mut u8; 3] = unsafe { + [ + std::ptr::null_mut(), + std::ptr::null_mut(), + std::ptr::null_mut(), + ] +}; pub fn main() { unsafe { std::process::exit(main_0() as i32); diff --git a/tests/unit/out/unsafe/global_without_initializer.rs b/tests/unit/out/unsafe/global_without_initializer.rs index 57c51700..9dfb12d6 100644 --- a/tests/unit/out/unsafe/global_without_initializer.rs +++ b/tests/unit/out/unsafe/global_without_initializer.rs @@ -11,9 +11,9 @@ use std::rc::Rc; pub struct S { pub a: i32, } -pub static mut s: *mut S = std::ptr::null_mut(); -pub static mut file: *mut ::std::fs::File = std::ptr::null_mut(); -pub static mut size: u64 = 0_u64; +pub static mut s: *mut S = unsafe { std::ptr::null_mut() }; +pub static mut file: *mut ::std::fs::File = unsafe { std::ptr::null_mut() }; +pub static mut size: u64 = unsafe { 0_u64 }; pub fn main() { unsafe { std::process::exit(main_0() as i32); diff --git a/tests/unit/out/unsafe/null_in_statics.rs b/tests/unit/out/unsafe/null_in_statics.rs index 7b6869f2..3e930445 100644 --- a/tests/unit/out/unsafe/null_in_statics.rs +++ b/tests/unit/out/unsafe/null_in_statics.rs @@ -6,14 +6,14 @@ use std::collections::BTreeMap; use std::io::{Read, Seek, Write}; use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; use std::rc::Rc; -pub static mut p_mut: *mut i32 = std::ptr::null_mut(); -pub static mut p_const: *const i32 = std::ptr::null(); -pub static mut cp: *const u8 = std::ptr::null(); -pub static mut arr_of_ptr: [*mut i32; 4] = [std::ptr::null_mut(); 4]; -pub static mut pp: *mut *mut i32 = std::ptr::null_mut(); -pub static mut const_arr_of_ptr: [*const i32; 3] = [std::ptr::null(); 3]; -pub static mut cp_explicit_null: *const u8 = std::ptr::null(); -pub static mut p_zero: *mut i32 = std::ptr::null_mut(); +pub static mut p_mut: *mut i32 = unsafe { std::ptr::null_mut() }; +pub static mut p_const: *const i32 = unsafe { std::ptr::null() }; +pub static mut cp: *const u8 = unsafe { std::ptr::null() }; +pub static mut arr_of_ptr: [*mut i32; 4] = unsafe { [std::ptr::null_mut(); 4] }; +pub static mut pp: *mut *mut i32 = unsafe { std::ptr::null_mut() }; +pub static mut const_arr_of_ptr: [*const i32; 3] = unsafe { [std::ptr::null(); 3] }; +pub static mut cp_explicit_null: *const u8 = unsafe { std::ptr::null() }; +pub static mut p_zero: *mut i32 = unsafe { std::ptr::null_mut() }; pub fn main() { unsafe { std::process::exit(main_0() as i32); diff --git a/tests/unit/out/unsafe/static_local.rs b/tests/unit/out/unsafe/static_local.rs index 022ee582..49183399 100644 --- a/tests/unit/out/unsafe/static_local.rs +++ b/tests/unit/out/unsafe/static_local.rs @@ -7,11 +7,11 @@ use std::io::{Read, Seek, Write}; use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; use std::rc::Rc; pub unsafe fn foo_0() -> i32 { - static mut static_i: i32 = 0_i32;; - static mut static_f: f32 = 0.0_f32;; - static mut static_b: bool = false;; - static mut kX1: i32 = 1;; - static mut kX2: i32 = 2;; + static mut static_i: i32 = unsafe { 0_i32 };; + static mut static_f: f32 = unsafe { 0.0_f32 };; + static mut static_b: bool = unsafe { false };; + static mut kX1: i32 = unsafe { 1 };; + static mut kX2: i32 = unsafe { 2 };; kX1 += 1; return (((kX1) + (kX2)) + (static_i)); } diff --git a/tests/unit/out/unsafe/string_escape.rs b/tests/unit/out/unsafe/string_escape.rs index d04d2c0b..5b4785db 100644 --- a/tests/unit/out/unsafe/string_escape.rs +++ b/tests/unit/out/unsafe/string_escape.rs @@ -14,12 +14,14 @@ pub fn main() { unsafe fn main_0() -> i32 { let mut special: *const u8 = b"\x07\x08\t\n\x0b\x0c\r !\"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~\0".as_ptr(); - static mut expected: [u8; 40] = [ - 7_u8, 8_u8, 9_u8, 10_u8, 11_u8, 12_u8, 13_u8, 32_u8, 33_u8, 34_u8, 35_u8, 36_u8, 37_u8, - 38_u8, 39_u8, 40_u8, 41_u8, 42_u8, 43_u8, 44_u8, 45_u8, 46_u8, 47_u8, 58_u8, 59_u8, 60_u8, - 61_u8, 62_u8, 63_u8, 64_u8, 91_u8, 92_u8, 93_u8, 94_u8, 95_u8, 96_u8, 123_u8, 124_u8, - 125_u8, 126_u8, - ];; + static mut expected: [u8; 40] = unsafe { + [ + 7_u8, 8_u8, 9_u8, 10_u8, 11_u8, 12_u8, 13_u8, 32_u8, 33_u8, 34_u8, 35_u8, 36_u8, 37_u8, + 38_u8, 39_u8, 40_u8, 41_u8, 42_u8, 43_u8, 44_u8, 45_u8, 46_u8, 47_u8, 58_u8, 59_u8, + 60_u8, 61_u8, 62_u8, 63_u8, 64_u8, 91_u8, 92_u8, 93_u8, 94_u8, 95_u8, 96_u8, 123_u8, + 124_u8, 125_u8, 126_u8, + ] + };; let mut i: i32 = 0; 'loop_: while ((i) < (((::std::mem::size_of::<[u8; 40]>() as u64 as u64) diff --git a/tests/unit/out/unsafe/union_tagged_struct_arms.rs b/tests/unit/out/unsafe/union_tagged_struct_arms.rs index 74d70dd9..681020f1 100644 --- a/tests/unit/out/unsafe/union_tagged_struct_arms.rs +++ b/tests/unit/out/unsafe/union_tagged_struct_arms.rs @@ -72,11 +72,13 @@ pub fn main() { } } unsafe fn main_0() -> i32 { - static mut items: [*mut u8; 3] = [ - b"a\0".as_ptr().cast_mut(), - b"b\0".as_ptr().cast_mut(), - b"c\0".as_ptr().cast_mut(), - ];; + static mut items: [*mut u8; 3] = unsafe { + [ + b"a\0".as_ptr().cast_mut(), + b"b\0".as_ptr().cast_mut(), + b"c\0".as_ptr().cast_mut(), + ] + };; let mut p_list: Branch = ::default(); p_list.choice = Choice::C_LIST; p_list.index = 0; diff --git a/tests/unit/out/unsafe/void_cast.rs b/tests/unit/out/unsafe/void_cast.rs index d3a68f95..cd887e18 100644 --- a/tests/unit/out/unsafe/void_cast.rs +++ b/tests/unit/out/unsafe/void_cast.rs @@ -7,21 +7,10 @@ use std::io::{Read, Seek, Write}; use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; use std::rc::Rc; pub unsafe fn unused_param_0(mut x: i32) { - &(x); + x; } -#[repr(C)] -#[derive(Clone, Default)] -pub struct NonTrivial { - pub data: Vec, -} -pub unsafe fn unused_ref_param_1(x: *const NonTrivial) { - &(*x); -} -pub unsafe fn unused_ptr_param_2(mut p: *const NonTrivial) { - &(*p); -} -pub static mut side_effect_counter: i32 = 0; -pub unsafe fn bump_and_return_3() -> i32 { +pub static mut side_effect_counter: i32 = unsafe { 0 }; +pub unsafe fn bump_and_return_1() -> i32 { side_effect_counter.prefix_inc(); return side_effect_counter; } @@ -41,68 +30,59 @@ unsafe fn main_0() -> i32 { unused_param_0(_x) }); let mut y: i32 = 5; - &(y); + y; let mut z: i32 = { - &(y); + y; 7 }; assert!(((z) == (7))); let mut counter: i32 = 0; let mut w: i32 = { - &(counter); + counter; counter = 3; counter }; assert!(((w) == (3))); assert!(((counter) == (3))); - &(unsafe { bump_and_return_3() }); + (unsafe { bump_and_return_1() }); assert!(((side_effect_counter) == (1))); let mut v: i32 = { - &(unsafe { bump_and_return_3() }); + (unsafe { bump_and_return_1() }); 99 }; assert!(((side_effect_counter) == (2))); assert!(((v) == (99))); - &(0); - &(0); - &(y); - (&(0)); - (&(y)); + 0; + (0); + (y); + (0); + (y); let mut err: i32 = 0; - (&(err = 42)); + (err = 42); assert!(((err) == (42))); let mut chosen: i32 = { - &(err = 7); + (err = 7); 123 }; assert!(((err) == (7))); assert!(((chosen) == (123))); - &(bump_and_return_3); + bump_and_return_1; assert!(((side_effect_counter) == (2))); - &(Some(bump_and_return_3)); + (Some(bump_and_return_1)); assert!(((side_effect_counter) == (2))); - &(std::mem::transmute:: i32>, Option i32>>( - (Some(bump_and_return_3)), + (std::mem::transmute:: i32>, Option i32>>( + (Some(bump_and_return_1)), )); assert!(((side_effect_counter) == (2))); let mut storage: i32 = 11; let mut p: *mut i32 = (&mut storage as *mut i32); - &(*p); - &(p); + (*p); + (p); let mut arr: [i32; 3] = [1, 2, 3]; - &(arr[(1) as usize]); + (arr[(1) as usize]); let mut h: Holder = Holder { field: 17 }; - &(h.field); + (h.field); let mut hp: *mut Holder = (&mut h as *mut Holder); - &((*hp).field); - let mut nt: NonTrivial = ::default(); - (unsafe { - let _x: *const NonTrivial = &nt as *const NonTrivial; - unused_ref_param_1(_x) - }); - (unsafe { - let _p: *const NonTrivial = (&mut nt as *mut NonTrivial).cast_const(); - unused_ptr_param_2(_p) - }); + ((*hp).field); return 0; } From 01516c16a82c9383df515bb398cf250b2dfe951f Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Sat, 16 May 2026 18:04:50 +0100 Subject: [PATCH 3/5] Fix build --- cpp2rust/converter/converter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index c880a9cb..92f7d2ec 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -437,7 +437,7 @@ bool Converter::ConvertLambdaVarDecl(clang::VarDecl *decl) { return false; } -void ConvertVarDeclInitializer(clang::VarDecl *decl) { +void Converter::ConvertVarDeclInitializer(clang::VarDecl *decl) { if (decl->hasInit()) { ConvertVarInit(decl->getType(), decl->getInit()); } else if (!clang::isa(decl)) { From 08ea88fbba45daca36de61d4efc5df2049fd48ce Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Sat, 16 May 2026 19:14:43 +0100 Subject: [PATCH 4/5] Add lobal-initialization-using-global test --- .../global-initialization-using-global.cpp | 10 ++++++++ .../global-initialization-using-global.rs | 23 +++++++++++++++++++ .../global-initialization-using-global.rs | 20 ++++++++++++++++ 3 files changed, 53 insertions(+) create mode 100644 tests/unit/global-initialization-using-global.cpp create mode 100644 tests/unit/out/refcount/global-initialization-using-global.rs create mode 100644 tests/unit/out/unsafe/global-initialization-using-global.rs diff --git a/tests/unit/global-initialization-using-global.cpp b/tests/unit/global-initialization-using-global.cpp new file mode 100644 index 00000000..240e28e3 --- /dev/null +++ b/tests/unit/global-initialization-using-global.cpp @@ -0,0 +1,10 @@ +#include + +int first; +int second = first + 1; + +int main() { + assert(first == 0); + assert(second == first + 1); + return 0; +} diff --git a/tests/unit/out/refcount/global-initialization-using-global.rs b/tests/unit/out/refcount/global-initialization-using-global.rs new file mode 100644 index 00000000..1ecbc94b --- /dev/null +++ b/tests/unit/out/refcount/global-initialization-using-global.rs @@ -0,0 +1,23 @@ +extern crate libcc2rs; +use libcc2rs::*; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::io::prelude::*; +use std::io::{Read, Seek, Write}; +use std::os::fd::AsFd; +use std::rc::{Rc, Weak}; +thread_local!( + pub static first: Value = >::default(); +); +thread_local!( + pub static second: Value = + Rc::new(RefCell::new(((*first.with(Value::clone).borrow()) + 1))); +); +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + assert!(((*first.with(Value::clone).borrow()) == 0)); + assert!(((*second.with(Value::clone).borrow()) == ((*first.with(Value::clone).borrow()) + 1))); + return 0; +} diff --git a/tests/unit/out/unsafe/global-initialization-using-global.rs b/tests/unit/out/unsafe/global-initialization-using-global.rs new file mode 100644 index 00000000..f0cb6be0 --- /dev/null +++ b/tests/unit/out/unsafe/global-initialization-using-global.rs @@ -0,0 +1,20 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::{Read, Seek, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +pub static mut first: i32 = unsafe { 0_i32 }; +pub static mut second: i32 = unsafe { ((first) + (1)) }; +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + assert!(((first) == (0))); + assert!(((second) == ((first) + (1)))); + return 0; +} From b17178fcb6703ac9550eefbda8e68955ee74face Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Sun, 17 May 2026 19:39:46 +0100 Subject: [PATCH 5/5] Update tests --- tests/unit/out/unsafe/static_var_in_class.rs | 4 +- tests/unit/out/unsafe/void_cast.rs | 66 +++++++++++++------- 2 files changed, 45 insertions(+), 25 deletions(-) diff --git a/tests/unit/out/unsafe/static_var_in_class.rs b/tests/unit/out/unsafe/static_var_in_class.rs index 231fc87a..1d8796ba 100644 --- a/tests/unit/out/unsafe/static_var_in_class.rs +++ b/tests/unit/out/unsafe/static_var_in_class.rs @@ -6,7 +6,7 @@ use std::collections::BTreeMap; use std::io::{Read, Seek, Write}; use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; use std::rc::Rc; -static mut C_inner_const: i32 = 1; +static mut C_inner_const: i32 = unsafe { 1 }; #[repr(C)] #[derive(Copy, Clone, Default)] pub struct C {} @@ -15,7 +15,7 @@ impl C { return C_inner_const; } } -pub static mut S_inner_const: i32 = 2; +pub static mut S_inner_const: i32 = unsafe { 2 }; #[repr(C)] #[derive(Copy, Clone, Default)] pub struct S {} diff --git a/tests/unit/out/unsafe/void_cast.rs b/tests/unit/out/unsafe/void_cast.rs index cd887e18..b5087d6e 100644 --- a/tests/unit/out/unsafe/void_cast.rs +++ b/tests/unit/out/unsafe/void_cast.rs @@ -7,10 +7,21 @@ use std::io::{Read, Seek, Write}; use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; use std::rc::Rc; pub unsafe fn unused_param_0(mut x: i32) { - x; + &(x); +} +#[repr(C)] +#[derive(Clone, Default)] +pub struct NonTrivial { + pub data: Vec, +} +pub unsafe fn unused_ref_param_1(x: *const NonTrivial) { + &(*x); +} +pub unsafe fn unused_ptr_param_2(mut p: *const NonTrivial) { + &(*p); } pub static mut side_effect_counter: i32 = unsafe { 0 }; -pub unsafe fn bump_and_return_1() -> i32 { +pub unsafe fn bump_and_return_3() -> i32 { side_effect_counter.prefix_inc(); return side_effect_counter; } @@ -30,59 +41,68 @@ unsafe fn main_0() -> i32 { unused_param_0(_x) }); let mut y: i32 = 5; - y; + &(y); let mut z: i32 = { - y; + &(y); 7 }; assert!(((z) == (7))); let mut counter: i32 = 0; let mut w: i32 = { - counter; + &(counter); counter = 3; counter }; assert!(((w) == (3))); assert!(((counter) == (3))); - (unsafe { bump_and_return_1() }); + &(unsafe { bump_and_return_3() }); assert!(((side_effect_counter) == (1))); let mut v: i32 = { - (unsafe { bump_and_return_1() }); + &(unsafe { bump_and_return_3() }); 99 }; assert!(((side_effect_counter) == (2))); assert!(((v) == (99))); - 0; - (0); - (y); - (0); - (y); + &(0); + &(0); + &(y); + (&(0)); + (&(y)); let mut err: i32 = 0; - (err = 42); + (&(err = 42)); assert!(((err) == (42))); let mut chosen: i32 = { - (err = 7); + &(err = 7); 123 }; assert!(((err) == (7))); assert!(((chosen) == (123))); - bump_and_return_1; + &(bump_and_return_3); assert!(((side_effect_counter) == (2))); - (Some(bump_and_return_1)); + &(Some(bump_and_return_3)); assert!(((side_effect_counter) == (2))); - (std::mem::transmute:: i32>, Option i32>>( - (Some(bump_and_return_1)), + &(std::mem::transmute:: i32>, Option i32>>( + (Some(bump_and_return_3)), )); assert!(((side_effect_counter) == (2))); let mut storage: i32 = 11; let mut p: *mut i32 = (&mut storage as *mut i32); - (*p); - (p); + &(*p); + &(p); let mut arr: [i32; 3] = [1, 2, 3]; - (arr[(1) as usize]); + &(arr[(1) as usize]); let mut h: Holder = Holder { field: 17 }; - (h.field); + &(h.field); let mut hp: *mut Holder = (&mut h as *mut Holder); - ((*hp).field); + &((*hp).field); + let mut nt: NonTrivial = ::default(); + (unsafe { + let _x: *const NonTrivial = &nt as *const NonTrivial; + unused_ref_param_1(_x) + }); + (unsafe { + let _p: *const NonTrivial = (&mut nt as *mut NonTrivial).cast_const(); + unused_ptr_param_2(_p) + }); return 0; }