From d121c2526a7b0a7666f676f13d9580b4209ee134 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Thu, 8 Oct 2026 20:34:11 +0100 Subject: [PATCH 1/5] Translate self-referencing initializer --- cpp2rust/converter/converter.cpp | 20 +++++++++++++ cpp2rust/converter/converter_lib.cpp | 42 ++++++++++++++++++++++++++++ cpp2rust/converter/converter_lib.h | 5 ++++ 3 files changed, 67 insertions(+) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 7a40fb153..11e32e7ca 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -555,6 +555,22 @@ void Converter::ConvertVarDecl(clang::VarDecl *decl) { } HoistMaterializedTempBindings hoist_temps(*this); + if (decl->isLocalVarDecl() && !IsGlobalVar(decl) && + !decl->getType()->isReferenceType() && decl->hasInit() && + ReferencesVar(decl->getInit(), decl)) { + if (DefaultInitHasSideEffects(ctx_, decl->getType())) { + llvm::report_fatal_error("self-referential initializer of a variable " + "whose default initialization has side effects " + "is not supported"); + } + hoisted_decls_.insert(decl); + if (ConvertVarDeclSkipInit(decl)) { + StrCat(token::kAssign, ConvertVarDefaultInit(decl), token::kSemiColon); + } + EmitHoistedInArmAssignment(decl); + return; + } + if (!ConvertVarDeclSkipInit(decl)) { // Skip global variables declared extern return; @@ -591,6 +607,10 @@ bool Converter::VisitVarDecl(clang::VarDecl *decl) { } if (IsGlobalVar(decl)) { + if (decl->hasInit() && ReferencesVar(decl->getInit(), decl)) { + llvm::report_fatal_error( + "self-referential initializer of a static variable is not supported"); + } ConvertGlobalVarDecl(decl); } else { ConvertVarDecl(decl); diff --git a/cpp2rust/converter/converter_lib.cpp b/cpp2rust/converter/converter_lib.cpp index 97afa0a39..a4731e8b0 100644 --- a/cpp2rust/converter/converter_lib.cpp +++ b/cpp2rust/converter/converter_lib.cpp @@ -1579,6 +1579,48 @@ GetAllVars(const clang::Stmt *stmt) { return vars; } +bool ReferencesVar(const clang::Stmt *stmt, const clang::VarDecl *var) { + if (!stmt) { + return false; + } + if (auto *decl_ref = clang::dyn_cast(stmt)) { + return decl_ref->getDecl() == var; + } + if (clang::isa(stmt)) { + return false; + } + return std::ranges::any_of(stmt->children(), [var](const clang::Stmt *child) { + return ReferencesVar(child, var); + }); +} + +bool DefaultInitHasSideEffects(const clang::ASTContext &ctx, + clang::QualType type) { + auto *record = ctx.getBaseElementType(type)->getAsCXXRecordDecl(); + if (!record || record->hasTrivialDefaultConstructor()) { + return false; + } + if (!record->hasDefaultConstructor() || + record->hasUserProvidedDefaultConstructor()) { + return true; + } + for (const auto &base : record->bases()) { + if (DefaultInitHasSideEffects(ctx, base.getType())) { + return true; + } + } + for (auto *field : record->fields()) { + if (auto *init = field->getInClassInitializer()) { + if (init->HasSideEffects(ctx)) { + return true; + } + } else if (DefaultInitHasSideEffects(ctx, field->getType())) { + return true; + } + } + return false; +} + bool ReadsMemory(const clang::Stmt *stmt) { if (auto *cast = clang::dyn_cast(stmt); cast && cast->getCastKind() == clang::CK_LValueToRValue) { diff --git a/cpp2rust/converter/converter_lib.h b/cpp2rust/converter/converter_lib.h index afce5742b..d0b91b2f9 100644 --- a/cpp2rust/converter/converter_lib.h +++ b/cpp2rust/converter/converter_lib.h @@ -279,6 +279,11 @@ clang::Expr *GetCallee(clang::CallExpr *expr); std::unordered_set GetAllVars(const clang::Stmt *stmt); +bool ReferencesVar(const clang::Stmt *stmt, const clang::VarDecl *var); + +bool DefaultInitHasSideEffects(const clang::ASTContext &ctx, + clang::QualType type); + bool ReferencesThis(const clang::Stmt *stmt); // Whether evaluating `stmt` reads a value from memory, e.g., a pointer. From 6fa0a5de14a66e914eceb24f47a2ec721eb65572 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Thu, 8 Oct 2026 20:34:20 +0100 Subject: [PATCH 2/5] Update tests --- .../refcount/self_referencing_initializer.rs | 31 +++++++ .../unsafe/self_referencing_initializer.rs | 34 +++++++ tests/ub/self_referencing_initializer.cpp | 12 +++ .../refcount/self_referencing_initializer.rs | 93 +++++++++++++++++++ .../unsafe/self_referencing_initializer.rs | 85 +++++++++++++++++ tests/unit/self_referencing_initializer.cpp | 42 +++++++++ 6 files changed, 297 insertions(+) create mode 100644 tests/ub/out/refcount/self_referencing_initializer.rs create mode 100644 tests/ub/out/unsafe/self_referencing_initializer.rs create mode 100644 tests/ub/self_referencing_initializer.cpp create mode 100644 tests/unit/out/refcount/self_referencing_initializer.rs create mode 100644 tests/unit/out/unsafe/self_referencing_initializer.rs create mode 100644 tests/unit/self_referencing_initializer.cpp diff --git a/tests/ub/out/refcount/self_referencing_initializer.rs b/tests/ub/out/refcount/self_referencing_initializer.rs new file mode 100644 index 000000000..9de2a8b8d --- /dev/null +++ b/tests/ub/out/refcount/self_referencing_initializer.rs @@ -0,0 +1,31 @@ +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}; +#[derive(Clone, Record, ByteRepr, VaArg, FnPtrArg, Default)] +#[byte_size(8)] +pub struct pair { + #[offset(0)] + pub a: i32, + #[offset(4)] + pub b: i32, +} +pub fn main() { + __cpp2rust_init_globals(); + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let mut x: i32 = 0_i32; + x = (x + 1); + let mut p: pair = ::default(); + p = pair { a: 1, b: (p.a + 1) }; + let r: Ptr = (r).clone(); + let __tmp_0: Value = Rc::new(RefCell::new(((cr.read()) + 1))); + let cr: Ptr = __tmp_0.as_pointer(); + return ({ ({ (x + p.b) } + { (r.read()) }) } + { (cr.read()) }); +} +pub fn __cpp2rust_init_globals() {} diff --git a/tests/ub/out/unsafe/self_referencing_initializer.rs b/tests/ub/out/unsafe/self_referencing_initializer.rs new file mode 100644 index 000000000..9da48cec0 --- /dev/null +++ b/tests/ub/out/unsafe/self_referencing_initializer.rs @@ -0,0 +1,34 @@ +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; +#[repr(C)] +#[derive(Copy, Clone, VaArg, FnPtrArg, Default)] +pub struct pair { + pub a: i32, + pub b: i32, +} +pub fn main() { + unsafe { + __cpp2rust_init_globals(); + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut x: i32 = 0_i32; + x = ((x) + (1)); + let mut p: pair = ::default(); + p = pair { + a: 1, + b: ((p.a) + (1)), + }; + let r: *mut i32 = r; + let mut __tmp_0: i32 = ((*cr) + (1)); + let cr: *const i32 = &mut __tmp_0; + return ((((x) + (p.b)) + (*r)) + (*cr)); +} +pub unsafe fn __cpp2rust_init_globals() {} diff --git a/tests/ub/self_referencing_initializer.cpp b/tests/ub/self_referencing_initializer.cpp new file mode 100644 index 000000000..901f4f6c5 --- /dev/null +++ b/tests/ub/self_referencing_initializer.cpp @@ -0,0 +1,12 @@ +// nondet-result + +struct pair { + int a; + int b; +}; + +int main() { + int x = x + 1; + pair p = {1, p.a + 1}; + return x + p.b; +} diff --git a/tests/unit/out/refcount/self_referencing_initializer.rs b/tests/unit/out/refcount/self_referencing_initializer.rs new file mode 100644 index 000000000..479a28e50 --- /dev/null +++ b/tests/unit/out/refcount/self_referencing_initializer.rs @@ -0,0 +1,93 @@ +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}; +#[derive(Clone, Record, ByteRepr, VaArg, FnPtrArg, Default)] +#[byte_size(8)] +pub struct list_head { + #[offset(0)] + #[byte_size(8)] + pub next: Ptr, +} +#[derive(Clone, Record, ByteRepr, VaArg, FnPtrArg, Default)] +#[byte_size(16)] +pub struct node { + #[offset(0)] + pub value: i32, + #[offset(8)] + #[byte_size(8)] + pub value_ptr: Ptr, +} +#[derive(Clone, Record, ByteRepr, VaArg, FnPtrArg)] +#[byte_size(16)] +pub struct node_with_defaults { + #[offset(0)] + #[byte_size(8)] + pub next: Ptr, + #[offset(8)] + pub value: i32, +} +impl Default for node_with_defaults { + fn default() -> Self { + node_with_defaults { + next: Ptr::::null(), + value: 3, + } + } +} +pub fn main() { + __cpp2rust_init_globals(); + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let list: Value = >::default(); + *list.borrow_mut() = list_head { + next: (list.as_pointer()), + }; + assert!(({ { (*list.borrow()).next.clone() } } == { (list.as_pointer()) })); + let n: Value = >::default(); + *n.borrow_mut() = node { + value: 42, + value_ptr: (field_ptr!(n.as_pointer(), value)), + }; + assert!(({ { (*n.borrow()).value_ptr.clone() } } == { (field_ptr!(n.as_pointer(), value)) })); + { (*n.borrow()).value_ptr.clone() }.write(7); + assert!(({ (*n.borrow()).value } == 7)); + let arr: Value> = Rc::new(RefCell::new( + (0..2).map(|_| AnyPtr::default()).collect::>(), + )); + *arr.borrow_mut() = Box::new([ + (((arr.as_pointer() as Ptr).offset(1)) as Ptr).to_any(), + (((arr.as_pointer() as Ptr).offset(0)) as Ptr).to_any(), + ]); + assert!( + ((*arr.borrow())[(0) as usize] + == (((arr.as_pointer() as Ptr).offset(1)) as Ptr).to_any()) + ); + assert!( + ((*arr.borrow())[(1) as usize] + == (((arr.as_pointer() as Ptr).offset(0)) as Ptr).to_any()) + ); + let p: Value = Rc::new(RefCell::new(AnyPtr::default())); + *p.borrow_mut() = ((p.as_pointer()) as Ptr).to_any(); + assert!(((*p.borrow()) == ((p.as_pointer()) as Ptr).to_any())); + let d: Value = >::default(); + *d.borrow_mut() = node_with_defaults { + next: (d.as_pointer()), + value: 3, + }; + assert!(({ { (*d.borrow()).next.clone() } } == { (d.as_pointer()) })); + assert!(({ (*d.borrow()).value } == 3)); + let mut heap: Ptr = + libcc2rs::malloc_refcount(8usize).reinterpret_cast::(); + assert!(!((heap).is_null())); + field!(heap, next).write({ (heap).clone() }); + assert!(({ heap.with(|__s| __s.next.clone()) } == { (heap).clone() })); + libcc2rs::free_refcount((heap).to_any()); + return 0; +} +pub fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/unsafe/self_referencing_initializer.rs b/tests/unit/out/unsafe/self_referencing_initializer.rs new file mode 100644 index 000000000..a6fd6b145 --- /dev/null +++ b/tests/unit/out/unsafe/self_referencing_initializer.rs @@ -0,0 +1,85 @@ +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; +#[repr(C)] +#[derive(Copy, Clone, VaArg, FnPtrArg, Default)] +pub struct list_head { + pub next: *mut list_head, +} +#[repr(C)] +#[derive(Copy, Clone, VaArg, FnPtrArg, Default)] +pub struct node { + pub value: i32, + pub value_ptr: *mut i32, +} +#[repr(C)] +#[derive(Copy, Clone, VaArg, FnPtrArg)] +pub struct node_with_defaults { + pub next: *mut node_with_defaults, + pub value: i32, +} +impl Default for node_with_defaults { + fn default() -> Self { + node_with_defaults { + next: std::ptr::null_mut(), + value: 3, + } + } +} +pub fn main() { + unsafe { + __cpp2rust_init_globals(); + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut list: list_head = ::default(); + list = list_head { + next: (&mut list as *mut list_head), + }; + assert!(((list.next) == (&mut list as *mut list_head))); + let mut n: node = ::default(); + n = node { + value: 42, + value_ptr: (&mut n.value as *mut i32), + }; + assert!(((n.value_ptr) == (&mut n.value as *mut i32))); + (*n.value_ptr) = 7; + assert!(((n.value) == (7))); + let mut arr: [*mut ::libc::c_void; 2] = [std::ptr::null_mut(); 2]; + arr = [ + ((&mut arr[(1) as usize] as *mut *mut ::libc::c_void) as *mut ::libc::c_void), + ((&mut arr[(0) as usize] as *mut *mut ::libc::c_void) as *mut ::libc::c_void), + ]; + assert!( + ((arr[(0) as usize]) + == ((&mut arr[(1) as usize] as *mut *mut ::libc::c_void) as *mut ::libc::c_void)) + ); + assert!( + ((arr[(1) as usize]) + == ((&mut arr[(0) as usize] as *mut *mut ::libc::c_void) as *mut ::libc::c_void)) + ); + let mut p: *mut ::libc::c_void = std::ptr::null_mut(); + p = ((&mut p as *mut *mut ::libc::c_void) as *mut ::libc::c_void); + assert!(((p) == ((&mut p as *mut *mut ::libc::c_void) as *mut ::libc::c_void))); + let mut d: node_with_defaults = ::default(); + d = node_with_defaults { + next: (&mut d as *mut node_with_defaults), + value: 3, + }; + assert!(((d.next) == (&mut d as *mut node_with_defaults))); + assert!(((d.value) == (3))); + let mut heap: *mut list_head = + (libcc2rs::malloc_unsafe(::std::mem::size_of::()) as *mut list_head); + assert!(!((heap).is_null())); + (*heap).next = heap; + assert!((((*heap).next) == (heap))); + libcc2rs::free_unsafe((heap as *mut ::libc::c_void)); + return 0; +} +pub unsafe fn __cpp2rust_init_globals() {} diff --git a/tests/unit/self_referencing_initializer.cpp b/tests/unit/self_referencing_initializer.cpp new file mode 100644 index 000000000..482b62651 --- /dev/null +++ b/tests/unit/self_referencing_initializer.cpp @@ -0,0 +1,42 @@ +#include +#include + +struct list_head { + list_head *next; +}; + +struct node { + int value; + int *value_ptr; +}; + +struct node_with_defaults { + node_with_defaults *next = nullptr; + int value = 3; +}; + +int main() { + list_head list = {&list}; + assert(list.next == &list); + + node n = {42, &n.value}; + assert(n.value_ptr == &n.value); + *n.value_ptr = 7; + assert(n.value == 7); + + list_head arr[2] = {{&arr[1]}, {&arr[0]}}; + assert(arr[0].next == &arr[1]); + assert(arr[1].next == &arr[0]); + + node_with_defaults d{&d}; + assert(d.next == &d); + assert(d.value == 3); + + list_head *heap = static_cast(malloc(sizeof(*heap))); + assert(heap != nullptr); + heap->next = heap; + assert(heap->next == heap); + free(heap); + + return 0; +} From b4c1d941389b7ffc15cf1e4a4fe6663de0f1af53 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Thu, 8 Oct 2026 20:34:53 +0100 Subject: [PATCH 3/5] Assert on self-referencing reference variable --- cpp2rust/converter/converter.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 11e32e7ca..68802115f 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -555,9 +555,12 @@ void Converter::ConvertVarDecl(clang::VarDecl *decl) { } HoistMaterializedTempBindings hoist_temps(*this); - if (decl->isLocalVarDecl() && !IsGlobalVar(decl) && - !decl->getType()->isReferenceType() && decl->hasInit() && + if (decl->isLocalVarDecl() && !IsGlobalVar(decl) && decl->hasInit() && ReferencesVar(decl->getInit(), decl)) { + if (decl->getType()->isReferenceType()) { + llvm::report_fatal_error( + "self-referential initializer of a reference is not supported"); + } if (DefaultInitHasSideEffects(ctx_, decl->getType())) { llvm::report_fatal_error("self-referential initializer of a variable " "whose default initialization has side effects " From 2e920ee7d7c0c3e486ee0c00cae031245fd77299 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Thu, 8 Oct 2026 20:35:10 +0100 Subject: [PATCH 4/5] Update tests --- .../refcount/self_referencing_initializer.rs | 5 +-- .../unsafe/self_referencing_initializer.rs | 5 +-- .../refcount/self_referencing_initializer.rs | 35 ++++++++++--------- .../unsafe/self_referencing_initializer.rs | 31 ++++++---------- tests/unit/self_referencing_initializer.cpp | 9 ++--- 5 files changed, 34 insertions(+), 51 deletions(-) diff --git a/tests/ub/out/refcount/self_referencing_initializer.rs b/tests/ub/out/refcount/self_referencing_initializer.rs index 9de2a8b8d..b374e835e 100644 --- a/tests/ub/out/refcount/self_referencing_initializer.rs +++ b/tests/ub/out/refcount/self_referencing_initializer.rs @@ -23,9 +23,6 @@ fn main_0() -> i32 { x = (x + 1); let mut p: pair = ::default(); p = pair { a: 1, b: (p.a + 1) }; - let r: Ptr = (r).clone(); - let __tmp_0: Value = Rc::new(RefCell::new(((cr.read()) + 1))); - let cr: Ptr = __tmp_0.as_pointer(); - return ({ ({ (x + p.b) } + { (r.read()) }) } + { (cr.read()) }); + return (x + p.b); } pub fn __cpp2rust_init_globals() {} diff --git a/tests/ub/out/unsafe/self_referencing_initializer.rs b/tests/ub/out/unsafe/self_referencing_initializer.rs index 9da48cec0..f33614c65 100644 --- a/tests/ub/out/unsafe/self_referencing_initializer.rs +++ b/tests/ub/out/unsafe/self_referencing_initializer.rs @@ -26,9 +26,6 @@ unsafe fn main_0() -> i32 { a: 1, b: ((p.a) + (1)), }; - let r: *mut i32 = r; - let mut __tmp_0: i32 = ((*cr) + (1)); - let cr: *const i32 = &mut __tmp_0; - return ((((x) + (p.b)) + (*r)) + (*cr)); + return ((x) + (p.b)); } pub unsafe fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/refcount/self_referencing_initializer.rs b/tests/unit/out/refcount/self_referencing_initializer.rs index 479a28e50..1662eff5f 100644 --- a/tests/unit/out/refcount/self_referencing_initializer.rs +++ b/tests/unit/out/refcount/self_referencing_initializer.rs @@ -57,24 +57,29 @@ fn main_0() -> i32 { assert!(({ { (*n.borrow()).value_ptr.clone() } } == { (field_ptr!(n.as_pointer(), value)) })); { (*n.borrow()).value_ptr.clone() }.write(7); assert!(({ (*n.borrow()).value } == 7)); - let arr: Value> = Rc::new(RefCell::new( - (0..2).map(|_| AnyPtr::default()).collect::>(), + let arr: Value> = Rc::new(RefCell::new( + (0..2) + .map(|_| ::default()) + .collect::>(), )); *arr.borrow_mut() = Box::new([ - (((arr.as_pointer() as Ptr).offset(1)) as Ptr).to_any(), - (((arr.as_pointer() as Ptr).offset(0)) as Ptr).to_any(), + list_head { + next: ((arr.as_pointer() as Ptr).offset(1)), + }, + list_head { + next: ((arr.as_pointer() as Ptr).offset(0)), + }, ]); assert!( - ((*arr.borrow())[(0) as usize] - == (((arr.as_pointer() as Ptr).offset(1)) as Ptr).to_any()) + ({ { (*arr.borrow())[(0) as usize].next.clone() } } == { + ((arr.as_pointer() as Ptr).offset(1)) + }) ); assert!( - ((*arr.borrow())[(1) as usize] - == (((arr.as_pointer() as Ptr).offset(0)) as Ptr).to_any()) + ({ { (*arr.borrow())[(1) as usize].next.clone() } } == { + ((arr.as_pointer() as Ptr).offset(0)) + }) ); - let p: Value = Rc::new(RefCell::new(AnyPtr::default())); - *p.borrow_mut() = ((p.as_pointer()) as Ptr).to_any(); - assert!(((*p.borrow()) == ((p.as_pointer()) as Ptr).to_any())); let d: Value = >::default(); *d.borrow_mut() = node_with_defaults { next: (d.as_pointer()), @@ -82,12 +87,8 @@ fn main_0() -> i32 { }; assert!(({ { (*d.borrow()).next.clone() } } == { (d.as_pointer()) })); assert!(({ (*d.borrow()).value } == 3)); - let mut heap: Ptr = - libcc2rs::malloc_refcount(8usize).reinterpret_cast::(); - assert!(!((heap).is_null())); - field!(heap, next).write({ (heap).clone() }); - assert!(({ heap.with(|__s| __s.next.clone()) } == { (heap).clone() })); - libcc2rs::free_refcount((heap).to_any()); + let mut size: usize = ::std::mem::size_of::(); + assert!((size == ::std::mem::size_of::())); return 0; } pub fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/unsafe/self_referencing_initializer.rs b/tests/unit/out/unsafe/self_referencing_initializer.rs index a6fd6b145..b94eaabf2 100644 --- a/tests/unit/out/unsafe/self_referencing_initializer.rs +++ b/tests/unit/out/unsafe/self_referencing_initializer.rs @@ -51,22 +51,17 @@ unsafe fn main_0() -> i32 { assert!(((n.value_ptr) == (&mut n.value as *mut i32))); (*n.value_ptr) = 7; assert!(((n.value) == (7))); - let mut arr: [*mut ::libc::c_void; 2] = [std::ptr::null_mut(); 2]; + let mut arr: [list_head; 2] = [::default(); 2]; arr = [ - ((&mut arr[(1) as usize] as *mut *mut ::libc::c_void) as *mut ::libc::c_void), - ((&mut arr[(0) as usize] as *mut *mut ::libc::c_void) as *mut ::libc::c_void), + list_head { + next: (&mut arr[(1) as usize] as *mut list_head), + }, + list_head { + next: (&mut arr[(0) as usize] as *mut list_head), + }, ]; - assert!( - ((arr[(0) as usize]) - == ((&mut arr[(1) as usize] as *mut *mut ::libc::c_void) as *mut ::libc::c_void)) - ); - assert!( - ((arr[(1) as usize]) - == ((&mut arr[(0) as usize] as *mut *mut ::libc::c_void) as *mut ::libc::c_void)) - ); - let mut p: *mut ::libc::c_void = std::ptr::null_mut(); - p = ((&mut p as *mut *mut ::libc::c_void) as *mut ::libc::c_void); - assert!(((p) == ((&mut p as *mut *mut ::libc::c_void) as *mut ::libc::c_void))); + assert!(((arr[(0) as usize].next) == (&mut arr[(1) as usize] as *mut list_head))); + assert!(((arr[(1) as usize].next) == (&mut arr[(0) as usize] as *mut list_head))); let mut d: node_with_defaults = ::default(); d = node_with_defaults { next: (&mut d as *mut node_with_defaults), @@ -74,12 +69,8 @@ unsafe fn main_0() -> i32 { }; assert!(((d.next) == (&mut d as *mut node_with_defaults))); assert!(((d.value) == (3))); - let mut heap: *mut list_head = - (libcc2rs::malloc_unsafe(::std::mem::size_of::()) as *mut list_head); - assert!(!((heap).is_null())); - (*heap).next = heap; - assert!((((*heap).next) == (heap))); - libcc2rs::free_unsafe((heap as *mut ::libc::c_void)); + let mut size: usize = ::std::mem::size_of::(); + assert!(((size) == (::std::mem::size_of::()))); return 0; } pub unsafe fn __cpp2rust_init_globals() {} diff --git a/tests/unit/self_referencing_initializer.cpp b/tests/unit/self_referencing_initializer.cpp index 482b62651..f816c5661 100644 --- a/tests/unit/self_referencing_initializer.cpp +++ b/tests/unit/self_referencing_initializer.cpp @@ -1,5 +1,5 @@ #include -#include +#include struct list_head { list_head *next; @@ -32,11 +32,8 @@ int main() { assert(d.next == &d); assert(d.value == 3); - list_head *heap = static_cast(malloc(sizeof(*heap))); - assert(heap != nullptr); - heap->next = heap; - assert(heap->next == heap); - free(heap); + size_t size = sizeof(size); + assert(size == sizeof(size_t)); return 0; } From 874440331222b2cce8cc8dbe4de977ab36abd5cc Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Thu, 8 Oct 2026 21:39:49 +0100 Subject: [PATCH 5/5] Update tests --- tests/unit/out/refcount/self_referencing_initializer.rs | 9 +++++++++ tests/unit/out/unsafe/self_referencing_initializer.rs | 9 +++++++++ tests/unit/self_referencing_initializer.cpp | 8 ++++++++ 3 files changed, 26 insertions(+) diff --git a/tests/unit/out/refcount/self_referencing_initializer.rs b/tests/unit/out/refcount/self_referencing_initializer.rs index 1662eff5f..80797122f 100644 --- a/tests/unit/out/refcount/self_referencing_initializer.rs +++ b/tests/unit/out/refcount/self_referencing_initializer.rs @@ -39,6 +39,10 @@ impl Default for node_with_defaults { } } } +pub fn init_0(mut l: Ptr) -> Ptr { + field!(l, next).write(Ptr::::null()); + return l; +} pub fn main() { __cpp2rust_init_globals(); std::process::exit(main_0()); @@ -87,6 +91,11 @@ fn main_0() -> i32 { }; assert!(({ { (*d.borrow()).next.clone() } } == { (d.as_pointer()) })); assert!(({ (*d.borrow()).value } == 3)); + let called: Value = >::default(); + *called.borrow_mut() = list_head { + next: ({ init_0((called.as_pointer())) }), + }; + assert!(({ { (*called.borrow()).next.clone() } } == { (called.as_pointer()) })); let mut size: usize = ::std::mem::size_of::(); assert!((size == ::std::mem::size_of::())); return 0; diff --git a/tests/unit/out/unsafe/self_referencing_initializer.rs b/tests/unit/out/unsafe/self_referencing_initializer.rs index b94eaabf2..c851c493b 100644 --- a/tests/unit/out/unsafe/self_referencing_initializer.rs +++ b/tests/unit/out/unsafe/self_referencing_initializer.rs @@ -31,6 +31,10 @@ impl Default for node_with_defaults { } } } +pub unsafe fn init_0(mut l: *mut list_head) -> *mut list_head { + (*l).next = std::ptr::null_mut(); + return l; +} pub fn main() { unsafe { __cpp2rust_init_globals(); @@ -69,6 +73,11 @@ unsafe fn main_0() -> i32 { }; assert!(((d.next) == (&mut d as *mut node_with_defaults))); assert!(((d.value) == (3))); + let mut called: list_head = ::default(); + called = list_head { + next: (unsafe { init_0((&mut called as *mut list_head)) }), + }; + assert!(((called.next) == (&mut called as *mut list_head))); let mut size: usize = ::std::mem::size_of::(); assert!(((size) == (::std::mem::size_of::()))); return 0; diff --git a/tests/unit/self_referencing_initializer.cpp b/tests/unit/self_referencing_initializer.cpp index f816c5661..27e318363 100644 --- a/tests/unit/self_referencing_initializer.cpp +++ b/tests/unit/self_referencing_initializer.cpp @@ -15,6 +15,11 @@ struct node_with_defaults { int value = 3; }; +static list_head *init(list_head *l) { + l->next = nullptr; + return l; +} + int main() { list_head list = {&list}; assert(list.next == &list); @@ -32,6 +37,9 @@ int main() { assert(d.next == &d); assert(d.value == 3); + list_head called = {init(&called)}; + assert(called.next == &called); + size_t size = sizeof(size); assert(size == sizeof(size_t));