From 5b5699933bf087b25b60bbea8f5565cb314db54a Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Tue, 23 Jun 2026 13:17:23 +0100 Subject: [PATCH 01/29] Codegen for safe union --- cpp2rust/converter/converter.cpp | 33 ++++++++++++++- cpp2rust/converter/converter.h | 2 + .../converter/models/converter_refcount.cpp | 41 +++++++++++++++++++ .../converter/models/converter_refcount.h | 2 + 4 files changed, 76 insertions(+), 2 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 9ba109d2..1a00fc6c 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -753,6 +753,11 @@ void Converter::EmitRustStructOrUnion(clang::RecordDecl *decl) { } } + if (decl->isUnion()) { + EmitRustUnion(decl); + return; + } + // Derived traits if (EmitsReprCForRecords()) { StrCat("#[repr(C)]"); @@ -770,8 +775,7 @@ void Converter::EmitRustStructOrUnion(clang::RecordDecl *decl) { auto access = clang::dyn_cast(decl) ? AccessSpecifierAsString(decl->getAccess()) : keyword::kPub; - StrCat(access, decl->isUnion() ? keyword::kUnion : keyword::kStruct, - GetRecordName(decl)); + StrCat(access, keyword::kStruct, GetRecordName(decl)); { PushBrace brace(*this); for (auto *field : decl->fields()) { @@ -817,6 +821,31 @@ void Converter::EmitRustStructOrUnion(clang::RecordDecl *decl) { AddByteReprTrait(decl); } +void Converter::EmitRustUnion(clang::RecordDecl *decl) { + if (EmitsReprCForRecords()) { + StrCat("#[repr(C)]"); + } + auto attrs = GetStructAttributes(decl); + Mapper::SetDerives(ctx_.getCanonicalTagType(decl), + std::vector(attrs.begin(), attrs.end())); + StrCat("#[derive("); + for (auto *attr : attrs) { + StrCat(attr, ','); + } + StrCat(")]"); + + StrCat(keyword::kPub, keyword::kUnion, GetRecordName(decl)); + { + PushBrace brace(*this); + for (auto *field : decl->fields()) { + VisitFieldDecl(field); + } + } + + AddDefaultTrait(decl); + AddByteReprTrait(decl); +} + bool Converter::VisitCXXRecordDecl(clang::CXXRecordDecl *decl) { if (clang::isa(decl)) { materializeTemplateSpecialization(decl); diff --git a/cpp2rust/converter/converter.h b/cpp2rust/converter/converter.h index 63de20e4..6fe344b2 100644 --- a/cpp2rust/converter/converter.h +++ b/cpp2rust/converter/converter.h @@ -112,6 +112,8 @@ class Converter : public clang::RecursiveASTVisitor { virtual void EmitRustStructOrUnion(clang::RecordDecl *decl); + virtual void EmitRustUnion(clang::RecordDecl *decl); + virtual bool EmitsReprCForRecords() const { return true; } virtual bool VisitCXXMethodDecl(clang::CXXMethodDecl *decl); diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index 7fb3bc9a..b413049e 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -469,6 +469,42 @@ void ConverterRefCount::AddDefaultTrait(const clang::RecordDecl *decl) { } void ConverterRefCount::AddDefaultTraitForUnion(const clang::RecordDecl *decl) { + auto name = GetRecordName(decl); + StrCat(std::format("impl Default for {}", name)); + PushBrace impl_brace(*this); + StrCat("fn default() -> Self"); + PushBrace fn_brace(*this); + StrCat(std::format("{} {{ __store: libcc2rs::UnionStore::new({}) }}", name, + ctx_.getASTRecordLayout(decl).getSize().getQuantity())); +} + +void ConverterRefCount::EmitRustUnion(clang::RecordDecl *decl) { + auto name = GetRecordName(decl); + + auto attrs = GetStructAttributes(decl); + Mapper::SetDerives(ctx_.getCanonicalTagType(decl), + std::vector(attrs.begin(), attrs.end())); + StrCat("#[derive("); + for (auto *attr : attrs) { + StrCat(attr, ','); + } + StrCat(")]"); + + StrCat( + std::format("pub struct {} {{ __store: libcc2rs::UnionStore, }}", name)); + + StrCat(std::format("impl {}", name)); + { + PushBrace impl_brace(*this); + for (auto *field : decl->fields()) { + StrCat(std::format( + "pub fn {}(&self) -> Ptr<{}> {{ self.__store.pod(0) }}", + GetNamedDeclAsString(field), Mapper::Map(field->getType()))); + } + } + + AddDefaultTrait(decl); + AddByteReprTrait(decl); } void ConverterRefCount::AddDropTrait(const clang::CXXRecordDecl *decl) { @@ -1789,6 +1825,11 @@ std::vector ConverterRefCount::GetStructAttributes(const clang::RecordDecl *decl) { std::vector attrs; + if (decl->isUnion()) { + attrs.emplace_back("Clone"); + return attrs; + } + if (RecordDerivesDefault(decl)) { attrs.emplace_back("Default"); } diff --git a/cpp2rust/converter/models/converter_refcount.h b/cpp2rust/converter/models/converter_refcount.h index 0d9d9296..7430c544 100644 --- a/cpp2rust/converter/models/converter_refcount.h +++ b/cpp2rust/converter/models/converter_refcount.h @@ -28,6 +28,8 @@ class ConverterRefCount final : public Converter { bool VisitCXXRecordDecl(clang::CXXRecordDecl *decl) override; + void EmitRustUnion(clang::RecordDecl *decl) override; + bool EmitsReprCForRecords() const override { return false; } void ConvertOrdAndPartialOrdTraits(const clang::CXXRecordDecl *decl, From 2427859a80648b8f04cc89faeefd4a08b26892cd Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Tue, 23 Jun 2026 13:19:04 +0100 Subject: [PATCH 02/29] Add UnionStore --- libcc2rs/src/lib.rs | 3 +++ libcc2rs/src/rc.rs | 9 +++++++++ libcc2rs/src/union.rs | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+) create mode 100644 libcc2rs/src/union.rs diff --git a/libcc2rs/src/lib.rs b/libcc2rs/src/lib.rs index 4288464f..88c73e74 100644 --- a/libcc2rs/src/lib.rs +++ b/libcc2rs/src/lib.rs @@ -7,6 +7,9 @@ pub use reinterpret::ByteRepr; mod rc; pub use rc::*; +mod union; +pub use union::*; + mod fn_ptr; pub use fn_ptr::FnPtr; diff --git a/libcc2rs/src/rc.rs b/libcc2rs/src/rc.rs index ccf2f991..71f0c993 100644 --- a/libcc2rs/src/rc.rs +++ b/libcc2rs/src/rc.rs @@ -1246,6 +1246,15 @@ impl AsPointerDyn for Rc> { impl ByteRepr for Ptr {} +impl Ptr { + pub(crate) fn reinterpreted(alloc: Rc, byte_offset: usize) -> Self { + Ptr { + offset: byte_offset, + kind: PtrKind::Reinterpreted(alloc), + } + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/libcc2rs/src/union.rs b/libcc2rs/src/union.rs new file mode 100644 index 00000000..92204387 --- /dev/null +++ b/libcc2rs/src/union.rs @@ -0,0 +1,34 @@ +// Copyright (c) 2022-present INESC-ID. +// Distributed under the MIT license that can be found in the LICENSE file. + +use std::{cell::RefCell, rc::Rc}; + +use crate::Ptr; +use crate::reinterpret::{ByteRepr, OriginalAlloc, SliceOriginalAlloc}; + +pub struct UnionStore { + bytes: Rc>>, +} + +impl UnionStore { + pub fn new(size: usize) -> Self { + UnionStore { + bytes: Rc::new(RefCell::new(vec![0u8; size])), + } + } + + pub fn pod(&self, offset: usize) -> Ptr { + let alloc: Rc = Rc::new(SliceOriginalAlloc { + weak: Rc::downgrade(&self.bytes), + }); + Ptr::reinterpreted(alloc, offset) + } +} + +impl Clone for UnionStore { + fn clone(&self) -> Self { + UnionStore { + bytes: Rc::new(RefCell::new(self.bytes.borrow().clone())), + } + } +} From 6da60bdcfec428fbde947cfe8a2fe0e26b7dde9e Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Tue, 23 Jun 2026 13:22:44 +0100 Subject: [PATCH 03/29] pod -> reinterpret and UnionStore -> UnionStorage --- cpp2rust/converter/models/converter_refcount.cpp | 6 +++--- libcc2rs/src/union.rs | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index b413049e..425383b7 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -474,7 +474,7 @@ void ConverterRefCount::AddDefaultTraitForUnion(const clang::RecordDecl *decl) { PushBrace impl_brace(*this); StrCat("fn default() -> Self"); PushBrace fn_brace(*this); - StrCat(std::format("{} {{ __store: libcc2rs::UnionStore::new({}) }}", name, + StrCat(std::format("{} {{ __store: libcc2rs::UnionStorage::new({}) }}", name, ctx_.getASTRecordLayout(decl).getSize().getQuantity())); } @@ -491,14 +491,14 @@ void ConverterRefCount::EmitRustUnion(clang::RecordDecl *decl) { StrCat(")]"); StrCat( - std::format("pub struct {} {{ __store: libcc2rs::UnionStore, }}", name)); + std::format("pub struct {} {{ __store: libcc2rs::UnionStorage, }}", name)); StrCat(std::format("impl {}", name)); { PushBrace impl_brace(*this); for (auto *field : decl->fields()) { StrCat(std::format( - "pub fn {}(&self) -> Ptr<{}> {{ self.__store.pod(0) }}", + "pub fn {}(&self) -> Ptr<{}> {{ self.__store.reinterpret(0) }}", GetNamedDeclAsString(field), Mapper::Map(field->getType()))); } } diff --git a/libcc2rs/src/union.rs b/libcc2rs/src/union.rs index 92204387..2501ebbf 100644 --- a/libcc2rs/src/union.rs +++ b/libcc2rs/src/union.rs @@ -6,18 +6,18 @@ use std::{cell::RefCell, rc::Rc}; use crate::Ptr; use crate::reinterpret::{ByteRepr, OriginalAlloc, SliceOriginalAlloc}; -pub struct UnionStore { +pub struct UnionStorage { bytes: Rc>>, } -impl UnionStore { +impl UnionStorage { pub fn new(size: usize) -> Self { - UnionStore { + UnionStorage { bytes: Rc::new(RefCell::new(vec![0u8; size])), } } - pub fn pod(&self, offset: usize) -> Ptr { + pub fn reinterpret(&self, offset: usize) -> Ptr { let alloc: Rc = Rc::new(SliceOriginalAlloc { weak: Rc::downgrade(&self.bytes), }); @@ -25,9 +25,9 @@ impl UnionStore { } } -impl Clone for UnionStore { +impl Clone for UnionStorage { fn clone(&self) -> Self { - UnionStore { + UnionStorage { bytes: Rc::new(RefCell::new(self.bytes.borrow().clone())), } } From 34627eadfb0f0633844bb25ea4739fe5388d39f1 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Tue, 23 Jun 2026 13:23:06 +0100 Subject: [PATCH 04/29] Codegen for union accessors --- .../converter/models/converter_refcount.cpp | 30 +++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index 425383b7..5a2eb0ac 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -490,8 +490,8 @@ void ConverterRefCount::EmitRustUnion(clang::RecordDecl *decl) { } StrCat(")]"); - StrCat( - std::format("pub struct {} {{ __store: libcc2rs::UnionStorage, }}", name)); + StrCat(std::format("pub struct {} {{ __store: libcc2rs::UnionStorage, }}", + name)); StrCat(std::format("impl {}", name)); { @@ -1487,6 +1487,32 @@ bool ConverterRefCount::VisitMemberExpr(clang::MemberExpr *expr) { return false; } + if (auto *parent = + clang::dyn_cast(member->getDeclContext()); + parent && parent->isUnion() && clang::isa(member)) { + std::string str; + { + Buffer buf(*this); + PushExprKind push(*this, + isLValue() ? ExprKind::LValue : ExprKind::RValue); + Converter::ConvertMemberExpr(expr); // e.g. (*u.borrow()).i + str = std::move(buf).str(); + } + str += "()"; + + if (isAddrOf()) { + StrCat(str); + computed_expr_type_ = ComputedExprType::Pointer; + return false; + } + if (isLValue()) { + pending_deref_.set(str); + return false; + } + StrCat(DerefPtrExpr(str, member->getType())); + return false; + } + std::string str; if (known) { str = GetMappedAsString(expr); From e85659f0aaa58e318a20c75b25c423571f7742cd Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Tue, 23 Jun 2026 13:25:52 +0100 Subject: [PATCH 05/29] Update tests --- .../converter/models/converter_refcount.cpp | 2 +- .../refcount/tag_vs_identifier_collision.rs | 187 +++++++++++++ tests/unit/out/refcount/union_basic.rs | 39 +++ .../union_pointer_pun_writethrough.rs | 39 +++ .../out/refcount/union_tagged_struct_arms.rs | 251 ++++++++++++++++++ tests/unit/tag_vs_identifier_collision.c | 1 - tests/unit/union_basic.c | 1 - tests/unit/union_pointer_pun_writethrough.c | 2 +- tests/unit/union_tagged_struct_arms.c | 2 +- 9 files changed, 519 insertions(+), 5 deletions(-) create mode 100644 tests/unit/out/refcount/tag_vs_identifier_collision.rs create mode 100644 tests/unit/out/refcount/union_basic.rs create mode 100644 tests/unit/out/refcount/union_pointer_pun_writethrough.rs create mode 100644 tests/unit/out/refcount/union_tagged_struct_arms.rs diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index 5a2eb0ac..bbffa741 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -1495,7 +1495,7 @@ bool ConverterRefCount::VisitMemberExpr(clang::MemberExpr *expr) { Buffer buf(*this); PushExprKind push(*this, isLValue() ? ExprKind::LValue : ExprKind::RValue); - Converter::ConvertMemberExpr(expr); // e.g. (*u.borrow()).i + Converter::ConvertMemberExpr(expr); str = std::move(buf).str(); } str += "()"; diff --git a/tests/unit/out/refcount/tag_vs_identifier_collision.rs b/tests/unit/out/refcount/tag_vs_identifier_collision.rs new file mode 100644 index 00000000..0623f19f --- /dev/null +++ b/tests/unit/out/refcount/tag_vs_identifier_collision.rs @@ -0,0 +1,187 @@ +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, Copy, PartialEq, Debug, Default)] +enum widget_enum { + #[default] + MODE_IDLE = 0, + MODE_ACTIVE = 1, + MODE_DONE = 2, +} +impl From for widget_enum { + fn from(n: i32) -> widget_enum { + match n { + 0 => widget_enum::MODE_IDLE, + 1 => widget_enum::MODE_ACTIVE, + 2 => widget_enum::MODE_DONE, + _ => panic!("invalid widget_enum value: {}", n), + } + } +} +libcc2rs::impl_enum_inc_dec!(widget_enum); +#[derive(Default)] +pub struct widget { + pub id: Value, + pub mode: Value, +} +impl ByteRepr for widget {} +#[derive(Default)] +pub struct point_struct { + pub x: Value, + pub y: Value, +} +impl ByteRepr for point_struct { + fn to_bytes(&self, buf: &mut [u8]) { + (*self.x.borrow()).to_bytes(&mut buf[0..4]); + (*self.y.borrow()).to_bytes(&mut buf[4..8]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + x: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), + y: Rc::new(RefCell::new(::from_bytes(&buf[4..8]))), + } + } +} +#[derive(Clone)] +pub struct point { + __store: libcc2rs::UnionStorage, +} +impl point { + pub fn whole(&self) -> Ptr { + self.__store.reinterpret(0) + } + pub fn half(&self) -> Ptr { + self.__store.reinterpret(0) + } +} +impl Default for point { + fn default() -> Self { + point { + __store: libcc2rs::UnionStorage::new(4), + } + } +} +impl ByteRepr for point {} +#[derive(Clone)] +pub struct slot_union { + __store: libcc2rs::UnionStorage, +} +impl slot_union { + pub fn i(&self) -> Ptr { + self.__store.reinterpret(0) + } + pub fn u(&self) -> Ptr { + self.__store.reinterpret(0) + } +} +impl Default for slot_union { + fn default() -> Self { + slot_union { + __store: libcc2rs::UnionStorage::new(4), + } + } +} +impl ByteRepr for slot_union {} +#[derive(Clone, Copy, PartialEq, Debug, Default)] +enum slot { + #[default] + SLOT_A = 0, + SLOT_B = 1, +} +impl From for slot { + fn from(n: i32) -> slot { + match n { + 0 => slot::SLOT_A, + 1 => slot::SLOT_B, + _ => panic!("invalid slot value: {}", n), + } + } +} +libcc2rs::impl_enum_inc_dec!(slot); +#[derive(Default)] +pub struct Inner { + pub tag_field: Value, +} +impl ByteRepr for Inner { + fn to_bytes(&self, buf: &mut [u8]) { + (*self.tag_field.borrow()).to_bytes(&mut buf[0..4]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + tag_field: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), + } + } +} +#[derive(Default)] +pub struct Outer { + pub field: Value, +} +impl ByteRepr for Outer {} +#[derive(Default)] +pub struct Inner_struct { + pub typedef_field: Value, +} +impl ByteRepr for Inner_struct { + fn to_bytes(&self, buf: &mut [u8]) { + (*self.typedef_field.borrow()).to_bytes(&mut buf[0..4]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + typedef_field: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), + } + } +} +pub fn is_active_0(w: Ptr) -> i32 { + let w: Value> = Rc::new(RefCell::new(w)); + return (({ + let _lhs = ((*(*(*w.borrow()).upgrade().deref()).mode.borrow()) as u32).clone(); + _lhs == ((widget_enum::MODE_ACTIVE as i32) as u32) + }) as i32); +} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let w: Value = >::default(); + (*(*w.borrow()).id.borrow_mut()) = 7; + (*(*w.borrow()).mode.borrow_mut()) = widget_enum::MODE_ACTIVE; + assert!( + (({ + let _w: Ptr = (w.as_pointer()); + is_active_0(_w) + }) != 0) + ); + (*(*w.borrow()).mode.borrow_mut()) = widget_enum::MODE_DONE; + assert!( + (((((*(*w.borrow()).mode.borrow()) as u32) == ((widget_enum::MODE_DONE as i32) as u32)) + as i32) + != 0) + ); + let p: Value = >::default(); + (*(*p.borrow()).x.borrow_mut()) = 3; + (*(*p.borrow()).y.borrow_mut()) = 4; + assert!((((((*(*p.borrow()).x.borrow()) + (*(*p.borrow()).y.borrow())) == 7) as i32) != 0)); + let up: Value = >::default(); + (*up.borrow_mut()).whole().write(5); + assert!((((((*up.borrow()).whole().read()) == 5) as i32) != 0)); + let b: Value = >::default(); + (*b.borrow_mut()).i().write(9); + assert!((((((*b.borrow()).i().read()) == 9) as i32) != 0)); + let e: Value = Rc::new(RefCell::new(slot::SLOT_B)); + assert!((((((*e.borrow()) as u32) == ((slot::SLOT_B as i32) as u32)) as i32) != 0)); + let inner_tag: Value = >::default(); + (*(*inner_tag.borrow()).tag_field.borrow_mut()) = 11; + assert!(((((*(*inner_tag.borrow()).tag_field.borrow()) == 11) as i32) != 0)); + let inner_typedef: Value = >::default(); + (*(*inner_typedef.borrow()).typedef_field.borrow_mut()) = 22; + assert!(((((*(*inner_typedef.borrow()).typedef_field.borrow()) == 22) as i32) != 0)); + let o: Value = >::default(); + (*(*(*o.borrow()).field.borrow()).tag_field.borrow_mut()) = 33; + assert!(((((*(*(*o.borrow()).field.borrow()).tag_field.borrow()) == 33) as i32) != 0)); + return (*(*w.borrow()).id.borrow()); +} diff --git a/tests/unit/out/refcount/union_basic.rs b/tests/unit/out/refcount/union_basic.rs new file mode 100644 index 00000000..f6fe7b26 --- /dev/null +++ b/tests/unit/out/refcount/union_basic.rs @@ -0,0 +1,39 @@ +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)] +pub struct basic { + __store: libcc2rs::UnionStorage, +} +impl basic { + pub fn i(&self) -> Ptr { + self.__store.reinterpret(0) + } + pub fn f(&self) -> Ptr { + self.__store.reinterpret(0) + } +} +impl Default for basic { + fn default() -> Self { + basic { + __store: libcc2rs::UnionStorage::new(4), + } + } +} +impl ByteRepr for basic {} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let u: Value = >::default(); + (*u.borrow_mut()).i().write(42); + assert!((((((*u.borrow()).i().read()) == 42) as i32) != 0)); + (*u.borrow_mut()).f().write(3.140000105E+0); + assert!((((((*u.borrow()).f().read()) == 3.140000105E+0) as i32) != 0)); + return 0; +} diff --git a/tests/unit/out/refcount/union_pointer_pun_writethrough.rs b/tests/unit/out/refcount/union_pointer_pun_writethrough.rs new file mode 100644 index 00000000..6ff3165c --- /dev/null +++ b/tests/unit/out/refcount/union_pointer_pun_writethrough.rs @@ -0,0 +1,39 @@ +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}; +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let x: Value = Rc::new(RefCell::new((-1_i32 as i64))); + #[derive(Clone)] + pub struct anon_0 { + __store: libcc2rs::UnionStorage, + } + impl anon_0 { + pub fn as_unsigned(&self) -> Ptr> { + self.__store.reinterpret(0) + } + pub fn as_signed(&self) -> Ptr> { + self.__store.reinterpret(0) + } + } + impl Default for anon_0 { + fn default() -> Self { + anon_0 { + __store: libcc2rs::UnionStorage::new(8), + } + } + } + impl ByteRepr for anon_0 {}; + let pp: Value = >::default(); + (*pp.borrow_mut()).as_signed().write((x.as_pointer())); + ((*pp.borrow()).as_unsigned().read()).write(42_u64); + assert!(((((*x.borrow()) == 42_i64) as i32) != 0)); + return 0; +} diff --git a/tests/unit/out/refcount/union_tagged_struct_arms.rs b/tests/unit/out/refcount/union_tagged_struct_arms.rs new file mode 100644 index 00000000..6c4cc0d5 --- /dev/null +++ b/tests/unit/out/refcount/union_tagged_struct_arms.rs @@ -0,0 +1,251 @@ +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, Copy, PartialEq, Debug, Default)] +enum Choice_enum { + #[default] + C_LIST = 1, + C_LETTERS = 2, + C_INTEGERS = 3, +} +impl From for Choice_enum { + fn from(n: i32) -> Choice_enum { + match n { + 1 => Choice_enum::C_LIST, + 2 => Choice_enum::C_LETTERS, + 3 => Choice_enum::C_INTEGERS, + _ => panic!("invalid Choice_enum value: {}", n), + } + } +} +libcc2rs::impl_enum_inc_dec!(Choice_enum); +#[derive(Default)] +pub struct anon_1 { + pub items: Value>>, + pub count: Value, + pub cursor: Value, +} +impl ByteRepr for anon_1 {} +#[derive(Default)] +pub struct anon_2 { + pub lo: Value, + pub hi: Value, + pub curr: Value, + pub step: Value, +} +impl ByteRepr for anon_2 { + fn to_bytes(&self, buf: &mut [u8]) { + (*self.lo.borrow()).to_bytes(&mut buf[0..4]); + (*self.hi.borrow()).to_bytes(&mut buf[4..8]); + (*self.curr.borrow()).to_bytes(&mut buf[8..12]); + (*self.step.borrow()).to_bytes(&mut buf[12..13]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + lo: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), + hi: Rc::new(RefCell::new(::from_bytes(&buf[4..8]))), + curr: Rc::new(RefCell::new(::from_bytes(&buf[8..12]))), + step: Rc::new(RefCell::new(::from_bytes(&buf[12..13]))), + } + } +} +#[derive(Default)] +pub struct anon_3 { + pub lo: Value, + pub hi: Value, + pub curr: Value, + pub step: Value, + pub width: Value, +} +impl ByteRepr for anon_3 { + fn to_bytes(&self, buf: &mut [u8]) { + (*self.lo.borrow()).to_bytes(&mut buf[0..8]); + (*self.hi.borrow()).to_bytes(&mut buf[8..16]); + (*self.curr.borrow()).to_bytes(&mut buf[16..24]); + (*self.step.borrow()).to_bytes(&mut buf[24..32]); + (*self.width.borrow()).to_bytes(&mut buf[32..36]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + lo: Rc::new(RefCell::new(::from_bytes(&buf[0..8]))), + hi: Rc::new(RefCell::new(::from_bytes(&buf[8..16]))), + curr: Rc::new(RefCell::new(::from_bytes(&buf[16..24]))), + step: Rc::new(RefCell::new(::from_bytes(&buf[24..32]))), + width: Rc::new(RefCell::new(::from_bytes(&buf[32..36]))), + } + } +} +#[derive(Clone)] +pub struct anon_0 { + __store: libcc2rs::UnionStorage, +} +impl anon_0 { + pub fn list(&self) -> Ptr { + self.__store.reinterpret(0) + } + pub fn letters(&self) -> Ptr { + self.__store.reinterpret(0) + } + pub fn integers(&self) -> Ptr { + self.__store.reinterpret(0) + } +} +impl Default for anon_0 { + fn default() -> Self { + anon_0 { + __store: libcc2rs::UnionStorage::new(40), + } + } +} +impl ByteRepr for anon_0 {} +#[derive(Default)] +pub struct Branch { + pub choice: Value, + pub index: Value, + pub v: Value, +} +impl ByteRepr for Branch {} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + thread_local!( + static items_4: Value]>> = Rc::new(RefCell::new(Box::new([ + Ptr::from_string_literal(b"a"), + Ptr::from_string_literal(b"b"), + Ptr::from_string_literal(b"c"), + ]))); + ); + let p_list: Value = >::default(); + (*(*p_list.borrow()).choice.borrow_mut()) = Choice_enum::C_LIST; + (*(*p_list.borrow()).index.borrow_mut()) = 0; + (*(*(*(*p_list.borrow()).v.borrow()).list().upgrade().deref()) + .items + .borrow_mut()) = (items_4.with(Value::clone).as_pointer() as Ptr>); + (*(*(*(*p_list.borrow()).v.borrow()).list().upgrade().deref()) + .count + .borrow_mut()) = 3_i64; + (*(*(*(*p_list.borrow()).v.borrow()).list().upgrade().deref()) + .cursor + .borrow_mut()) = 1_i64; + assert!( + ((((*(*(*(*p_list.borrow()).v.borrow()).list().upgrade().deref()) + .count + .borrow()) + == 3_i64) as i32) + != 0) + ); + assert!( + (((((((*(*(*(*p_list.borrow()).v.borrow()).list().upgrade().deref()) + .items + .borrow()) + .offset((1) as isize) + .read()) + .offset((0) as isize) + .read()) as i32) + == ('b' as i32)) as i32) + != 0) + ); + let p_letters: Value = >::default(); + (*(*p_letters.borrow()).choice.borrow_mut()) = Choice_enum::C_LETTERS; + (*(*p_letters.borrow()).index.borrow_mut()) = 1; + (*(*(*(*p_letters.borrow()).v.borrow()) + .letters() + .upgrade() + .deref()) + .lo + .borrow_mut()) = ('a' as i32); + (*(*(*(*p_letters.borrow()).v.borrow()) + .letters() + .upgrade() + .deref()) + .hi + .borrow_mut()) = ('z' as i32); + (*(*(*(*p_letters.borrow()).v.borrow()) + .letters() + .upgrade() + .deref()) + .curr + .borrow_mut()) = ('m' as i32); + (*(*(*(*p_letters.borrow()).v.borrow()) + .letters() + .upgrade() + .deref()) + .step + .borrow_mut()) = 1_u8; + assert!( + (((((*(*(*(*p_letters.borrow()).v.borrow()) + .letters() + .upgrade() + .deref()) + .hi + .borrow()) + - (*(*(*(*p_letters.borrow()).v.borrow()) + .letters() + .upgrade() + .deref()) + .lo + .borrow())) + == 25) as i32) + != 0) + ); + let p_integers: Value = >::default(); + (*(*p_integers.borrow()).choice.borrow_mut()) = Choice_enum::C_INTEGERS; + (*(*p_integers.borrow()).index.borrow_mut()) = 2; + (*(*(*(*p_integers.borrow()).v.borrow()) + .integers() + .upgrade() + .deref()) + .lo + .borrow_mut()) = 1_i64; + (*(*(*(*p_integers.borrow()).v.borrow()) + .integers() + .upgrade() + .deref()) + .hi + .borrow_mut()) = 100_i64; + (*(*(*(*p_integers.borrow()).v.borrow()) + .integers() + .upgrade() + .deref()) + .curr + .borrow_mut()) = 1_i64; + (*(*(*(*p_integers.borrow()).v.borrow()) + .integers() + .upgrade() + .deref()) + .step + .borrow_mut()) = 1_i64; + (*(*(*(*p_integers.borrow()).v.borrow()) + .integers() + .upgrade() + .deref()) + .width + .borrow_mut()) = 3; + assert!( + ((((*(*(*(*p_integers.borrow()).v.borrow()) + .integers() + .upgrade() + .deref()) + .hi + .borrow()) + == 100_i64) as i32) + != 0) + ); + assert!( + ((((*(*(*(*p_integers.borrow()).v.borrow()) + .integers() + .upgrade() + .deref()) + .width + .borrow()) + == 3) as i32) + != 0) + ); + return 0; +} diff --git a/tests/unit/tag_vs_identifier_collision.c b/tests/unit/tag_vs_identifier_collision.c index 79212c64..a51731e9 100644 --- a/tests/unit/tag_vs_identifier_collision.c +++ b/tests/unit/tag_vs_identifier_collision.c @@ -1,4 +1,3 @@ -// no-compile: refcount #include typedef enum { MODE_IDLE, MODE_ACTIVE, MODE_DONE } widget; diff --git a/tests/unit/union_basic.c b/tests/unit/union_basic.c index 86731cc2..5d26a336 100644 --- a/tests/unit/union_basic.c +++ b/tests/unit/union_basic.c @@ -1,4 +1,3 @@ -// no-compile: refcount #include union basic { diff --git a/tests/unit/union_pointer_pun_writethrough.c b/tests/unit/union_pointer_pun_writethrough.c index d29cbc50..44bd842f 100644 --- a/tests/unit/union_pointer_pun_writethrough.c +++ b/tests/unit/union_pointer_pun_writethrough.c @@ -1,4 +1,4 @@ -// no-compile: refcount +// panic: refcount #include int main(void) { diff --git a/tests/unit/union_tagged_struct_arms.c b/tests/unit/union_tagged_struct_arms.c index f5b90e18..ca20e9a6 100644 --- a/tests/unit/union_tagged_struct_arms.c +++ b/tests/unit/union_tagged_struct_arms.c @@ -1,4 +1,4 @@ -// no-compile: refcount +// panic: refcount #include #include From 50584558f3900671de05925c8273c4dcc3ddecec Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Tue, 23 Jun 2026 15:11:05 +0100 Subject: [PATCH 06/29] Add ByteRepr for arrays --- cpp2rust/converter/converter_lib.cpp | 24 ++++++++++++++++++ cpp2rust/converter/converter_lib.h | 2 ++ .../converter/models/converter_refcount.cpp | 25 +++---------------- 3 files changed, 29 insertions(+), 22 deletions(-) diff --git a/cpp2rust/converter/converter_lib.cpp b/cpp2rust/converter/converter_lib.cpp index 12c0bf69..8e9261d0 100644 --- a/cpp2rust/converter/converter_lib.cpp +++ b/cpp2rust/converter/converter_lib.cpp @@ -199,6 +199,30 @@ bool IsMut(clang::QualType qual_type) { qual_type->getPointeeType().isConstQualified()); } +bool TypeImplementsByteRepr(clang::QualType qt) { + if (qt->isEnumeralType()) { + return false; + } + if (qt->isIntegerType() || qt->isFloatingType()) { + return true; + } + if (const auto *arr = qt->getAsArrayTypeUnsafe()) { + return TypeImplementsByteRepr(arr->getElementType()); + } + if (const auto *rd = qt->getAsRecordDecl()) { + if (rd->isUnion()) { + return false; + } + for (const auto *field : rd->fields()) { + if (!TypeImplementsByteRepr(field->getType())) { + return false; + } + } + return true; + } + return false; +} + bool IsMutatingCall(const clang::CallExpr *expr) { if (auto *callee = expr->getDirectCallee()) { if (auto *method = clang::dyn_cast(callee)) { diff --git a/cpp2rust/converter/converter_lib.h b/cpp2rust/converter/converter_lib.h index a09e0e5d..14463f13 100644 --- a/cpp2rust/converter/converter_lib.h +++ b/cpp2rust/converter/converter_lib.h @@ -51,6 +51,8 @@ bool IsUnsignedArithOp(const clang::BinaryOperator *expr); bool IsMut(clang::QualType qual_type); +bool TypeImplementsByteRepr(clang::QualType qt); + bool IsMutatingCall(const clang::CallExpr *expr); bool IsOverloadedFunction(const clang::FunctionDecl *decl); diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index bbffa741..40d941d6 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -537,30 +537,10 @@ void ConverterRefCount::AddDropTrait(const clang::CXXRecordDecl *decl) { StrCat('}'); } -static bool recordImplementsByteRepr(const clang::RecordDecl *decl) { - if (decl->isUnion()) { - return false; - } - - // ByteRepr is only supported for user-defined structs that contain ByteRepr - // fields. - for (auto *f : decl->fields()) { - auto qt = f->getType(); - if (qt->isEnumeralType()) { - return false; - } - if (!qt->isIntegerType() && !qt->isFloatingType()) { - return false; - } - } - - return true; -} - void ConverterRefCount::AddByteReprTrait(const clang::RecordDecl *decl) { auto struct_name = GetRecordName(decl); - if (!recordImplementsByteRepr(decl)) { + if (!TypeImplementsByteRepr(ctx_.getCanonicalTagType(decl))) { StrCat(std::format("impl ByteRepr for {}", struct_name)); PushBrace brace(*this); return; @@ -588,6 +568,7 @@ void ConverterRefCount::AddByteReprTrait(const clang::RecordDecl *decl) { StrCat("fn from_bytes(buf: &[u8]) -> Self"); { PushBrace fn_brace(*this); + PushConversionKind push(*this, ConversionKind::FullRefCount); StrCat("Self"); PushBrace lit_brace(*this); unsigned idx = 0; @@ -596,7 +577,7 @@ void ConverterRefCount::AddByteReprTrait(const clang::RecordDecl *decl) { auto byte_size = ctx_.getTypeSize(field->getType()) / 8; StrCat(std::format( "{}: Rc::new(RefCell::new(<{}>::from_bytes(&buf[{}..{}]))),", - GetNamedDeclAsString(field), Mapper::Map(field->getType()), byte_off, + GetNamedDeclAsString(field), ToString(field->getType()), byte_off, byte_off + byte_size)); ++idx; } From d0957adb9e24fef52c746a271c7c12e2b2afbb97 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Tue, 23 Jun 2026 15:11:30 +0100 Subject: [PATCH 07/29] Access fields of struct arm in union --- cpp2rust/converter/models/converter_refcount.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index 40d941d6..b6081081 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -1488,6 +1488,9 @@ bool ConverterRefCount::VisitMemberExpr(clang::MemberExpr *expr) { } if (isLValue()) { pending_deref_.set(str); + if (member->getType()->isRecordType()) { + StrCat("__v"); + } return false; } StrCat(DerefPtrExpr(str, member->getType())); @@ -1924,7 +1927,11 @@ void ConverterRefCount::EmitSetOrAssign(clang::Expr *lhs, auto lhs_str = ConvertLValue(lhs); if (!pending_deref_.empty()) { auto ptr = pending_deref_.take(); - StrCat(ptr, ".write(", rhs, ')'); + if (lhs_str.empty()) { + StrCat(ptr, ".write(", rhs, ')'); + } else { + StrCat(ptr, ".with_mut(|__v| ", lhs_str, token::kAssign, rhs, ')'); + } } else { StrCat(lhs_str, token::kAssign, rhs); } From e4d60b8b4bf7d246432aacc29c1da847a3e0c85f Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Tue, 23 Jun 2026 15:11:41 +0100 Subject: [PATCH 08/29] Add ByteRepr for arrays --- libcc2rs/src/reinterpret.rs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/libcc2rs/src/reinterpret.rs b/libcc2rs/src/reinterpret.rs index 452b35de..29c91f63 100644 --- a/libcc2rs/src/reinterpret.rs +++ b/libcc2rs/src/reinterpret.rs @@ -62,7 +62,22 @@ impl ByteRepr for Vec {} impl ByteRepr for Option {} impl ByteRepr for std::rc::Rc {} impl ByteRepr for std::cell::RefCell {} -impl ByteRepr for Box<[T]> {} +impl ByteRepr for Box<[T]> { + fn to_bytes(&self, buf: &mut [u8]) { + let size = std::mem::size_of::(); + for (i, elem) in self.iter().enumerate() { + elem.to_bytes(&mut buf[i * size..(i + 1) * size]); + } + } + fn from_bytes(buf: &[u8]) -> Self { + let size = std::mem::size_of::(); + let n = buf.len() / size; + (0..n) + .map(|i| T::from_bytes(&buf[i * size..(i + 1) * size])) + .collect::>() + .into_boxed_slice() + } +} impl ByteRepr for Box {} impl ByteRepr for *const T {} impl ByteRepr for *mut T {} From 9f40efb3f93c45f2e51ebccf0db9e837c4de7c72 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Tue, 23 Jun 2026 15:11:52 +0100 Subject: [PATCH 09/29] Update tests --- tests/unit/out/refcount/anonymous-struct.rs | 34 ++++++++++++++++-- tests/unit/out/refcount/anonymous-struct_c.rs | 34 ++++++++++++++++-- tests/unit/out/refcount/array_const_init.rs | 15 +++++++- .../out/refcount/array_of_noncopy_struct.rs | 13 ++++++- tests/unit/out/refcount/c_struct.rs | 13 ++++++- tests/unit/out/refcount/class.rs | 13 ++++++- tests/unit/out/refcount/class_templates.rs | 33 +++++++++++++++-- .../refcount/foreach_disjoint_field_borrow.rs | 13 ++++++- tests/unit/out/refcount/huffman.rs | 23 +++++++++++- tests/unit/out/refcount/implicit_autoref.rs | 11 +++++- tests/unit/out/refcount/kruskal.rs | 36 +++++++++++++++++-- tests/unit/out/refcount/push_emplace_back.rs | 15 +++++++- .../refcount/tag_vs_identifier_collision.rs | 11 +++++- .../unit/out/refcount/typedef-anon-struct.rs | 11 +++++- tests/unit/out/refcount/unique_ptr.rs | 11 +++++- .../out/refcount/unique_ptr_const_deref.rs | 11 +++++- tests/unit/out/refcount/unique_ptr_nested.rs | 11 +++++- tests/unit/out/refcount/void_cast.rs | 11 +++++- 18 files changed, 296 insertions(+), 23 deletions(-) diff --git a/tests/unit/out/refcount/anonymous-struct.rs b/tests/unit/out/refcount/anonymous-struct.rs index fcd7db80..159d05a6 100644 --- a/tests/unit/out/refcount/anonymous-struct.rs +++ b/tests/unit/out/refcount/anonymous-struct.rs @@ -170,7 +170,20 @@ impl Clone for anon_3 { this } } -impl ByteRepr for anon_3 {} +impl ByteRepr for anon_3 { + fn to_bytes(&self, buf: &mut [u8]) { + (*self.i.borrow()).to_bytes(&mut buf[0..4]); + (*self.inner_named.borrow()).to_bytes(&mut buf[4..8]); + (*self.anon_5.borrow()).to_bytes(&mut buf[8..12]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + i: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), + inner_named: Rc::new(RefCell::new(::from_bytes(&buf[4..8]))), + anon_5: Rc::new(RefCell::new(::from_bytes(&buf[8..12]))), + } + } +} #[derive(Default)] pub struct Outer { pub named: Value, @@ -191,7 +204,24 @@ impl Clone for Outer { this } } -impl ByteRepr for Outer {} +impl ByteRepr for Outer { + fn to_bytes(&self, buf: &mut [u8]) { + (*self.named.borrow()).to_bytes(&mut buf[0..8]); + (*self.anonymous_named_0.borrow()).to_bytes(&mut buf[8..16]); + (*self.anonymous_named_1.borrow()).to_bytes(&mut buf[16..24]); + (*self.anon_2.borrow()).to_bytes(&mut buf[24..32]); + (*self.anon_3.borrow()).to_bytes(&mut buf[32..44]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + named: Rc::new(RefCell::new(::from_bytes(&buf[0..8]))), + anonymous_named_0: Rc::new(RefCell::new(::from_bytes(&buf[8..16]))), + anonymous_named_1: Rc::new(RefCell::new(::from_bytes(&buf[16..24]))), + anon_2: Rc::new(RefCell::new(::from_bytes(&buf[24..32]))), + anon_3: Rc::new(RefCell::new(::from_bytes(&buf[32..44]))), + } + } +} pub fn main() { std::process::exit(main_0()); } diff --git a/tests/unit/out/refcount/anonymous-struct_c.rs b/tests/unit/out/refcount/anonymous-struct_c.rs index 23ce8df8..a9ae663e 100644 --- a/tests/unit/out/refcount/anonymous-struct_c.rs +++ b/tests/unit/out/refcount/anonymous-struct_c.rs @@ -108,7 +108,20 @@ pub struct anon_3 { pub inner_named: Value, pub anon_5: Value, } -impl ByteRepr for anon_3 {} +impl ByteRepr for anon_3 { + fn to_bytes(&self, buf: &mut [u8]) { + (*self.i.borrow()).to_bytes(&mut buf[0..4]); + (*self.inner_named.borrow()).to_bytes(&mut buf[4..8]); + (*self.anon_5.borrow()).to_bytes(&mut buf[8..12]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + i: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), + inner_named: Rc::new(RefCell::new(::from_bytes(&buf[4..8]))), + anon_5: Rc::new(RefCell::new(::from_bytes(&buf[8..12]))), + } + } +} #[derive(Default)] pub struct Outer { pub named: Value, @@ -117,7 +130,24 @@ pub struct Outer { pub anon_2: Value, pub anon_3: Value, } -impl ByteRepr for Outer {} +impl ByteRepr for Outer { + fn to_bytes(&self, buf: &mut [u8]) { + (*self.named.borrow()).to_bytes(&mut buf[0..8]); + (*self.anon0.borrow()).to_bytes(&mut buf[8..16]); + (*self.anon1.borrow()).to_bytes(&mut buf[16..24]); + (*self.anon_2.borrow()).to_bytes(&mut buf[24..32]); + (*self.anon_3.borrow()).to_bytes(&mut buf[32..44]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + named: Rc::new(RefCell::new(::from_bytes(&buf[0..8]))), + anon0: Rc::new(RefCell::new(::from_bytes(&buf[8..16]))), + anon1: Rc::new(RefCell::new(::from_bytes(&buf[16..24]))), + anon_2: Rc::new(RefCell::new(::from_bytes(&buf[24..32]))), + anon_3: Rc::new(RefCell::new(::from_bytes(&buf[32..44]))), + } + } +} pub fn main() { std::process::exit(main_0()); } diff --git a/tests/unit/out/refcount/array_const_init.rs b/tests/unit/out/refcount/array_const_init.rs index 784f3a73..8a8a41b1 100644 --- a/tests/unit/out/refcount/array_const_init.rs +++ b/tests/unit/out/refcount/array_const_init.rs @@ -25,7 +25,20 @@ impl Default for S { } } } -impl ByteRepr for S {} +impl ByteRepr for S { + fn to_bytes(&self, buf: &mut [u8]) { + (*self.head.borrow()).to_bytes(&mut buf[0..4]); + (*self.tail.borrow()).to_bytes(&mut buf[4..16]); + (*self.buf.borrow()).to_bytes(&mut buf[16..20]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + head: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), + tail: Rc::new(RefCell::new(>::from_bytes(&buf[4..16]))), + buf: Rc::new(RefCell::new(>::from_bytes(&buf[16..20]))), + } + } +} thread_local!( pub static s_0: Value = Rc::new(RefCell::new(S { head: Rc::new(RefCell::new(5)), diff --git a/tests/unit/out/refcount/array_of_noncopy_struct.rs b/tests/unit/out/refcount/array_of_noncopy_struct.rs index 4af56349..d09df1bc 100644 --- a/tests/unit/out/refcount/array_of_noncopy_struct.rs +++ b/tests/unit/out/refcount/array_of_noncopy_struct.rs @@ -20,7 +20,18 @@ impl Clone for NonCopy { this } } -impl ByteRepr for NonCopy {} +impl ByteRepr for NonCopy { + fn to_bytes(&self, buf: &mut [u8]) { + (*self.data.borrow()).to_bytes(&mut buf[0..24]); + (*self.tag.borrow()).to_bytes(&mut buf[24..28]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + data: Rc::new(RefCell::new(>::from_bytes(&buf[0..24]))), + tag: Rc::new(RefCell::new(::from_bytes(&buf[24..28]))), + } + } +} pub fn main() { std::process::exit(main_0()); } diff --git a/tests/unit/out/refcount/c_struct.rs b/tests/unit/out/refcount/c_struct.rs index 0549baab..de876ec4 100644 --- a/tests/unit/out/refcount/c_struct.rs +++ b/tests/unit/out/refcount/c_struct.rs @@ -28,7 +28,18 @@ pub struct Line { pub start: Value, pub end: Value, } -impl ByteRepr for Line {} +impl ByteRepr for Line { + fn to_bytes(&self, buf: &mut [u8]) { + (*self.start.borrow()).to_bytes(&mut buf[0..8]); + (*self.end.borrow()).to_bytes(&mut buf[8..16]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + start: Rc::new(RefCell::new(::from_bytes(&buf[0..8]))), + end: Rc::new(RefCell::new(::from_bytes(&buf[8..16]))), + } + } +} #[derive(Default)] pub struct Node { pub value: Value, diff --git a/tests/unit/out/refcount/class.rs b/tests/unit/out/refcount/class.rs index 6bed63d3..cf3599a7 100644 --- a/tests/unit/out/refcount/class.rs +++ b/tests/unit/out/refcount/class.rs @@ -89,7 +89,18 @@ impl Clone for Route { this } } -impl ByteRepr for Route {} +impl ByteRepr for Route { + fn to_bytes(&self, buf: &mut [u8]) { + (*self.path.borrow()).to_bytes(&mut buf[0..8]); + (*self.cost.borrow()).to_bytes(&mut buf[8..16]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + path: Rc::new(RefCell::new(::from_bytes(&buf[0..8]))), + cost: Rc::new(RefCell::new(::from_bytes(&buf[8..16]))), + } + } +} pub fn RandomRoute_0(route: Ptr) -> i32 { if (((*(*(*route.upgrade().deref()).path.borrow()).first.borrow()) % 2) != 0) { return ({ diff --git a/tests/unit/out/refcount/class_templates.rs b/tests/unit/out/refcount/class_templates.rs index 3cbce86e..b2e532c4 100644 --- a/tests/unit/out/refcount/class_templates.rs +++ b/tests/unit/out/refcount/class_templates.rs @@ -42,7 +42,16 @@ impl Clone for MyContainer_int_ { this } } -impl ByteRepr for MyContainer_int_ {} +impl ByteRepr for MyContainer_int_ { + fn to_bytes(&self, buf: &mut [u8]) { + (*self.vec_.borrow()).to_bytes(&mut buf[0..24]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + vec_: Rc::new(RefCell::new(>::from_bytes(&buf[0..24]))), + } + } +} #[derive(Default)] pub struct MyContainer_char_ { vec_: Value>, @@ -79,7 +88,16 @@ impl Clone for MyContainer_char_ { this } } -impl ByteRepr for MyContainer_char_ {} +impl ByteRepr for MyContainer_char_ { + fn to_bytes(&self, buf: &mut [u8]) { + (*self.vec_.borrow()).to_bytes(&mut buf[0..24]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + vec_: Rc::new(RefCell::new(>::from_bytes(&buf[0..24]))), + } + } +} #[derive(Default)] pub struct MyContainer_float_ { vec_: Value>, @@ -116,7 +134,16 @@ impl Clone for MyContainer_float_ { this } } -impl ByteRepr for MyContainer_float_ {} +impl ByteRepr for MyContainer_float_ { + fn to_bytes(&self, buf: &mut [u8]) { + (*self.vec_.borrow()).to_bytes(&mut buf[0..24]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + vec_: Rc::new(RefCell::new(>::from_bytes(&buf[0..24]))), + } + } +} pub fn main() { std::process::exit(main_0()); } diff --git a/tests/unit/out/refcount/foreach_disjoint_field_borrow.rs b/tests/unit/out/refcount/foreach_disjoint_field_borrow.rs index 66c9e892..8725ce22 100644 --- a/tests/unit/out/refcount/foreach_disjoint_field_borrow.rs +++ b/tests/unit/out/refcount/foreach_disjoint_field_borrow.rs @@ -20,7 +20,18 @@ impl Clone for S { this } } -impl ByteRepr for S {} +impl ByteRepr for S { + fn to_bytes(&self, buf: &mut [u8]) { + (*self.v.borrow()).to_bytes(&mut buf[0..24]); + (*self.a.borrow()).to_bytes(&mut buf[24..28]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + v: Rc::new(RefCell::new(>::from_bytes(&buf[0..24]))), + a: Rc::new(RefCell::new(::from_bytes(&buf[24..28]))), + } + } +} pub fn main() { std::process::exit(main_0()); } diff --git a/tests/unit/out/refcount/huffman.rs b/tests/unit/out/refcount/huffman.rs index 3a2cc168..89641c8f 100644 --- a/tests/unit/out/refcount/huffman.rs +++ b/tests/unit/out/refcount/huffman.rs @@ -206,7 +206,28 @@ impl MinHeap { } } } -impl ByteRepr for MinHeap {} +impl ByteRepr for MinHeap { + fn to_bytes(&self, buf: &mut [u8]) { + (*self.size.borrow()).to_bytes(&mut buf[0..4]); + (*self.capacity.borrow()).to_bytes(&mut buf[4..8]); + (*self.arr.borrow()).to_bytes(&mut buf[8..16]); + (*self.next.borrow()).to_bytes(&mut buf[16..20]); + (*self.alloc.borrow()).to_bytes(&mut buf[24..32]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + size: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), + capacity: Rc::new(RefCell::new(::from_bytes(&buf[4..8]))), + arr: Rc::new(RefCell::new( + ]>>>>::from_bytes(&buf[8..16]), + )), + next: Rc::new(RefCell::new(::from_bytes(&buf[16..20]))), + alloc: Rc::new(RefCell::new( + >>>::from_bytes(&buf[24..32]), + )), + } + } +} pub fn AllocMinHeap_1(capacity: i32) -> Option> { let capacity: Value = Rc::new(RefCell::new(capacity)); let minHeap: Value>> = diff --git a/tests/unit/out/refcount/implicit_autoref.rs b/tests/unit/out/refcount/implicit_autoref.rs index 498d9fc0..c1cbf5f6 100644 --- a/tests/unit/out/refcount/implicit_autoref.rs +++ b/tests/unit/out/refcount/implicit_autoref.rs @@ -18,7 +18,16 @@ impl Clone for Holder { this } } -impl ByteRepr for Holder {} +impl ByteRepr for Holder { + fn to_bytes(&self, buf: &mut [u8]) { + (*self.v.borrow()).to_bytes(&mut buf[0..24]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + v: Rc::new(RefCell::new(>::from_bytes(&buf[0..24]))), + } + } +} pub fn write_through_0(p: Ptr) { let p: Value> = Rc::new(RefCell::new(p)); (*p.borrow()).write(42); diff --git a/tests/unit/out/refcount/kruskal.rs b/tests/unit/out/refcount/kruskal.rs index d5f88c57..f606c434 100644 --- a/tests/unit/out/refcount/kruskal.rs +++ b/tests/unit/out/refcount/kruskal.rs @@ -287,14 +287,46 @@ impl DisjointSet { } } } -impl ByteRepr for DisjointSet {} +impl ByteRepr for DisjointSet { + fn to_bytes(&self, buf: &mut [u8]) { + (*self.rank.borrow()).to_bytes(&mut buf[0..8]); + (*self.parent.borrow()).to_bytes(&mut buf[8..16]); + (*self.n.borrow()).to_bytes(&mut buf[16..20]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + rank: Rc::new(RefCell::new(>>>::from_bytes( + &buf[0..8], + ))), + parent: Rc::new(RefCell::new(>>>::from_bytes( + &buf[8..16], + ))), + n: Rc::new(RefCell::new(::from_bytes(&buf[16..20]))), + } + } +} #[derive(Default)] pub struct Graph { pub edges: Value>>>, pub V: Value, pub E: Value, } -impl ByteRepr for Graph {} +impl ByteRepr for Graph { + fn to_bytes(&self, buf: &mut [u8]) { + (*self.edges.borrow()).to_bytes(&mut buf[0..8]); + (*self.V.borrow()).to_bytes(&mut buf[8..12]); + (*self.E.borrow()).to_bytes(&mut buf[12..16]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + edges: Rc::new(RefCell::new(>>>::from_bytes( + &buf[0..8], + ))), + V: Rc::new(RefCell::new(::from_bytes(&buf[8..12]))), + E: Rc::new(RefCell::new(::from_bytes(&buf[12..16]))), + } + } +} pub fn MSTKruskal_2(graph: Ptr) -> f64 { ({ let _arr: Ptr>>> = (*graph.upgrade().deref()).edges.as_pointer(); diff --git a/tests/unit/out/refcount/push_emplace_back.rs b/tests/unit/out/refcount/push_emplace_back.rs index 4a96eafd..0ec6ec13 100644 --- a/tests/unit/out/refcount/push_emplace_back.rs +++ b/tests/unit/out/refcount/push_emplace_back.rs @@ -67,7 +67,20 @@ impl Clone for JPEGData { this } } -impl ByteRepr for JPEGData {} +impl ByteRepr for JPEGData { + fn to_bytes(&self, buf: &mut [u8]) { + (*self.com_data.borrow()).to_bytes(&mut buf[0..24]); + (*self.app_data.borrow()).to_bytes(&mut buf[24..48]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + com_data: Rc::new(RefCell::new(>>>::from_bytes(&buf[0..24]))), + app_data: Rc::new(RefCell::new(>>>::from_bytes( + &buf[24..48], + ))), + } + } +} pub fn push_param_0(dest: Ptr>>>) { let dest: Value>>>> = Rc::new(RefCell::new(dest)); ((*dest.borrow()).to_strong().as_pointer() as Ptr>>>).with_mut( diff --git a/tests/unit/out/refcount/tag_vs_identifier_collision.rs b/tests/unit/out/refcount/tag_vs_identifier_collision.rs index 0623f19f..9500524e 100644 --- a/tests/unit/out/refcount/tag_vs_identifier_collision.rs +++ b/tests/unit/out/refcount/tag_vs_identifier_collision.rs @@ -121,7 +121,16 @@ impl ByteRepr for Inner { pub struct Outer { pub field: Value, } -impl ByteRepr for Outer {} +impl ByteRepr for Outer { + fn to_bytes(&self, buf: &mut [u8]) { + (*self.field.borrow()).to_bytes(&mut buf[0..4]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + field: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), + } + } +} #[derive(Default)] pub struct Inner_struct { pub typedef_field: Value, diff --git a/tests/unit/out/refcount/typedef-anon-struct.rs b/tests/unit/out/refcount/typedef-anon-struct.rs index 251d05d8..cc552c42 100644 --- a/tests/unit/out/refcount/typedef-anon-struct.rs +++ b/tests/unit/out/refcount/typedef-anon-struct.rs @@ -44,7 +44,16 @@ impl Clone for Outer { this } } -impl ByteRepr for Outer {} +impl ByteRepr for Outer { + fn to_bytes(&self, buf: &mut [u8]) { + (*self.runs.borrow()).to_bytes(&mut buf[0..24]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + runs: Rc::new(RefCell::new(>::from_bytes(&buf[0..24]))), + } + } +} pub fn main() { std::process::exit(main_0()); } diff --git a/tests/unit/out/refcount/unique_ptr.rs b/tests/unit/out/refcount/unique_ptr.rs index 1bcfc3e4..7f682d42 100644 --- a/tests/unit/out/refcount/unique_ptr.rs +++ b/tests/unit/out/refcount/unique_ptr.rs @@ -15,7 +15,16 @@ impl SafePointer { (*(*self.ptr.borrow_mut()).as_ref().unwrap().borrow_mut()).prefix_inc(); } } -impl ByteRepr for SafePointer {} +impl ByteRepr for SafePointer { + fn to_bytes(&self, buf: &mut [u8]) { + (*self.ptr.borrow()).to_bytes(&mut buf[0..8]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + ptr: Rc::new(RefCell::new(>>::from_bytes(&buf[0..8]))), + } + } +} #[derive(Default)] pub struct Pair { pub x: Value, diff --git a/tests/unit/out/refcount/unique_ptr_const_deref.rs b/tests/unit/out/refcount/unique_ptr_const_deref.rs index d1598432..d7b82b00 100644 --- a/tests/unit/out/refcount/unique_ptr_const_deref.rs +++ b/tests/unit/out/refcount/unique_ptr_const_deref.rs @@ -10,7 +10,16 @@ use std::rc::{Rc, Weak}; pub struct Holder { pub val: Value>>, } -impl ByteRepr for Holder {} +impl ByteRepr for Holder { + fn to_bytes(&self, buf: &mut [u8]) { + (*self.val.borrow()).to_bytes(&mut buf[0..8]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + val: Rc::new(RefCell::new(>>::from_bytes(&buf[0..8]))), + } + } +} pub fn read_val_0(h: Ptr) -> i32 { let h: Value> = Rc::new(RefCell::new(h)); return (*(*(*(*h.borrow()).upgrade().deref()).val.borrow()) diff --git a/tests/unit/out/refcount/unique_ptr_nested.rs b/tests/unit/out/refcount/unique_ptr_nested.rs index 94cfb1d5..d22ddb15 100644 --- a/tests/unit/out/refcount/unique_ptr_nested.rs +++ b/tests/unit/out/refcount/unique_ptr_nested.rs @@ -36,7 +36,16 @@ impl ByteRepr for Inner { pub struct Outer { pub inner: Value>>, } -impl ByteRepr for Outer {} +impl ByteRepr for Outer { + fn to_bytes(&self, buf: &mut [u8]) { + (*self.inner.borrow()).to_bytes(&mut buf[0..8]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + inner: Rc::new(RefCell::new(>>::from_bytes(&buf[0..8]))), + } + } +} pub fn main() { std::process::exit(main_0()); } diff --git a/tests/unit/out/refcount/void_cast.rs b/tests/unit/out/refcount/void_cast.rs index 4a070cbc..49c37c2b 100644 --- a/tests/unit/out/refcount/void_cast.rs +++ b/tests/unit/out/refcount/void_cast.rs @@ -22,7 +22,16 @@ impl Clone for NonTrivial { this } } -impl ByteRepr for NonTrivial {} +impl ByteRepr for NonTrivial { + fn to_bytes(&self, buf: &mut [u8]) { + (*self.data.borrow()).to_bytes(&mut buf[0..24]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + data: Rc::new(RefCell::new(>::from_bytes(&buf[0..24]))), + } + } +} pub fn unused_ref_param_1(x: Ptr) { (*x.upgrade().deref()).clone(); } From b57892acab88c979fbe76b5b35673bc7193cd16d Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Tue, 23 Jun 2026 15:50:05 +0100 Subject: [PATCH 10/29] Add ByteRepr for unions --- cpp2rust/converter/converter_lib.cpp | 2 +- .../converter/models/converter_refcount.cpp | 17 ++++++++++++-- libcc2rs/src/union.rs | 11 ++++++++++ .../refcount/tag_vs_identifier_collision.rs | 22 +++++++++++++++++-- tests/unit/out/refcount/union_basic.rs | 11 +++++++++- .../union_pointer_pun_writethrough.rs | 11 +++++++++- .../out/refcount/union_tagged_struct_arms.rs | 11 +++++++++- 7 files changed, 77 insertions(+), 8 deletions(-) diff --git a/cpp2rust/converter/converter_lib.cpp b/cpp2rust/converter/converter_lib.cpp index 8e9261d0..8695a0b7 100644 --- a/cpp2rust/converter/converter_lib.cpp +++ b/cpp2rust/converter/converter_lib.cpp @@ -211,7 +211,7 @@ bool TypeImplementsByteRepr(clang::QualType qt) { } if (const auto *rd = qt->getAsRecordDecl()) { if (rd->isUnion()) { - return false; + return true; } for (const auto *field : rd->fields()) { if (!TypeImplementsByteRepr(field->getType())) { diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index b6081081..5aec8d34 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -540,6 +540,17 @@ void ConverterRefCount::AddDropTrait(const clang::CXXRecordDecl *decl) { void ConverterRefCount::AddByteReprTrait(const clang::RecordDecl *decl) { auto struct_name = GetRecordName(decl); + if (decl->isUnion()) { + StrCat(std::format("impl ByteRepr for {}", struct_name)); + PushBrace impl_brace(*this); + StrCat( + "fn to_bytes(&self, buf: &mut [u8]) { self.__store.to_bytes(buf); }"); + StrCat(std::format("fn from_bytes(buf: &[u8]) -> Self {{ {} {{ __store: " + "libcc2rs::UnionStorage::from_bytes(buf) }} }}", + struct_name)); + return; + } + if (!TypeImplementsByteRepr(ctx_.getCanonicalTagType(decl))) { StrCat(std::format("impl ByteRepr for {}", struct_name)); PushBrace brace(*this); @@ -568,16 +579,18 @@ void ConverterRefCount::AddByteReprTrait(const clang::RecordDecl *decl) { StrCat("fn from_bytes(buf: &[u8]) -> Self"); { PushBrace fn_brace(*this); - PushConversionKind push(*this, ConversionKind::FullRefCount); StrCat("Self"); PushBrace lit_brace(*this); unsigned idx = 0; for (auto *field : decl->fields()) { auto byte_off = layout.getFieldOffset(idx) / 8; auto byte_size = ctx_.getTypeSize(field->getType()) / 8; + PushConversionKind push(*this, ConversionKind::FullRefCount); + std::string storage_ty = ToString(field->getType()); + Unwrap(storage_ty, "Value<", ">"); StrCat(std::format( "{}: Rc::new(RefCell::new(<{}>::from_bytes(&buf[{}..{}]))),", - GetNamedDeclAsString(field), ToString(field->getType()), byte_off, + GetNamedDeclAsString(field), storage_ty, byte_off, byte_off + byte_size)); ++idx; } diff --git a/libcc2rs/src/union.rs b/libcc2rs/src/union.rs index 2501ebbf..759ace7e 100644 --- a/libcc2rs/src/union.rs +++ b/libcc2rs/src/union.rs @@ -32,3 +32,14 @@ impl Clone for UnionStorage { } } } + +impl ByteRepr for UnionStorage { + fn to_bytes(&self, buf: &mut [u8]) { + buf.copy_from_slice(&self.bytes.borrow()); + } + fn from_bytes(buf: &[u8]) -> Self { + UnionStorage { + bytes: Rc::new(RefCell::new(buf.to_vec())), + } + } +} diff --git a/tests/unit/out/refcount/tag_vs_identifier_collision.rs b/tests/unit/out/refcount/tag_vs_identifier_collision.rs index 9500524e..b4647d30 100644 --- a/tests/unit/out/refcount/tag_vs_identifier_collision.rs +++ b/tests/unit/out/refcount/tag_vs_identifier_collision.rs @@ -66,7 +66,16 @@ impl Default for point { } } } -impl ByteRepr for point {} +impl ByteRepr for point { + fn to_bytes(&self, buf: &mut [u8]) { + self.__store.to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { + point { + __store: libcc2rs::UnionStorage::from_bytes(buf), + } + } +} #[derive(Clone)] pub struct slot_union { __store: libcc2rs::UnionStorage, @@ -86,7 +95,16 @@ impl Default for slot_union { } } } -impl ByteRepr for slot_union {} +impl ByteRepr for slot_union { + fn to_bytes(&self, buf: &mut [u8]) { + self.__store.to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { + slot_union { + __store: libcc2rs::UnionStorage::from_bytes(buf), + } + } +} #[derive(Clone, Copy, PartialEq, Debug, Default)] enum slot { #[default] diff --git a/tests/unit/out/refcount/union_basic.rs b/tests/unit/out/refcount/union_basic.rs index f6fe7b26..80196a86 100644 --- a/tests/unit/out/refcount/union_basic.rs +++ b/tests/unit/out/refcount/union_basic.rs @@ -25,7 +25,16 @@ impl Default for basic { } } } -impl ByteRepr for basic {} +impl ByteRepr for basic { + fn to_bytes(&self, buf: &mut [u8]) { + self.__store.to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { + basic { + __store: libcc2rs::UnionStorage::from_bytes(buf), + } + } +} pub fn main() { std::process::exit(main_0()); } diff --git a/tests/unit/out/refcount/union_pointer_pun_writethrough.rs b/tests/unit/out/refcount/union_pointer_pun_writethrough.rs index 6ff3165c..0683de06 100644 --- a/tests/unit/out/refcount/union_pointer_pun_writethrough.rs +++ b/tests/unit/out/refcount/union_pointer_pun_writethrough.rs @@ -30,7 +30,16 @@ fn main_0() -> i32 { } } } - impl ByteRepr for anon_0 {}; + impl ByteRepr for anon_0 { + fn to_bytes(&self, buf: &mut [u8]) { + self.__store.to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { + anon_0 { + __store: libcc2rs::UnionStorage::from_bytes(buf), + } + } + }; let pp: Value = >::default(); (*pp.borrow_mut()).as_signed().write((x.as_pointer())); ((*pp.borrow()).as_unsigned().read()).write(42_u64); diff --git a/tests/unit/out/refcount/union_tagged_struct_arms.rs b/tests/unit/out/refcount/union_tagged_struct_arms.rs index 6c4cc0d5..dc80fb93 100644 --- a/tests/unit/out/refcount/union_tagged_struct_arms.rs +++ b/tests/unit/out/refcount/union_tagged_struct_arms.rs @@ -102,7 +102,16 @@ impl Default for anon_0 { } } } -impl ByteRepr for anon_0 {} +impl ByteRepr for anon_0 { + fn to_bytes(&self, buf: &mut [u8]) { + self.__store.to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { + anon_0 { + __store: libcc2rs::UnionStorage::from_bytes(buf), + } + } +} #[derive(Default)] pub struct Branch { pub choice: Value, From aa518050a49636db748b004c90486a31864ace3a Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Tue, 23 Jun 2026 16:03:03 +0100 Subject: [PATCH 11/29] Memcpy a poitner to a struct through ErasedPtr --- libcc2rs/src/fn_ptr.rs | 16 +++----- libcc2rs/src/rc.rs | 90 +++++++++--------------------------------- 2 files changed, 23 insertions(+), 83 deletions(-) diff --git a/libcc2rs/src/fn_ptr.rs b/libcc2rs/src/fn_ptr.rs index 2ccc150e..e7152279 100644 --- a/libcc2rs/src/fn_ptr.rs +++ b/libcc2rs/src/fn_ptr.rs @@ -6,7 +6,7 @@ use std::marker::PhantomData; use std::ops::Deref; use std::rc::Rc; -use crate::rc::{AnyPtr, ErasedPtr}; +use crate::rc::{AnyPtr, ErasedPtr, Ptr}; use crate::reinterpret::ByteRepr; pub trait FnAddr { @@ -146,20 +146,14 @@ impl Eq for FnPtr {} impl ByteRepr for FnPtr {} impl ErasedPtr for FnPtr { - fn pointee_type_id(&self) -> TypeId { - TypeId::of::() - } - fn memcpy(&self, _src: &dyn ErasedPtr, _len: usize) { - panic!("memcpy not supported on fn pointer"); + fn as_bytes(&self) -> Ptr { + panic!("byte view not supported on fn pointer"); } fn as_any(&self) -> &dyn Any { self } - fn equals(&self, other: &dyn ErasedPtr) -> Option { - if self.pointee_type_id() != other.pointee_type_id() { - return None; - } - other.as_any().downcast_ref::>().map(|o| self == o) + fn equals(&self, other: &dyn ErasedPtr) -> bool { + other.as_any().downcast_ref::>() == Some(self) } fn is_null(&self) -> bool { FnPtr::is_null(self) diff --git a/libcc2rs/src/rc.rs b/libcc2rs/src/rc.rs index 71f0c993..f881cf4e 100644 --- a/libcc2rs/src/rc.rs +++ b/libcc2rs/src/rc.rs @@ -1031,49 +1031,33 @@ impl Ptr { } pub(crate) trait ErasedPtr: std::any::Any { - fn pointee_type_id(&self) -> std::any::TypeId; - fn memcpy(&self, src: &dyn ErasedPtr, len: usize); + fn as_bytes(&self) -> Ptr; fn as_any(&self) -> &dyn std::any::Any; - fn equals(&self, other: &dyn ErasedPtr) -> Option; + fn equals(&self, other: &dyn ErasedPtr) -> bool; fn is_null(&self) -> bool; } +impl PartialEq for dyn ErasedPtr { + fn eq(&self, other: &Self) -> bool { + self.equals(other) + } +} + impl ErasedPtr for Ptr where T: ByteRepr + 'static, Ptr: PartialEq, { - fn pointee_type_id(&self) -> std::any::TypeId { - std::any::TypeId::of::() - } - - fn memcpy(&self, src: &dyn ErasedPtr, len: usize) { - if self.pointee_type_id() != src.pointee_type_id() { - panic!("memcpy: type mismatch"); - } - let src_ptr = src - .as_any() - .downcast_ref::>() - .expect("memcpy: downcast to Ptr failed"); - let dst_bytes: Ptr = self.reinterpret_cast(); - let src_bytes: Ptr = src_ptr.reinterpret_cast(); - dst_bytes.memcpy(&src_bytes, len); + fn as_bytes(&self) -> Ptr { + self.reinterpret_cast::() } fn as_any(&self) -> &dyn std::any::Any { self } - fn equals(&self, other: &dyn ErasedPtr) -> Option { - if self.pointee_type_id() != other.pointee_type_id() { - return None; - } - - if let Some(other_ptr) = other.as_any().downcast_ref::>() { - return Some(self == other_ptr); - } - - None + fn equals(&self, other: &dyn ErasedPtr) -> bool { + other.as_any().downcast_ref::>() == Some(self) } fn is_null(&self) -> bool { @@ -1107,66 +1091,28 @@ impl AnyPtr { } self.ptr.as_any().downcast_ref::>().cloned() } - - pub fn reinterpret_cast(&self) -> Ptr { - macro_rules! try_src { - ($ty:ty) => {{ - if let Some(p) = self.cast::<$ty>() { - return p.reinterpret_cast::(); - } - if let Some(pv) = self.cast::>() { - return pv.reinterpret_cast::(); - } - }}; - } - - try_src!(u8); - try_src!(i8); - try_src!(u16); - try_src!(i16); - try_src!(u32); - try_src!(i32); - try_src!(u64); - try_src!(i64); - try_src!(usize); - try_src!(isize); - - panic!("reinterpret_cast: unsupported AnyPtr source"); - } } impl PartialEq for AnyPtr { fn eq(&self, other: &Self) -> bool { - let lhs: &dyn ErasedPtr = self.ptr.as_ref(); - let rhs: &dyn ErasedPtr = other.ptr.as_ref(); - - lhs.equals(rhs).unwrap_or_default() + *self.ptr == *other.ptr } } impl AnyPtr { pub fn memcpy(&self, src: &AnyPtr, len: usize) { - let dst_erased = &*self.ptr; - let src_erased = &*src.ptr; - - if dst_erased.pointee_type_id() == src_erased.pointee_type_id() { - dst_erased.memcpy(src_erased, len); - return; - } - - let dst_u8: Ptr = self.reinterpret_cast(); - let src_u8: Ptr = src.reinterpret_cast(); + let dst_u8 = self.ptr.as_bytes(); + let src_u8 = src.ptr.as_bytes(); dst_u8.memcpy(&src_u8, len); } pub fn memset(&self, value: u8, num: usize) { - let dst_u8: Ptr = self.reinterpret_cast(); - dst_u8.memset(value, num); + self.ptr.as_bytes().memset(value, num); } pub fn memcmp(&self, other: &AnyPtr, len: usize) -> i32 { - let a: Ptr = self.reinterpret_cast(); - let b: Ptr = other.reinterpret_cast(); + let a = self.ptr.as_bytes(); + let b = other.ptr.as_bytes(); a.memcmp(&b, len) } } From 88e4868782772e7e1721c9c622478c6feb7aa711 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 24 Jun 2026 11:24:21 +0100 Subject: [PATCH 12/29] Fix arrays in unions --- cpp2rust/converter/models/converter_refcount.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index 5aec8d34..8155dc8a 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -497,9 +497,12 @@ void ConverterRefCount::EmitRustUnion(clang::RecordDecl *decl) { { PushBrace impl_brace(*this); for (auto *field : decl->fields()) { + PushConversionKind push(*this, ConversionKind::FullRefCount); + std::string storage_ty = ToString(field->getType()); + Unwrap(storage_ty, "Value<", ">"); StrCat(std::format( "pub fn {}(&self) -> Ptr<{}> {{ self.__store.reinterpret(0) }}", - GetNamedDeclAsString(field), Mapper::Map(field->getType()))); + GetNamedDeclAsString(field), storage_ty)); } } From 4cae8e2c5bdaffcdb02ed4f5b24a304298d743d4 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 24 Jun 2026 11:32:53 +0100 Subject: [PATCH 13/29] Use C size when size_of diverges between C and Rust --- cpp2rust/converter/converter_lib.cpp | 12 ++++++++++++ cpp2rust/converter/converter_lib.h | 2 ++ cpp2rust/converter/models/converter_refcount.cpp | 14 ++++++++++++++ cpp2rust/converter/models/converter_refcount.h | 3 +++ 4 files changed, 31 insertions(+) diff --git a/cpp2rust/converter/converter_lib.cpp b/cpp2rust/converter/converter_lib.cpp index 8695a0b7..415601c3 100644 --- a/cpp2rust/converter/converter_lib.cpp +++ b/cpp2rust/converter/converter_lib.cpp @@ -223,6 +223,18 @@ bool TypeImplementsByteRepr(clang::QualType qt) { return false; } +bool RustSizeDivergesFromC(clang::QualType qt) { + qt = qt.getCanonicalType(); + // Records have Rc> fields that diverge from the C size + if (qt->isRecordType()) { + return true; + } + if (auto *arr = qt->getAsArrayTypeUnsafe()) { + return RustSizeDivergesFromC(arr->getElementType()); + } + return false; +} + bool IsMutatingCall(const clang::CallExpr *expr) { if (auto *callee = expr->getDirectCallee()) { if (auto *method = clang::dyn_cast(callee)) { diff --git a/cpp2rust/converter/converter_lib.h b/cpp2rust/converter/converter_lib.h index 14463f13..cd7e9d5a 100644 --- a/cpp2rust/converter/converter_lib.h +++ b/cpp2rust/converter/converter_lib.h @@ -53,6 +53,8 @@ bool IsMut(clang::QualType qual_type); bool TypeImplementsByteRepr(clang::QualType qt); +bool RustSizeDivergesFromC(clang::QualType qt); + bool IsMutatingCall(const clang::CallExpr *expr); bool IsOverloadedFunction(const clang::FunctionDecl *decl); diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index 8155dc8a..b1ae2d33 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -1302,6 +1302,20 @@ bool ConverterRefCount::VisitExplicitCastExpr(clang::ExplicitCastExpr *expr) { } } +bool ConverterRefCount::VisitUnaryExprOrTypeTraitExpr( + clang::UnaryExprOrTypeTraitExpr *expr) { + if (expr->getKind() == clang::UnaryExprOrTypeTrait::UETT_SizeOf) { + auto arg_type = expr->isArgumentType() ? expr->getArgumentType() + : expr->getArgumentExpr()->getType(); + if (RustSizeDivergesFromC(arg_type)) { + StrCat(std::format("{}usize", ctx_.getTypeSize(arg_type) / 8)); + computed_expr_type_ = ComputedExprType::FreshValue; + return false; + } + } + return Converter::VisitUnaryExprOrTypeTraitExpr(expr); +} + bool ConverterRefCount::VisitStmtExpr(clang::StmtExpr *expr) { PushConversionKind push(*this, ConversionKind::FullRefCount); return Converter::VisitStmtExpr(expr); diff --git a/cpp2rust/converter/models/converter_refcount.h b/cpp2rust/converter/models/converter_refcount.h index 7430c544..600e6026 100644 --- a/cpp2rust/converter/models/converter_refcount.h +++ b/cpp2rust/converter/models/converter_refcount.h @@ -41,6 +41,9 @@ class ConverterRefCount final : public Converter { void AddByteReprTrait(const clang::RecordDecl *decl) override; + bool + VisitUnaryExprOrTypeTraitExpr(clang::UnaryExprOrTypeTraitExpr *expr) override; + void AddDefaultTrait(const clang::RecordDecl *decl) override; void AddDefaultTraitForUnion(const clang::RecordDecl *decl) override; From 7cd416174b40ba797f91bd2e76b2f270715a1318 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 24 Jun 2026 11:34:07 +0100 Subject: [PATCH 14/29] Add byte_size in ByteRepr to capture C size --- .../converter/models/converter_refcount.cpp | 5 + libcc2rs/src/rc.rs | 104 ++++++++++-------- libcc2rs/src/reinterpret.rs | 14 ++- 3 files changed, 74 insertions(+), 49 deletions(-) diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index b1ae2d33..5156a730 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -546,6 +546,8 @@ void ConverterRefCount::AddByteReprTrait(const clang::RecordDecl *decl) { if (decl->isUnion()) { StrCat(std::format("impl ByteRepr for {}", struct_name)); PushBrace impl_brace(*this); + StrCat(std::format("fn byte_size() -> usize {{ {} }}", + ctx_.getTypeSize(ctx_.getCanonicalTagType(decl)) / 8)); StrCat( "fn to_bytes(&self, buf: &mut [u8]) { self.__store.to_bytes(buf); }"); StrCat(std::format("fn from_bytes(buf: &[u8]) -> Self {{ {} {{ __store: " @@ -565,6 +567,9 @@ void ConverterRefCount::AddByteReprTrait(const clang::RecordDecl *decl) { const auto &layout = ctx_.getASTRecordLayout(decl); + StrCat(std::format("fn byte_size() -> usize {{ {} }}", + ctx_.getTypeSize(ctx_.getCanonicalTagType(decl)) / 8)); + StrCat("fn to_bytes(&self, buf: &mut [u8])"); { PushBrace fn_brace(*this); diff --git a/libcc2rs/src/rc.rs b/libcc2rs/src/rc.rs index f881cf4e..64fd4b72 100644 --- a/libcc2rs/src/rc.rs +++ b/libcc2rs/src/rc.rs @@ -16,6 +16,13 @@ use crate::reinterpret::{ByteRepr, OriginalAlloc, SingleOriginalAlloc, SliceOrig pub type Value = Rc>; +struct ReinterpretedView { + // Pointer to the source of reinterpret + alloc: Rc, + // C++ size of the reinterpreted view + elem_byte_size: usize, +} + #[derive(Default)] enum PtrKind { #[default] @@ -25,7 +32,7 @@ enum PtrKind { HeapSingle(Weak>), HeapArray(Weak>>), Vec(Weak>>), - Reinterpreted(Rc), + Reinterpreted(Rc), } pub enum StrongPtr { @@ -59,7 +66,7 @@ impl StrongPtr { cell, } => { // Read-through: always re-read from the original allocation. - let mut buf = vec![0u8; std::mem::size_of::()]; + let mut buf = vec![0u8; T::byte_size()]; alloc.read_bytes(*byte_offset, &mut buf); *cell.borrow_mut() = Some(T::from_bytes(&buf)); Ref::map(cell.borrow(), |opt| opt.as_ref().unwrap()) @@ -77,8 +84,8 @@ impl fmt::Debug for PtrKind { PtrKind::HeapSingle(w) => write!(f, "HeapSingle({:?})", w.as_ptr()), PtrKind::StackArray(w) => write!(f, "StackArray({:?})", w.as_ptr()), PtrKind::HeapArray(w) => write!(f, "HeapArray({:?})", w.as_ptr()), - PtrKind::Reinterpreted(data) => { - write!(f, "Reinterpreted(0x{:x})", data.address()) + PtrKind::Reinterpreted(view) => { + write!(f, "Reinterpreted(0x{:x})", view.alloc.address()) } } } @@ -93,7 +100,7 @@ impl Clone for PtrKind { PtrKind::HeapSingle(weak) => PtrKind::HeapSingle(weak.clone()), PtrKind::StackArray(weak) => PtrKind::StackArray(weak.clone()), PtrKind::HeapArray(weak) => PtrKind::HeapArray(weak.clone()), - PtrKind::Reinterpreted(data) => PtrKind::Reinterpreted(Rc::clone(data)), + PtrKind::Reinterpreted(view) => PtrKind::Reinterpreted(Rc::clone(view)), } } } @@ -105,7 +112,7 @@ impl PtrKind { PtrKind::StackSingle(w) | PtrKind::HeapSingle(w) => w.as_ptr() as usize, PtrKind::Vec(w) => w.as_ptr() as usize, PtrKind::StackArray(w) | PtrKind::HeapArray(w) => w.as_ptr() as usize, - PtrKind::Reinterpreted(data) => data.address(), + PtrKind::Reinterpreted(view) => view.alloc.address(), } } } @@ -251,40 +258,40 @@ impl Ptr { #[inline] fn elem_step(&self) -> usize { match &self.kind { - PtrKind::Reinterpreted(_) => std::mem::size_of::(), + PtrKind::Reinterpreted(view) => view.elem_byte_size, _ => 1, } } #[inline] pub fn len(&self) -> usize { - match self.kind { + match &self.kind { PtrKind::Null => 0, PtrKind::StackSingle(_) | PtrKind::HeapSingle(_) => 1, - PtrKind::Vec(ref weak) => weak.upgrade().expect("ub: dangling pointer").borrow().len(), - PtrKind::StackArray(ref weak) | PtrKind::HeapArray(ref weak) => { + PtrKind::Vec(weak) => weak.upgrade().expect("ub: dangling pointer").borrow().len(), + PtrKind::StackArray(weak) | PtrKind::HeapArray(weak) => { weak.upgrade().expect("ub: dangling pointer").borrow().len() } - PtrKind::Reinterpreted(ref data) => data.total_byte_len() / std::mem::size_of::(), + PtrKind::Reinterpreted(view) => view.alloc.total_byte_len() / view.elem_byte_size, } } #[inline] pub fn is_empty(&self) -> bool { - match self.kind { + match &self.kind { PtrKind::Null => true, PtrKind::StackSingle(_) | PtrKind::HeapSingle(_) => false, - PtrKind::Vec(ref weak) => weak + PtrKind::Vec(weak) => weak .upgrade() .expect("ub: dangling pointer") .borrow() .is_empty(), - PtrKind::StackArray(ref weak) | PtrKind::HeapArray(ref weak) => weak + PtrKind::StackArray(weak) | PtrKind::HeapArray(weak) => weak .upgrade() .expect("ub: dangling pointer") .borrow() .is_empty(), - PtrKind::Reinterpreted(ref data) => self.offset >= data.total_byte_len(), + PtrKind::Reinterpreted(view) => self.offset >= view.alloc.total_byte_len(), } } @@ -339,8 +346,8 @@ impl Ptr { rc: weak.upgrade().expect("ub: dangling pointer"), offset: self.offset, }, - PtrKind::Reinterpreted(data) => StrongPtr::Reinterpreted { - alloc: Rc::clone(data), + PtrKind::Reinterpreted(view) => StrongPtr::Reinterpreted { + alloc: Rc::clone(&view.alloc), byte_offset: self.offset, cell: RefCell::new(None), }, @@ -365,10 +372,10 @@ impl Ptr { let rc = weak.upgrade().expect("ub: dangling pointer"); rc.borrow_mut()[self.offset] = value; } - PtrKind::Reinterpreted(data) => { - let mut buf = vec![0u8; std::mem::size_of::()]; + PtrKind::Reinterpreted(view) => { + let mut buf = vec![0u8; T::byte_size()]; value.to_bytes(&mut buf); - data.write_bytes(self.offset, &buf); + view.alloc.write_bytes(self.offset, &buf); } } } @@ -391,30 +398,34 @@ impl Ptr { return self_any.downcast_ref::>().unwrap().clone(); } - if std::mem::size_of::() == 0 { + if U::byte_size() == 0 { panic!("cannot reinterpret_cast to zero-sized type"); } + let src_byte_off = self.offset.wrapping_mul(T::byte_size()); let (alloc, abs_byte_off): (Rc, usize) = match &self.kind { PtrKind::Null => return Ptr::null(), PtrKind::StackSingle(weak) | PtrKind::HeapSingle(weak) => ( Rc::new(SingleOriginalAlloc { weak: weak.clone() }), - self.byte_offset(), + src_byte_off, ), PtrKind::Vec(weak) => ( Rc::new(SliceOriginalAlloc { weak: weak.clone() }), - self.byte_offset(), + src_byte_off, ), PtrKind::StackArray(weak) | PtrKind::HeapArray(weak) => ( Rc::new(SliceOriginalAlloc { weak: weak.clone() }), - self.byte_offset(), + src_byte_off, ), - PtrKind::Reinterpreted(data) => (Rc::clone(data), self.offset), + PtrKind::Reinterpreted(view) => (Rc::clone(&view.alloc), self.offset), }; Ptr { offset: abs_byte_off, - kind: PtrKind::Reinterpreted(alloc), + kind: PtrKind::Reinterpreted(Rc::new(ReinterpretedView { + alloc, + elem_byte_size: U::byte_size(), + })), } } } @@ -441,13 +452,13 @@ impl Ptr { let mut borrow = rc.borrow_mut(); f(&mut borrow[self.offset]) } - PtrKind::Reinterpreted(data) => { - let mut buf = vec![0u8; std::mem::size_of::()]; - data.read_bytes(self.offset, &mut buf); + PtrKind::Reinterpreted(view) => { + let mut buf = vec![0u8; T::byte_size()]; + view.alloc.read_bytes(self.offset, &mut buf); let mut val = T::from_bytes(&buf); let ret = f(&mut val); val.to_bytes(&mut buf); - data.write_bytes(self.offset, &buf); + view.alloc.write_bytes(self.offset, &buf); ret } } @@ -474,9 +485,9 @@ impl Ptr { let borrow = rc.borrow(); f(&borrow[self.offset]) } - PtrKind::Reinterpreted(data) => { - let mut buf = vec![0u8; std::mem::size_of::()]; - data.read_bytes(self.offset, &mut buf); + PtrKind::Reinterpreted(view) => { + let mut buf = vec![0u8; T::byte_size()]; + view.alloc.read_bytes(self.offset, &mut buf); let val = T::from_bytes(&buf); f(&val) } @@ -501,9 +512,9 @@ impl Ptr { PtrKind::StackArray(ref weak) | PtrKind::HeapArray(ref weak) => { weak.upgrade().expect("ub: dangling pointer").borrow()[self.offset].clone() } - PtrKind::Reinterpreted(ref data) => { - let mut buf = vec![0u8; std::mem::size_of::()]; - data.read_bytes(self.offset, &mut buf); + PtrKind::Reinterpreted(ref view) => { + let mut buf = vec![0u8; T::byte_size()]; + view.alloc.read_bytes(self.offset, &mut buf); T::from_bytes(&buf) } } @@ -535,7 +546,7 @@ impl Ptr { let strong = weak.upgrade().expect("ub: dangling pointer"); (*strong.borrow_mut())[self.get_offset()..last].sort(); } - PtrKind::Reinterpreted(..) => { + PtrKind::Reinterpreted(_) => { panic!("sorting not supported for reinterpreted pointers") } } @@ -580,7 +591,7 @@ impl Ptr { let mut borrow = strong.borrow_mut(); sort(&mut borrow, self.get_offset(), last, &mut cmp); } - PtrKind::Reinterpreted(..) => { + PtrKind::Reinterpreted(_) => { panic!("sorting not supported for reinterpreted pointers") } } @@ -856,7 +867,7 @@ impl ToOwnedOption for Ptr { } PtrKind::Vec(_) => panic!("Can't own a vector"), PtrKind::HeapArray(_) => panic!("Can't own an array variable as single"), - PtrKind::Reinterpreted(..) => panic!("Can't own a reinterpreted pointer"), + PtrKind::Reinterpreted(_) => panic!("Can't own a reinterpreted pointer"), } } } @@ -882,7 +893,7 @@ impl ToOwnedOption> for Ptr { } PtrKind::Vec(_) => panic!("Can't own a vector"), PtrKind::HeapSingle(_) => panic!("Can't own a single variable as an array"), - PtrKind::Reinterpreted(..) => panic!("Can't own a reinterpreted pointer"), + PtrKind::Reinterpreted(_) => panic!("Can't own a reinterpreted pointer"), } } } @@ -898,7 +909,7 @@ impl fmt::Debug for Ptr { (Weak::as_ptr(w) as usize).wrapping_add(self.byte_offset()) } PtrKind::Vec(w) => (Weak::as_ptr(w) as usize).wrapping_add(self.byte_offset()), - PtrKind::Reinterpreted(data) => data.address().wrapping_add(self.byte_offset()), + PtrKind::Reinterpreted(view) => view.alloc.address().wrapping_add(self.byte_offset()), }; write!(f, "0x{:x}", addr) } @@ -994,9 +1005,9 @@ impl Ptr { let raw = strong.borrow(); raw[start..end].to_vec() } - PtrKind::Reinterpreted(ref data) => { + PtrKind::Reinterpreted(ref view) => { let mut buf = vec![0u8; end.wrapping_sub(start)]; - data.read_bytes(start, &mut buf); + view.alloc.read_bytes(start, &mut buf); buf } } @@ -1192,11 +1203,14 @@ impl AsPointerDyn for Rc> { impl ByteRepr for Ptr {} -impl Ptr { +impl Ptr { pub(crate) fn reinterpreted(alloc: Rc, byte_offset: usize) -> Self { Ptr { offset: byte_offset, - kind: PtrKind::Reinterpreted(alloc), + kind: PtrKind::Reinterpreted(Rc::new(ReinterpretedView { + alloc, + elem_byte_size: T::byte_size(), + })), } } } diff --git a/libcc2rs/src/reinterpret.rs b/libcc2rs/src/reinterpret.rs index 29c91f63..623c7060 100644 --- a/libcc2rs/src/reinterpret.rs +++ b/libcc2rs/src/reinterpret.rs @@ -4,6 +4,12 @@ use std::{cell::RefCell, rc::Weak}; pub trait ByteRepr: 'static { + fn byte_size() -> usize + where + Self: Sized, + { + std::mem::size_of::() + } fn to_bytes(&self, _buf: &mut [u8]) { panic!("ByteRepr not supported for this type"); } @@ -98,7 +104,7 @@ pub trait OriginalAlloc { // Only serializes the overlapping elements, not the whole slice. fn slice_read_bytes(slice: &[S], byte_offset: usize, buf: &mut [u8]) { let len = buf.len(); - let elem_size = std::mem::size_of::(); + let elem_size = S::byte_size(); let first_elem = byte_offset / elem_size; let last_elem = (byte_offset + len).div_ceil(elem_size); let tmp_len = (last_elem - first_elem) * elem_size; @@ -113,7 +119,7 @@ fn slice_read_bytes(slice: &[S], byte_offset: usize, buf: &mut [u8] // Write `data` at `byte_offset` into a slice of S elements. // Only deserializes/reserializes the overlapping elements. fn slice_write_bytes(slice: &mut [S], byte_offset: usize, data: &[u8]) { - let elem_size = std::mem::size_of::(); + let elem_size = S::byte_size(); let mut elem_buf = vec![0u8; elem_size]; let first_elem = byte_offset / elem_size; let num_elem = data.len().div_ceil(elem_size); @@ -151,7 +157,7 @@ impl OriginalAlloc for SingleOriginalAlloc { } fn total_byte_len(&self) -> usize { - std::mem::size_of::() + T::byte_size() } fn address(&self) -> usize { @@ -205,7 +211,7 @@ impl OriginalAlloc for SliceOriginalAlloc { fn total_byte_len(&self) -> usize { let rc = self.weak.upgrade().expect("ub: dangling pointer"); let val = rc.borrow(); - std::mem::size_of_val(val.as_slice()) + val.as_slice().len() * ::byte_size() } fn address(&self) -> usize { From f59af63010d77600ac19a9bcf6364b845b3233e6 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 24 Jun 2026 11:44:26 +0100 Subject: [PATCH 15/29] Update tests --- .../out/refcount/cross_tu_tag_collision.rs | 3 +++ tests/unit/out/refcount/addr_of_global.rs | 3 +++ tests/unit/out/refcount/anonymous-struct.rs | 27 +++++++++++++++++++ tests/unit/out/refcount/anonymous-struct_c.rs | 27 +++++++++++++++++++ tests/unit/out/refcount/anonymous_enum.rs | 3 +++ tests/unit/out/refcount/anonymous_enum_c.rs | 3 +++ tests/unit/out/refcount/array_const_init.rs | 3 +++ .../out/refcount/array_of_noncopy_struct.rs | 3 +++ tests/unit/out/refcount/bounded_struct_ptr.rs | 3 +++ tests/unit/out/refcount/c_struct.rs | 9 +++++++ tests/unit/out/refcount/class.rs | 6 +++++ tests/unit/out/refcount/class_templates.rs | 9 +++++++ tests/unit/out/refcount/clone_vs_move.rs | 3 +++ tests/unit/out/refcount/complex_function.rs | 3 +++ tests/unit/out/refcount/exprs.rs | 3 +++ tests/unit/out/refcount/fft.rs | 3 +++ tests/unit/out/refcount/fn_ptr_stable_sort.rs | 3 +++ .../refcount/foreach_disjoint_field_borrow.rs | 3 +++ .../unit/out/refcount/function_overloading.rs | 3 +++ .../refcount/global_without_initializer.rs | 3 +++ .../out/refcount/goto_aggregate_default.rs | 3 +++ tests/unit/out/refcount/huffman.rs | 3 +++ .../refcount/immutable-deref-on-func-call.rs | 3 +++ tests/unit/out/refcount/implicit_autoref.rs | 3 +++ tests/unit/out/refcount/init.rs | 3 +++ tests/unit/out/refcount/kruskal.rs | 9 +++++++ .../refcount/local_anon_struct_collision.rs | 6 +++++ .../unit/out/refcount/memcpy_struct_struct.rs | 7 ++--- tests/unit/out/refcount/nested_structs.rs | 18 +++++++++++++ tests/unit/out/refcount/new_struct.rs | 3 +++ tests/unit/out/refcount/operator_less_than.rs | 3 +++ tests/unit/out/refcount/pod.rs | 3 +++ tests/unit/out/refcount/pointers.rs | 3 +++ tests/unit/out/refcount/polymorphism.rs | 6 +++++ tests/unit/out/refcount/push_emplace_back.rs | 6 +++++ tests/unit/out/refcount/random.rs | 3 +++ .../out/refcount/reinterpret_cast_struct.rs | 3 +++ .../reinterpret_cast_struct_to_struct.rs | 6 +++++ tests/unit/out/refcount/reserved_keywords.rs | 3 +++ .../unit/out/refcount/static_var_in_class.rs | 6 +++++ tests/unit/out/refcount/struct_ctor.rs | 3 +++ tests/unit/out/refcount/struct_ptr.rs | 3 +++ .../refcount/tag_vs_identifier_collision.rs | 18 +++++++++++++ .../unit/out/refcount/typedef-anon-struct.rs | 6 +++++ tests/unit/out/refcount/union_basic.rs | 3 +++ .../union_pointer_pun_writethrough.rs | 3 +++ .../out/refcount/union_tagged_struct_arms.rs | 9 +++++++ tests/unit/out/refcount/unique_ptr.rs | 6 +++++ .../out/refcount/unique_ptr_const_deref.rs | 3 +++ tests/unit/out/refcount/unique_ptr_nested.rs | 6 +++++ tests/unit/out/refcount/unique_ptr_struct.rs | 3 +++ tests/unit/out/refcount/va_arg_struct_ctx.rs | 3 +++ tests/unit/out/refcount/void_cast.rs | 6 +++++ tests/unit/union_cross_arm_cast.c | 2 +- tests/unit/union_nested.c | 2 +- tests/unit/union_pointer_pun_address.c | 2 +- tests/unit/union_struct_dual_use.c | 2 +- 57 files changed, 296 insertions(+), 7 deletions(-) diff --git a/tests/multi-file/cross_tu_tag_collision/out/refcount/cross_tu_tag_collision.rs b/tests/multi-file/cross_tu_tag_collision/out/refcount/cross_tu_tag_collision.rs index 5fd97a8f..457ab0e5 100644 --- a/tests/multi-file/cross_tu_tag_collision/out/refcount/cross_tu_tag_collision.rs +++ b/tests/multi-file/cross_tu_tag_collision/out/refcount/cross_tu_tag_collision.rs @@ -11,6 +11,9 @@ pub struct widget { pub id: Value, } impl ByteRepr for widget { + fn byte_size() -> usize { + 4 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.id.borrow()).to_bytes(&mut buf[0..4]); } diff --git a/tests/unit/out/refcount/addr_of_global.rs b/tests/unit/out/refcount/addr_of_global.rs index 01ddb7f7..0d03ca3b 100644 --- a/tests/unit/out/refcount/addr_of_global.rs +++ b/tests/unit/out/refcount/addr_of_global.rs @@ -19,6 +19,9 @@ impl Clone for Inner { } } impl ByteRepr for Inner { + fn byte_size() -> usize { + 4 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.value.borrow()).to_bytes(&mut buf[0..4]); } diff --git a/tests/unit/out/refcount/anonymous-struct.rs b/tests/unit/out/refcount/anonymous-struct.rs index 159d05a6..ad257c16 100644 --- a/tests/unit/out/refcount/anonymous-struct.rs +++ b/tests/unit/out/refcount/anonymous-struct.rs @@ -21,6 +21,9 @@ impl Clone for Outer_Named { } } impl ByteRepr for Outer_Named { + fn byte_size() -> usize { + 8 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.a.borrow()).to_bytes(&mut buf[0..4]); (*self.b.borrow()).to_bytes(&mut buf[4..8]); @@ -47,6 +50,9 @@ impl Clone for anon_0 { } } impl ByteRepr for anon_0 { + fn byte_size() -> usize { + 8 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.c.borrow()).to_bytes(&mut buf[0..4]); (*self.d.borrow()).to_bytes(&mut buf[4..8]); @@ -73,6 +79,9 @@ impl Clone for anon_1 { } } impl ByteRepr for anon_1 { + fn byte_size() -> usize { + 8 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.g.borrow()).to_bytes(&mut buf[0..4]); (*self.h.borrow()).to_bytes(&mut buf[4..8]); @@ -99,6 +108,9 @@ impl Clone for anon_2 { } } impl ByteRepr for anon_2 { + fn byte_size() -> usize { + 8 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.e.borrow()).to_bytes(&mut buf[0..4]); (*self.f.borrow()).to_bytes(&mut buf[4..8]); @@ -123,6 +135,9 @@ impl Clone for anon_4 { } } impl ByteRepr for anon_4 { + fn byte_size() -> usize { + 4 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.j.borrow()).to_bytes(&mut buf[0..4]); } @@ -145,6 +160,9 @@ impl Clone for anon_5 { } } impl ByteRepr for anon_5 { + fn byte_size() -> usize { + 4 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.k.borrow()).to_bytes(&mut buf[0..4]); } @@ -171,6 +189,9 @@ impl Clone for anon_3 { } } impl ByteRepr for anon_3 { + fn byte_size() -> usize { + 12 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.i.borrow()).to_bytes(&mut buf[0..4]); (*self.inner_named.borrow()).to_bytes(&mut buf[4..8]); @@ -205,6 +226,9 @@ impl Clone for Outer { } } impl ByteRepr for Outer { + fn byte_size() -> usize { + 44 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.named.borrow()).to_bytes(&mut buf[0..8]); (*self.anonymous_named_0.borrow()).to_bytes(&mut buf[8..16]); @@ -304,6 +328,9 @@ fn main_0() -> i32 { } } impl ByteRepr for anon_6 { + fn byte_size() -> usize { + 8 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.x.borrow()).to_bytes(&mut buf[0..4]); (*self.z.borrow()).to_bytes(&mut buf[4..8]); diff --git a/tests/unit/out/refcount/anonymous-struct_c.rs b/tests/unit/out/refcount/anonymous-struct_c.rs index a9ae663e..970d6e99 100644 --- a/tests/unit/out/refcount/anonymous-struct_c.rs +++ b/tests/unit/out/refcount/anonymous-struct_c.rs @@ -12,6 +12,9 @@ pub struct Named { pub b: Value, } impl ByteRepr for Named { + fn byte_size() -> usize { + 8 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.a.borrow()).to_bytes(&mut buf[0..4]); (*self.b.borrow()).to_bytes(&mut buf[4..8]); @@ -29,6 +32,9 @@ pub struct anon_0 { pub d: Value, } impl ByteRepr for anon_0 { + fn byte_size() -> usize { + 8 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.c.borrow()).to_bytes(&mut buf[0..4]); (*self.d.borrow()).to_bytes(&mut buf[4..8]); @@ -46,6 +52,9 @@ pub struct anon_1 { pub h: Value, } impl ByteRepr for anon_1 { + fn byte_size() -> usize { + 8 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.g.borrow()).to_bytes(&mut buf[0..4]); (*self.h.borrow()).to_bytes(&mut buf[4..8]); @@ -63,6 +72,9 @@ pub struct anon_2 { pub f: Value, } impl ByteRepr for anon_2 { + fn byte_size() -> usize { + 8 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.e.borrow()).to_bytes(&mut buf[0..4]); (*self.f.borrow()).to_bytes(&mut buf[4..8]); @@ -79,6 +91,9 @@ pub struct anon_4 { pub j: Value, } impl ByteRepr for anon_4 { + fn byte_size() -> usize { + 4 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.j.borrow()).to_bytes(&mut buf[0..4]); } @@ -93,6 +108,9 @@ pub struct anon_5 { pub k: Value, } impl ByteRepr for anon_5 { + fn byte_size() -> usize { + 4 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.k.borrow()).to_bytes(&mut buf[0..4]); } @@ -109,6 +127,9 @@ pub struct anon_3 { pub anon_5: Value, } impl ByteRepr for anon_3 { + fn byte_size() -> usize { + 12 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.i.borrow()).to_bytes(&mut buf[0..4]); (*self.inner_named.borrow()).to_bytes(&mut buf[4..8]); @@ -131,6 +152,9 @@ pub struct Outer { pub anon_3: Value, } impl ByteRepr for Outer { + fn byte_size() -> usize { + 44 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.named.borrow()).to_bytes(&mut buf[0..8]); (*self.anon0.borrow()).to_bytes(&mut buf[8..16]); @@ -206,6 +230,9 @@ fn main_0() -> i32 { pub z: Value, } impl ByteRepr for anon_6 { + fn byte_size() -> usize { + 8 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.x.borrow()).to_bytes(&mut buf[0..4]); (*self.z.borrow()).to_bytes(&mut buf[4..8]); diff --git a/tests/unit/out/refcount/anonymous_enum.rs b/tests/unit/out/refcount/anonymous_enum.rs index 25de7201..f63deffd 100644 --- a/tests/unit/out/refcount/anonymous_enum.rs +++ b/tests/unit/out/refcount/anonymous_enum.rs @@ -51,6 +51,9 @@ impl Clone for S { } } impl ByteRepr for S { + fn byte_size() -> usize { + 4 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.a.borrow()).to_bytes(&mut buf[0..4]); } diff --git a/tests/unit/out/refcount/anonymous_enum_c.rs b/tests/unit/out/refcount/anonymous_enum_c.rs index 772ea6e5..43dc943b 100644 --- a/tests/unit/out/refcount/anonymous_enum_c.rs +++ b/tests/unit/out/refcount/anonymous_enum_c.rs @@ -43,6 +43,9 @@ pub struct S { pub a: Value, } impl ByteRepr for S { + fn byte_size() -> usize { + 4 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.a.borrow()).to_bytes(&mut buf[0..4]); } diff --git a/tests/unit/out/refcount/array_const_init.rs b/tests/unit/out/refcount/array_const_init.rs index 8a8a41b1..7a2cf78d 100644 --- a/tests/unit/out/refcount/array_const_init.rs +++ b/tests/unit/out/refcount/array_const_init.rs @@ -26,6 +26,9 @@ impl Default for S { } } impl ByteRepr for S { + fn byte_size() -> usize { + 20 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.head.borrow()).to_bytes(&mut buf[0..4]); (*self.tail.borrow()).to_bytes(&mut buf[4..16]); diff --git a/tests/unit/out/refcount/array_of_noncopy_struct.rs b/tests/unit/out/refcount/array_of_noncopy_struct.rs index d09df1bc..0c91af6d 100644 --- a/tests/unit/out/refcount/array_of_noncopy_struct.rs +++ b/tests/unit/out/refcount/array_of_noncopy_struct.rs @@ -21,6 +21,9 @@ impl Clone for NonCopy { } } impl ByteRepr for NonCopy { + fn byte_size() -> usize { + 32 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.data.borrow()).to_bytes(&mut buf[0..24]); (*self.tag.borrow()).to_bytes(&mut buf[24..28]); diff --git a/tests/unit/out/refcount/bounded_struct_ptr.rs b/tests/unit/out/refcount/bounded_struct_ptr.rs index 477a71a6..6da5e2fb 100644 --- a/tests/unit/out/refcount/bounded_struct_ptr.rs +++ b/tests/unit/out/refcount/bounded_struct_ptr.rs @@ -21,6 +21,9 @@ impl Clone for Foo { } } impl ByteRepr for Foo { + fn byte_size() -> usize { + 8 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.x1.borrow()).to_bytes(&mut buf[0..4]); (*self.x2.borrow()).to_bytes(&mut buf[4..8]); diff --git a/tests/unit/out/refcount/c_struct.rs b/tests/unit/out/refcount/c_struct.rs index de876ec4..a0985ec8 100644 --- a/tests/unit/out/refcount/c_struct.rs +++ b/tests/unit/out/refcount/c_struct.rs @@ -12,6 +12,9 @@ pub struct Point { pub y: Value, } impl ByteRepr for Point { + fn byte_size() -> usize { + 8 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.x.borrow()).to_bytes(&mut buf[0..4]); (*self.y.borrow()).to_bytes(&mut buf[4..8]); @@ -29,6 +32,9 @@ pub struct Line { pub end: Value, } impl ByteRepr for Line { + fn byte_size() -> usize { + 16 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.start.borrow()).to_bytes(&mut buf[0..8]); (*self.end.borrow()).to_bytes(&mut buf[8..16]); @@ -70,6 +76,9 @@ pub struct Inner { pub b: Value, } impl ByteRepr for Inner { + fn byte_size() -> usize { + 8 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.a.borrow()).to_bytes(&mut buf[0..4]); (*self.b.borrow()).to_bytes(&mut buf[4..8]); diff --git a/tests/unit/out/refcount/class.rs b/tests/unit/out/refcount/class.rs index cf3599a7..ed4161fc 100644 --- a/tests/unit/out/refcount/class.rs +++ b/tests/unit/out/refcount/class.rs @@ -56,6 +56,9 @@ impl Clone for Pair { } } impl ByteRepr for Pair { + fn byte_size() -> usize { + 8 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.first.borrow()).to_bytes(&mut buf[0..4]); (*self.second.borrow()).to_bytes(&mut buf[4..8]); @@ -90,6 +93,9 @@ impl Clone for Route { } } impl ByteRepr for Route { + fn byte_size() -> usize { + 16 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.path.borrow()).to_bytes(&mut buf[0..8]); (*self.cost.borrow()).to_bytes(&mut buf[8..16]); diff --git a/tests/unit/out/refcount/class_templates.rs b/tests/unit/out/refcount/class_templates.rs index b2e532c4..183fbd41 100644 --- a/tests/unit/out/refcount/class_templates.rs +++ b/tests/unit/out/refcount/class_templates.rs @@ -43,6 +43,9 @@ impl Clone for MyContainer_int_ { } } impl ByteRepr for MyContainer_int_ { + fn byte_size() -> usize { + 24 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.vec_.borrow()).to_bytes(&mut buf[0..24]); } @@ -89,6 +92,9 @@ impl Clone for MyContainer_char_ { } } impl ByteRepr for MyContainer_char_ { + fn byte_size() -> usize { + 24 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.vec_.borrow()).to_bytes(&mut buf[0..24]); } @@ -135,6 +141,9 @@ impl Clone for MyContainer_float_ { } } impl ByteRepr for MyContainer_float_ { + fn byte_size() -> usize { + 24 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.vec_.borrow()).to_bytes(&mut buf[0..24]); } diff --git a/tests/unit/out/refcount/clone_vs_move.rs b/tests/unit/out/refcount/clone_vs_move.rs index 9f6ee411..1953e3d9 100644 --- a/tests/unit/out/refcount/clone_vs_move.rs +++ b/tests/unit/out/refcount/clone_vs_move.rs @@ -19,6 +19,9 @@ impl Clone for Bar { } } impl ByteRepr for Bar { + fn byte_size() -> usize { + 4 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.w.borrow()).to_bytes(&mut buf[0..4]); } diff --git a/tests/unit/out/refcount/complex_function.rs b/tests/unit/out/refcount/complex_function.rs index 07a300f9..40f929c9 100644 --- a/tests/unit/out/refcount/complex_function.rs +++ b/tests/unit/out/refcount/complex_function.rs @@ -30,6 +30,9 @@ impl Clone for X1 { } } impl ByteRepr for X1 { + fn byte_size() -> usize { + 4 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.v.borrow()).to_bytes(&mut buf[0..4]); } diff --git a/tests/unit/out/refcount/exprs.rs b/tests/unit/out/refcount/exprs.rs index 6a4a1646..e8a9eed6 100644 --- a/tests/unit/out/refcount/exprs.rs +++ b/tests/unit/out/refcount/exprs.rs @@ -19,6 +19,9 @@ impl Clone for X { } } impl ByteRepr for X { + fn byte_size() -> usize { + 4 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.x.borrow()).to_bytes(&mut buf[0..4]); } diff --git a/tests/unit/out/refcount/fft.rs b/tests/unit/out/refcount/fft.rs index 7402fbc6..d7d2465d 100644 --- a/tests/unit/out/refcount/fft.rs +++ b/tests/unit/out/refcount/fft.rs @@ -21,6 +21,9 @@ impl Clone for Complex { } } impl ByteRepr for Complex { + fn byte_size() -> usize { + 16 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.re.borrow()).to_bytes(&mut buf[0..8]); (*self.img.borrow()).to_bytes(&mut buf[8..16]); diff --git a/tests/unit/out/refcount/fn_ptr_stable_sort.rs b/tests/unit/out/refcount/fn_ptr_stable_sort.rs index 5182170f..da7b2e8a 100644 --- a/tests/unit/out/refcount/fn_ptr_stable_sort.rs +++ b/tests/unit/out/refcount/fn_ptr_stable_sort.rs @@ -21,6 +21,9 @@ impl Clone for Item { } } impl ByteRepr for Item { + fn byte_size() -> usize { + 8 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.key.borrow()).to_bytes(&mut buf[0..4]); (*self.value.borrow()).to_bytes(&mut buf[4..8]); diff --git a/tests/unit/out/refcount/foreach_disjoint_field_borrow.rs b/tests/unit/out/refcount/foreach_disjoint_field_borrow.rs index 8725ce22..57c56051 100644 --- a/tests/unit/out/refcount/foreach_disjoint_field_borrow.rs +++ b/tests/unit/out/refcount/foreach_disjoint_field_borrow.rs @@ -21,6 +21,9 @@ impl Clone for S { } } impl ByteRepr for S { + fn byte_size() -> usize { + 32 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.v.borrow()).to_bytes(&mut buf[0..24]); (*self.a.borrow()).to_bytes(&mut buf[24..28]); diff --git a/tests/unit/out/refcount/function_overloading.rs b/tests/unit/out/refcount/function_overloading.rs index 1d43def8..34b67cc0 100644 --- a/tests/unit/out/refcount/function_overloading.rs +++ b/tests/unit/out/refcount/function_overloading.rs @@ -63,6 +63,9 @@ impl Clone for Foo { } } impl ByteRepr for Foo { + fn byte_size() -> usize { + 1 + } fn to_bytes(&self, buf: &mut [u8]) {} fn from_bytes(buf: &[u8]) -> Self { Self {} diff --git a/tests/unit/out/refcount/global_without_initializer.rs b/tests/unit/out/refcount/global_without_initializer.rs index 51fce351..f1dd9e2a 100644 --- a/tests/unit/out/refcount/global_without_initializer.rs +++ b/tests/unit/out/refcount/global_without_initializer.rs @@ -19,6 +19,9 @@ impl Clone for S { } } impl ByteRepr for S { + fn byte_size() -> usize { + 4 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.a.borrow()).to_bytes(&mut buf[0..4]); } diff --git a/tests/unit/out/refcount/goto_aggregate_default.rs b/tests/unit/out/refcount/goto_aggregate_default.rs index 4eb6fee0..5b5fb3c8 100644 --- a/tests/unit/out/refcount/goto_aggregate_default.rs +++ b/tests/unit/out/refcount/goto_aggregate_default.rs @@ -12,6 +12,9 @@ pub struct Point { pub y: Value, } impl ByteRepr for Point { + fn byte_size() -> usize { + 8 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.x.borrow()).to_bytes(&mut buf[0..4]); (*self.y.borrow()).to_bytes(&mut buf[4..8]); diff --git a/tests/unit/out/refcount/huffman.rs b/tests/unit/out/refcount/huffman.rs index 89641c8f..f00081cd 100644 --- a/tests/unit/out/refcount/huffman.rs +++ b/tests/unit/out/refcount/huffman.rs @@ -207,6 +207,9 @@ impl MinHeap { } } impl ByteRepr for MinHeap { + fn byte_size() -> usize { + 32 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.size.borrow()).to_bytes(&mut buf[0..4]); (*self.capacity.borrow()).to_bytes(&mut buf[4..8]); diff --git a/tests/unit/out/refcount/immutable-deref-on-func-call.rs b/tests/unit/out/refcount/immutable-deref-on-func-call.rs index 416e1438..84ae55c9 100644 --- a/tests/unit/out/refcount/immutable-deref-on-func-call.rs +++ b/tests/unit/out/refcount/immutable-deref-on-func-call.rs @@ -25,6 +25,9 @@ impl Clone for Item { } } impl ByteRepr for Item { + fn byte_size() -> usize { + 4 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.value.borrow()).to_bytes(&mut buf[0..4]); } diff --git a/tests/unit/out/refcount/implicit_autoref.rs b/tests/unit/out/refcount/implicit_autoref.rs index c1cbf5f6..52a20e63 100644 --- a/tests/unit/out/refcount/implicit_autoref.rs +++ b/tests/unit/out/refcount/implicit_autoref.rs @@ -19,6 +19,9 @@ impl Clone for Holder { } } impl ByteRepr for Holder { + fn byte_size() -> usize { + 24 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.v.borrow()).to_bytes(&mut buf[0..24]); } diff --git a/tests/unit/out/refcount/init.rs b/tests/unit/out/refcount/init.rs index f74601da..2fed9750 100644 --- a/tests/unit/out/refcount/init.rs +++ b/tests/unit/out/refcount/init.rs @@ -19,6 +19,9 @@ impl Clone for X { } } impl ByteRepr for X { + fn byte_size() -> usize { + 4 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.x.borrow()).to_bytes(&mut buf[0..4]); } diff --git a/tests/unit/out/refcount/kruskal.rs b/tests/unit/out/refcount/kruskal.rs index f606c434..abb97818 100644 --- a/tests/unit/out/refcount/kruskal.rs +++ b/tests/unit/out/refcount/kruskal.rs @@ -23,6 +23,9 @@ impl Clone for Edge { } } impl ByteRepr for Edge { + fn byte_size() -> usize { + 16 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.u.borrow()).to_bytes(&mut buf[0..4]); (*self.v.borrow()).to_bytes(&mut buf[4..8]); @@ -288,6 +291,9 @@ impl DisjointSet { } } impl ByteRepr for DisjointSet { + fn byte_size() -> usize { + 24 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.rank.borrow()).to_bytes(&mut buf[0..8]); (*self.parent.borrow()).to_bytes(&mut buf[8..16]); @@ -312,6 +318,9 @@ pub struct Graph { pub E: Value, } impl ByteRepr for Graph { + fn byte_size() -> usize { + 16 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.edges.borrow()).to_bytes(&mut buf[0..8]); (*self.V.borrow()).to_bytes(&mut buf[8..12]); diff --git a/tests/unit/out/refcount/local_anon_struct_collision.rs b/tests/unit/out/refcount/local_anon_struct_collision.rs index c4b23e73..d69250d0 100644 --- a/tests/unit/out/refcount/local_anon_struct_collision.rs +++ b/tests/unit/out/refcount/local_anon_struct_collision.rs @@ -13,6 +13,9 @@ pub fn first_0() -> i32 { pub y: Value, } impl ByteRepr for anon_1 { + fn byte_size() -> usize { + 8 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.x.borrow()).to_bytes(&mut buf[0..4]); (*self.y.borrow()).to_bytes(&mut buf[4..8]); @@ -36,6 +39,9 @@ pub fn second_2() -> i32 { pub b: Value, } impl ByteRepr for anon_3 { + fn byte_size() -> usize { + 16 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.a.borrow()).to_bytes(&mut buf[0..8]); (*self.b.borrow()).to_bytes(&mut buf[8..16]); diff --git a/tests/unit/out/refcount/memcpy_struct_struct.rs b/tests/unit/out/refcount/memcpy_struct_struct.rs index 5ccc910e..158e7cff 100644 --- a/tests/unit/out/refcount/memcpy_struct_struct.rs +++ b/tests/unit/out/refcount/memcpy_struct_struct.rs @@ -21,6 +21,9 @@ impl Clone for Entry { } } impl ByteRepr for Entry { + fn byte_size() -> usize { + 4 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.bits.borrow()).to_bytes(&mut buf[0..1]); (*self.value.borrow()).to_bytes(&mut buf[2..4]); @@ -77,9 +80,7 @@ fn main_0() -> i32 { .to_any() .memcpy( &(((table.as_pointer() as Ptr).offset(0 as isize)) as Ptr).to_any(), - (((*table_size.borrow()) as u64) - .wrapping_mul((::std::mem::size_of::() as u64)) - as usize) as usize, + (((*table_size.borrow()) as u64).wrapping_mul((4usize as u64)) as usize) as usize, ); (((table.as_pointer() as Ptr).offset((*table_size.borrow()) as isize)) as Ptr) .to_any() diff --git a/tests/unit/out/refcount/nested_structs.rs b/tests/unit/out/refcount/nested_structs.rs index 491cdf12..febf11a8 100644 --- a/tests/unit/out/refcount/nested_structs.rs +++ b/tests/unit/out/refcount/nested_structs.rs @@ -19,6 +19,9 @@ impl Clone for Level0_Level1_1_Level2_1_Level3_1 { } } impl ByteRepr for Level0_Level1_1_Level2_1_Level3_1 { + fn byte_size() -> usize { + 4 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.x1.borrow()).to_bytes(&mut buf[0..4]); } @@ -43,6 +46,9 @@ impl Clone for Level0_Level1_1_Level2_1_Level3_2 { } } impl ByteRepr for Level0_Level1_1_Level2_1_Level3_2 { + fn byte_size() -> usize { + 8 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.x1.borrow()).to_bytes(&mut buf[0..4]); (*self.x2.borrow()).to_bytes(&mut buf[4..8]); @@ -67,6 +73,9 @@ impl Clone for Level0_Level1_1_Level2_1 { } } impl ByteRepr for Level0_Level1_1_Level2_1 { + fn byte_size() -> usize { + 4 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.x1.borrow()).to_bytes(&mut buf[0..4]); } @@ -89,6 +98,9 @@ impl Clone for Level0_Level1_1 { } } impl ByteRepr for Level0_Level1_1 { + fn byte_size() -> usize { + 4 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.x1.borrow()).to_bytes(&mut buf[0..4]); } @@ -113,6 +125,9 @@ impl Clone for Level0_Level1_2 { } } impl ByteRepr for Level0_Level1_2 { + fn byte_size() -> usize { + 8 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.x1.borrow()).to_bytes(&mut buf[0..4]); (*self.x2.borrow()).to_bytes(&mut buf[4..8]); @@ -133,6 +148,9 @@ impl Clone for Level0 { } } impl ByteRepr for Level0 { + fn byte_size() -> usize { + 1 + } fn to_bytes(&self, buf: &mut [u8]) {} fn from_bytes(buf: &[u8]) -> Self { Self {} diff --git a/tests/unit/out/refcount/new_struct.rs b/tests/unit/out/refcount/new_struct.rs index 9885653c..05ba3965 100644 --- a/tests/unit/out/refcount/new_struct.rs +++ b/tests/unit/out/refcount/new_struct.rs @@ -21,6 +21,9 @@ impl Clone for Pair { } } impl ByteRepr for Pair { + fn byte_size() -> usize { + 8 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.x.borrow()).to_bytes(&mut buf[0..4]); (*self.y.borrow()).to_bytes(&mut buf[4..8]); diff --git a/tests/unit/out/refcount/operator_less_than.rs b/tests/unit/out/refcount/operator_less_than.rs index cbf3d70b..94102602 100644 --- a/tests/unit/out/refcount/operator_less_than.rs +++ b/tests/unit/out/refcount/operator_less_than.rs @@ -62,6 +62,9 @@ impl Clone for Pair { } } impl ByteRepr for Pair { + fn byte_size() -> usize { + 8 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.x.borrow()).to_bytes(&mut buf[0..4]); (*self.y.borrow()).to_bytes(&mut buf[4..8]); diff --git a/tests/unit/out/refcount/pod.rs b/tests/unit/out/refcount/pod.rs index 1f095551..7af61324 100644 --- a/tests/unit/out/refcount/pod.rs +++ b/tests/unit/out/refcount/pod.rs @@ -23,6 +23,9 @@ impl Clone for POD { } } impl ByteRepr for POD { + fn byte_size() -> usize { + 12 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.x1.borrow()).to_bytes(&mut buf[0..4]); (*self.x2.borrow()).to_bytes(&mut buf[4..8]); diff --git a/tests/unit/out/refcount/pointers.rs b/tests/unit/out/refcount/pointers.rs index 0c4d2b16..826fca3b 100644 --- a/tests/unit/out/refcount/pointers.rs +++ b/tests/unit/out/refcount/pointers.rs @@ -35,6 +35,9 @@ impl Clone for Test { } } impl ByteRepr for Test { + fn byte_size() -> usize { + 4 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.x.borrow()).to_bytes(&mut buf[0..4]); } diff --git a/tests/unit/out/refcount/polymorphism.rs b/tests/unit/out/refcount/polymorphism.rs index b1f4297f..b50c4491 100644 --- a/tests/unit/out/refcount/polymorphism.rs +++ b/tests/unit/out/refcount/polymorphism.rs @@ -23,6 +23,9 @@ impl Clone for Dog { } } impl ByteRepr for Dog { + fn byte_size() -> usize { + 8 + } fn to_bytes(&self, buf: &mut [u8]) {} fn from_bytes(buf: &[u8]) -> Self { Self {} @@ -47,6 +50,9 @@ impl Clone for Cat { } } impl ByteRepr for Cat { + fn byte_size() -> usize { + 8 + } fn to_bytes(&self, buf: &mut [u8]) {} fn from_bytes(buf: &[u8]) -> Self { Self {} diff --git a/tests/unit/out/refcount/push_emplace_back.rs b/tests/unit/out/refcount/push_emplace_back.rs index 0ec6ec13..47c9e3c0 100644 --- a/tests/unit/out/refcount/push_emplace_back.rs +++ b/tests/unit/out/refcount/push_emplace_back.rs @@ -19,6 +19,9 @@ impl Clone for Chunk { } } impl ByteRepr for Chunk { + fn byte_size() -> usize { + 4 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.data.borrow()).to_bytes(&mut buf[0..4]); } @@ -68,6 +71,9 @@ impl Clone for JPEGData { } } impl ByteRepr for JPEGData { + fn byte_size() -> usize { + 48 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.com_data.borrow()).to_bytes(&mut buf[0..24]); (*self.app_data.borrow()).to_bytes(&mut buf[24..48]); diff --git a/tests/unit/out/refcount/random.rs b/tests/unit/out/refcount/random.rs index 3b1057f8..aa0e5a31 100644 --- a/tests/unit/out/refcount/random.rs +++ b/tests/unit/out/refcount/random.rs @@ -82,6 +82,9 @@ impl Clone for X1 { } } impl ByteRepr for X1 { + fn byte_size() -> usize { + 1 + } fn to_bytes(&self, buf: &mut [u8]) {} fn from_bytes(buf: &[u8]) -> Self { Self {} diff --git a/tests/unit/out/refcount/reinterpret_cast_struct.rs b/tests/unit/out/refcount/reinterpret_cast_struct.rs index 9e2370a1..1c9e14b5 100644 --- a/tests/unit/out/refcount/reinterpret_cast_struct.rs +++ b/tests/unit/out/refcount/reinterpret_cast_struct.rs @@ -21,6 +21,9 @@ impl Clone for Point { } } impl ByteRepr for Point { + fn byte_size() -> usize { + 8 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.x.borrow()).to_bytes(&mut buf[0..4]); (*self.y.borrow()).to_bytes(&mut buf[4..8]); diff --git a/tests/unit/out/refcount/reinterpret_cast_struct_to_struct.rs b/tests/unit/out/refcount/reinterpret_cast_struct_to_struct.rs index 0f065102..5b5d82c9 100644 --- a/tests/unit/out/refcount/reinterpret_cast_struct_to_struct.rs +++ b/tests/unit/out/refcount/reinterpret_cast_struct_to_struct.rs @@ -21,6 +21,9 @@ impl Clone for Point { } } impl ByteRepr for Point { + fn byte_size() -> usize { + 8 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.x.borrow()).to_bytes(&mut buf[0..4]); (*self.y.borrow()).to_bytes(&mut buf[4..8]); @@ -47,6 +50,9 @@ impl Clone for Pair { } } impl ByteRepr for Pair { + fn byte_size() -> usize { + 8 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.first.borrow()).to_bytes(&mut buf[0..4]); (*self.second.borrow()).to_bytes(&mut buf[4..8]); diff --git a/tests/unit/out/refcount/reserved_keywords.rs b/tests/unit/out/refcount/reserved_keywords.rs index b670988f..5258cfab 100644 --- a/tests/unit/out/refcount/reserved_keywords.rs +++ b/tests/unit/out/refcount/reserved_keywords.rs @@ -93,6 +93,9 @@ impl Clone for S { } } impl ByteRepr for S { + fn byte_size() -> usize { + 152 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.as_.borrow()).to_bytes(&mut buf[0..4]); (*self.async_.borrow()).to_bytes(&mut buf[4..8]); diff --git a/tests/unit/out/refcount/static_var_in_class.rs b/tests/unit/out/refcount/static_var_in_class.rs index 35e012e7..d08a4f63 100644 --- a/tests/unit/out/refcount/static_var_in_class.rs +++ b/tests/unit/out/refcount/static_var_in_class.rs @@ -23,6 +23,9 @@ impl Clone for C { } } impl ByteRepr for C { + fn byte_size() -> usize { + 1 + } fn to_bytes(&self, buf: &mut [u8]) {} fn from_bytes(buf: &[u8]) -> Self { Self {} @@ -40,6 +43,9 @@ impl Clone for S { } } impl ByteRepr for S { + fn byte_size() -> usize { + 1 + } fn to_bytes(&self, buf: &mut [u8]) {} fn from_bytes(buf: &[u8]) -> Self { Self {} diff --git a/tests/unit/out/refcount/struct_ctor.rs b/tests/unit/out/refcount/struct_ctor.rs index e0a9d434..6c2fd936 100644 --- a/tests/unit/out/refcount/struct_ctor.rs +++ b/tests/unit/out/refcount/struct_ctor.rs @@ -40,6 +40,9 @@ impl Clone for StructWithCtor { } } impl ByteRepr for StructWithCtor { + fn byte_size() -> usize { + 8 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.x1_.borrow()).to_bytes(&mut buf[0..4]); (*self.x2_.borrow()).to_bytes(&mut buf[4..8]); diff --git a/tests/unit/out/refcount/struct_ptr.rs b/tests/unit/out/refcount/struct_ptr.rs index 4defc67a..beb54800 100644 --- a/tests/unit/out/refcount/struct_ptr.rs +++ b/tests/unit/out/refcount/struct_ptr.rs @@ -19,6 +19,9 @@ impl Clone for XX { } } impl ByteRepr for XX { + fn byte_size() -> usize { + 4 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.x.borrow()).to_bytes(&mut buf[0..4]); } diff --git a/tests/unit/out/refcount/tag_vs_identifier_collision.rs b/tests/unit/out/refcount/tag_vs_identifier_collision.rs index b4647d30..5df7172a 100644 --- a/tests/unit/out/refcount/tag_vs_identifier_collision.rs +++ b/tests/unit/out/refcount/tag_vs_identifier_collision.rs @@ -36,6 +36,9 @@ pub struct point_struct { pub y: Value, } impl ByteRepr for point_struct { + fn byte_size() -> usize { + 8 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.x.borrow()).to_bytes(&mut buf[0..4]); (*self.y.borrow()).to_bytes(&mut buf[4..8]); @@ -67,6 +70,9 @@ impl Default for point { } } impl ByteRepr for point { + fn byte_size() -> usize { + 4 + } fn to_bytes(&self, buf: &mut [u8]) { self.__store.to_bytes(buf); } @@ -96,6 +102,9 @@ impl Default for slot_union { } } impl ByteRepr for slot_union { + fn byte_size() -> usize { + 4 + } fn to_bytes(&self, buf: &mut [u8]) { self.__store.to_bytes(buf); } @@ -126,6 +135,9 @@ pub struct Inner { pub tag_field: Value, } impl ByteRepr for Inner { + fn byte_size() -> usize { + 4 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.tag_field.borrow()).to_bytes(&mut buf[0..4]); } @@ -140,6 +152,9 @@ pub struct Outer { pub field: Value, } impl ByteRepr for Outer { + fn byte_size() -> usize { + 4 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.field.borrow()).to_bytes(&mut buf[0..4]); } @@ -154,6 +169,9 @@ pub struct Inner_struct { pub typedef_field: Value, } impl ByteRepr for Inner_struct { + fn byte_size() -> usize { + 4 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.typedef_field.borrow()).to_bytes(&mut buf[0..4]); } diff --git a/tests/unit/out/refcount/typedef-anon-struct.rs b/tests/unit/out/refcount/typedef-anon-struct.rs index cc552c42..80e81458 100644 --- a/tests/unit/out/refcount/typedef-anon-struct.rs +++ b/tests/unit/out/refcount/typedef-anon-struct.rs @@ -21,6 +21,9 @@ impl Clone for Outer_RunInfo { } } impl ByteRepr for Outer_RunInfo { + fn byte_size() -> usize { + 8 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.block_idx.borrow()).to_bytes(&mut buf[0..4]); (*self.num_extra_zero_runs.borrow()).to_bytes(&mut buf[4..8]); @@ -45,6 +48,9 @@ impl Clone for Outer { } } impl ByteRepr for Outer { + fn byte_size() -> usize { + 24 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.runs.borrow()).to_bytes(&mut buf[0..24]); } diff --git a/tests/unit/out/refcount/union_basic.rs b/tests/unit/out/refcount/union_basic.rs index 80196a86..96d01775 100644 --- a/tests/unit/out/refcount/union_basic.rs +++ b/tests/unit/out/refcount/union_basic.rs @@ -26,6 +26,9 @@ impl Default for basic { } } impl ByteRepr for basic { + fn byte_size() -> usize { + 4 + } fn to_bytes(&self, buf: &mut [u8]) { self.__store.to_bytes(buf); } diff --git a/tests/unit/out/refcount/union_pointer_pun_writethrough.rs b/tests/unit/out/refcount/union_pointer_pun_writethrough.rs index 0683de06..598e3921 100644 --- a/tests/unit/out/refcount/union_pointer_pun_writethrough.rs +++ b/tests/unit/out/refcount/union_pointer_pun_writethrough.rs @@ -31,6 +31,9 @@ fn main_0() -> i32 { } } impl ByteRepr for anon_0 { + fn byte_size() -> usize { + 8 + } fn to_bytes(&self, buf: &mut [u8]) { self.__store.to_bytes(buf); } diff --git a/tests/unit/out/refcount/union_tagged_struct_arms.rs b/tests/unit/out/refcount/union_tagged_struct_arms.rs index dc80fb93..d675186f 100644 --- a/tests/unit/out/refcount/union_tagged_struct_arms.rs +++ b/tests/unit/out/refcount/union_tagged_struct_arms.rs @@ -39,6 +39,9 @@ pub struct anon_2 { pub step: Value, } impl ByteRepr for anon_2 { + fn byte_size() -> usize { + 16 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.lo.borrow()).to_bytes(&mut buf[0..4]); (*self.hi.borrow()).to_bytes(&mut buf[4..8]); @@ -63,6 +66,9 @@ pub struct anon_3 { pub width: Value, } impl ByteRepr for anon_3 { + fn byte_size() -> usize { + 40 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.lo.borrow()).to_bytes(&mut buf[0..8]); (*self.hi.borrow()).to_bytes(&mut buf[8..16]); @@ -103,6 +109,9 @@ impl Default for anon_0 { } } impl ByteRepr for anon_0 { + fn byte_size() -> usize { + 40 + } fn to_bytes(&self, buf: &mut [u8]) { self.__store.to_bytes(buf); } diff --git a/tests/unit/out/refcount/unique_ptr.rs b/tests/unit/out/refcount/unique_ptr.rs index 7f682d42..f7559906 100644 --- a/tests/unit/out/refcount/unique_ptr.rs +++ b/tests/unit/out/refcount/unique_ptr.rs @@ -16,6 +16,9 @@ impl SafePointer { } } impl ByteRepr for SafePointer { + fn byte_size() -> usize { + 8 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.ptr.borrow()).to_bytes(&mut buf[0..8]); } @@ -40,6 +43,9 @@ impl Clone for Pair { } } impl ByteRepr for Pair { + fn byte_size() -> usize { + 8 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.x.borrow()).to_bytes(&mut buf[0..4]); (*self.y.borrow()).to_bytes(&mut buf[4..8]); diff --git a/tests/unit/out/refcount/unique_ptr_const_deref.rs b/tests/unit/out/refcount/unique_ptr_const_deref.rs index d7b82b00..a860f6fd 100644 --- a/tests/unit/out/refcount/unique_ptr_const_deref.rs +++ b/tests/unit/out/refcount/unique_ptr_const_deref.rs @@ -11,6 +11,9 @@ pub struct Holder { pub val: Value>>, } impl ByteRepr for Holder { + fn byte_size() -> usize { + 8 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.val.borrow()).to_bytes(&mut buf[0..8]); } diff --git a/tests/unit/out/refcount/unique_ptr_nested.rs b/tests/unit/out/refcount/unique_ptr_nested.rs index d22ddb15..73a07682 100644 --- a/tests/unit/out/refcount/unique_ptr_nested.rs +++ b/tests/unit/out/refcount/unique_ptr_nested.rs @@ -21,6 +21,9 @@ impl Clone for Inner { } } impl ByteRepr for Inner { + fn byte_size() -> usize { + 8 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.x.borrow()).to_bytes(&mut buf[0..4]); (*self.y.borrow()).to_bytes(&mut buf[4..8]); @@ -37,6 +40,9 @@ pub struct Outer { pub inner: Value>>, } impl ByteRepr for Outer { + fn byte_size() -> usize { + 8 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.inner.borrow()).to_bytes(&mut buf[0..8]); } diff --git a/tests/unit/out/refcount/unique_ptr_struct.rs b/tests/unit/out/refcount/unique_ptr_struct.rs index db2e7df6..7ed4daf1 100644 --- a/tests/unit/out/refcount/unique_ptr_struct.rs +++ b/tests/unit/out/refcount/unique_ptr_struct.rs @@ -21,6 +21,9 @@ impl Clone for Point { } } impl ByteRepr for Point { + fn byte_size() -> usize { + 8 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.x.borrow()).to_bytes(&mut buf[0..4]); (*self.y.borrow()).to_bytes(&mut buf[4..8]); diff --git a/tests/unit/out/refcount/va_arg_struct_ctx.rs b/tests/unit/out/refcount/va_arg_struct_ctx.rs index bc607d65..aea69a5e 100644 --- a/tests/unit/out/refcount/va_arg_struct_ctx.rs +++ b/tests/unit/out/refcount/va_arg_struct_ctx.rs @@ -12,6 +12,9 @@ pub struct context { pub last_error: Value, } impl ByteRepr for context { + fn byte_size() -> usize { + 8 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.verbose.borrow()).to_bytes(&mut buf[0..4]); (*self.last_error.borrow()).to_bytes(&mut buf[4..8]); diff --git a/tests/unit/out/refcount/void_cast.rs b/tests/unit/out/refcount/void_cast.rs index 49c37c2b..174a219f 100644 --- a/tests/unit/out/refcount/void_cast.rs +++ b/tests/unit/out/refcount/void_cast.rs @@ -23,6 +23,9 @@ impl Clone for NonTrivial { } } impl ByteRepr for NonTrivial { + fn byte_size() -> usize { + 24 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.data.borrow()).to_bytes(&mut buf[0..24]); } @@ -59,6 +62,9 @@ impl Clone for Holder { } } impl ByteRepr for Holder { + fn byte_size() -> usize { + 4 + } fn to_bytes(&self, buf: &mut [u8]) { (*self.field.borrow()).to_bytes(&mut buf[0..4]); } diff --git a/tests/unit/union_cross_arm_cast.c b/tests/unit/union_cross_arm_cast.c index 598de31e..274335ac 100644 --- a/tests/unit/union_cross_arm_cast.c +++ b/tests/unit/union_cross_arm_cast.c @@ -1,4 +1,4 @@ -// no-compile: refcount +// panic: refcount #include #include #include diff --git a/tests/unit/union_nested.c b/tests/unit/union_nested.c index b056725e..ca967139 100644 --- a/tests/unit/union_nested.c +++ b/tests/unit/union_nested.c @@ -1,4 +1,4 @@ -// no-compile: refcount +// panic: refcount #include #include #include diff --git a/tests/unit/union_pointer_pun_address.c b/tests/unit/union_pointer_pun_address.c index 421bb1f0..75123e0c 100644 --- a/tests/unit/union_pointer_pun_address.c +++ b/tests/unit/union_pointer_pun_address.c @@ -1,4 +1,4 @@ -// no-compile: refcount +// panic: refcount #include struct node_a { diff --git a/tests/unit/union_struct_dual_use.c b/tests/unit/union_struct_dual_use.c index 2ddb14f4..400f5c4e 100644 --- a/tests/unit/union_struct_dual_use.c +++ b/tests/unit/union_struct_dual_use.c @@ -1,4 +1,4 @@ -// no-compile: refcount +// panic: refcount #include #include From 83a9dccb77684a47860c7cddd1e7f6ccb1a226ad Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 24 Jun 2026 11:47:08 +0100 Subject: [PATCH 16/29] Update tests --- .../unit/out/refcount/union_cross_arm_cast.rs | 192 +++++++++++++++ .../unit/out/refcount/union_memset_memcpy.rs | 233 ++++++++++++++++++ tests/unit/out/refcount/union_nested.rs | 197 +++++++++++++++ .../out/refcount/union_pointer_pun_address.rs | 82 ++++++ .../out/refcount/union_struct_dual_use.rs | 130 ++++++++++ .../unit/out/refcount/union_tagged_simple.rs | 93 +++++++ tests/unit/union_addrof_external.c | 2 +- tests/unit/union_memset_memcpy.c | 2 +- 8 files changed, 929 insertions(+), 2 deletions(-) create mode 100644 tests/unit/out/refcount/union_cross_arm_cast.rs create mode 100644 tests/unit/out/refcount/union_memset_memcpy.rs create mode 100644 tests/unit/out/refcount/union_nested.rs create mode 100644 tests/unit/out/refcount/union_pointer_pun_address.rs create mode 100644 tests/unit/out/refcount/union_struct_dual_use.rs create mode 100644 tests/unit/out/refcount/union_tagged_simple.rs diff --git a/tests/unit/out/refcount/union_cross_arm_cast.rs b/tests/unit/out/refcount/union_cross_arm_cast.rs new file mode 100644 index 00000000..b6bfef6d --- /dev/null +++ b/tests/unit/out/refcount/union_cross_arm_cast.rs @@ -0,0 +1,192 @@ +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()] +pub struct shape_a { + pub code: Value, + pub pad: Value>, +} +impl Default for shape_a { + fn default() -> Self { + shape_a { + code: >::default(), + pad: Rc::new(RefCell::new( + (0..14).map(|_| ::default()).collect::>(), + )), + } + } +} +impl ByteRepr for shape_a { + fn byte_size() -> usize { + 16 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.code.borrow()).to_bytes(&mut buf[0..2]); + (*self.pad.borrow()).to_bytes(&mut buf[2..16]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + code: Rc::new(RefCell::new(::from_bytes(&buf[0..2]))), + pad: Rc::new(RefCell::new(>::from_bytes(&buf[2..16]))), + } + } +} +#[derive()] +pub struct shape_b { + pub code: Value, + pub lo: Value, + pub mid: Value, + pub fill: Value>, + pub tail: Value, +} +impl Default for shape_b { + fn default() -> Self { + shape_b { + code: >::default(), + lo: >::default(), + mid: >::default(), + fill: Rc::new(RefCell::new( + (0..16).map(|_| ::default()).collect::>(), + )), + tail: >::default(), + } + } +} +impl ByteRepr for shape_b { + fn byte_size() -> usize { + 28 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.code.borrow()).to_bytes(&mut buf[0..2]); + (*self.lo.borrow()).to_bytes(&mut buf[2..4]); + (*self.mid.borrow()).to_bytes(&mut buf[4..8]); + (*self.fill.borrow()).to_bytes(&mut buf[8..24]); + (*self.tail.borrow()).to_bytes(&mut buf[24..28]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + code: Rc::new(RefCell::new(::from_bytes(&buf[0..2]))), + lo: Rc::new(RefCell::new(::from_bytes(&buf[2..4]))), + mid: Rc::new(RefCell::new(::from_bytes(&buf[4..8]))), + fill: Rc::new(RefCell::new(>::from_bytes(&buf[8..24]))), + tail: Rc::new(RefCell::new(::from_bytes(&buf[24..28]))), + } + } +} +#[derive(Clone)] +pub struct anon_0 { + __store: libcc2rs::UnionStorage, +} +impl anon_0 { + pub fn a(&self) -> Ptr { + self.__store.reinterpret(0) + } + pub fn b(&self) -> Ptr { + self.__store.reinterpret(0) + } + pub fn raw_(&self) -> Ptr> { + self.__store.reinterpret(0) + } +} +impl Default for anon_0 { + fn default() -> Self { + anon_0 { + __store: libcc2rs::UnionStorage::new(64), + } + } +} +impl ByteRepr for anon_0 { + fn byte_size() -> usize { + 64 + } + fn to_bytes(&self, buf: &mut [u8]) { + self.__store.to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { + anon_0 { + __store: libcc2rs::UnionStorage::from_bytes(buf), + } + } +} +#[derive(Default)] +pub struct Container { + pub len: Value, + pub u: Value, +} +impl ByteRepr for Container { + fn byte_size() -> usize { + 68 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.len.borrow()).to_bytes(&mut buf[0..4]); + (*self.u.borrow()).to_bytes(&mut buf[4..68]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + len: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), + u: Rc::new(RefCell::new(::from_bytes(&buf[4..68]))), + } + } +} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let c: Value = >::default(); + { + ((c.as_pointer()) as Ptr) + .to_any() + .memset((0) as u8, 68usize as usize); + ((c.as_pointer()) as Ptr).to_any().clone() + }; + (*(*(*(*c.borrow()).u.borrow()).a().upgrade().deref()) + .code + .borrow_mut()) = 10_u16; + (*(*c.borrow()).len.borrow_mut()) = (28usize as u32); + (*(*(((*(*c.borrow()).u.borrow()).a()) + .clone() + .to_any() + .cast::() + .expect("ub:wrong type")) + .upgrade() + .deref()) + .tail + .borrow_mut()) = 3735928559_u32; + assert!( + ((((*(*(*(*c.borrow()).u.borrow()).b().upgrade().deref()) + .tail + .borrow()) + == 3735928559_u32) as i32) + != 0) + ); + assert!( + (((((*(*(*(*c.borrow()).u.borrow()).b().upgrade().deref()) + .code + .borrow()) as i32) + == 10) as i32) + != 0) + ); + (*(*(*(*c.borrow()).u.borrow()).b().upgrade().deref()) + .lo + .borrow_mut()) = 8080_u16; + assert!( + ((((((((*(*c.borrow()).u.borrow()).raw_()).reinterpret_cast::()) + .offset((2) as isize) + .read()) as i32) + == 144) as i32) + != 0) + ); + assert!( + ((((((((*(*c.borrow()).u.borrow()).raw_()).reinterpret_cast::()) + .offset((3) as isize) + .read()) as i32) + == 31) as i32) + != 0) + ); + return 0; +} diff --git a/tests/unit/out/refcount/union_memset_memcpy.rs b/tests/unit/out/refcount/union_memset_memcpy.rs new file mode 100644 index 00000000..712efc36 --- /dev/null +++ b/tests/unit/out/refcount/union_memset_memcpy.rs @@ -0,0 +1,233 @@ +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()] +pub struct shape_a { + pub code: Value, + pub pad: Value>, +} +impl Default for shape_a { + fn default() -> Self { + shape_a { + code: >::default(), + pad: Rc::new(RefCell::new( + (0..14).map(|_| ::default()).collect::>(), + )), + } + } +} +impl ByteRepr for shape_a { + fn byte_size() -> usize { + 16 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.code.borrow()).to_bytes(&mut buf[0..2]); + (*self.pad.borrow()).to_bytes(&mut buf[2..16]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + code: Rc::new(RefCell::new(::from_bytes(&buf[0..2]))), + pad: Rc::new(RefCell::new(>::from_bytes(&buf[2..16]))), + } + } +} +#[derive()] +pub struct shape_b { + pub code: Value, + pub lo: Value, + pub hi: Value, + pub fill: Value>, +} +impl Default for shape_b { + fn default() -> Self { + shape_b { + code: >::default(), + lo: >::default(), + hi: >::default(), + fill: Rc::new(RefCell::new( + (0..8).map(|_| ::default()).collect::>(), + )), + } + } +} +impl ByteRepr for shape_b { + fn byte_size() -> usize { + 16 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.code.borrow()).to_bytes(&mut buf[0..2]); + (*self.lo.borrow()).to_bytes(&mut buf[2..4]); + (*self.hi.borrow()).to_bytes(&mut buf[4..8]); + (*self.fill.borrow()).to_bytes(&mut buf[8..16]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + code: Rc::new(RefCell::new(::from_bytes(&buf[0..2]))), + lo: Rc::new(RefCell::new(::from_bytes(&buf[2..4]))), + hi: Rc::new(RefCell::new(::from_bytes(&buf[4..8]))), + fill: Rc::new(RefCell::new(>::from_bytes(&buf[8..16]))), + } + } +} +#[derive(Clone)] +pub struct anon_0 { + __store: libcc2rs::UnionStorage, +} +impl anon_0 { + pub fn a(&self) -> Ptr { + self.__store.reinterpret(0) + } + pub fn b(&self) -> Ptr { + self.__store.reinterpret(0) + } + pub fn raw_(&self) -> Ptr> { + self.__store.reinterpret(0) + } +} +impl Default for anon_0 { + fn default() -> Self { + anon_0 { + __store: libcc2rs::UnionStorage::new(256), + } + } +} +impl ByteRepr for anon_0 { + fn byte_size() -> usize { + 256 + } + fn to_bytes(&self, buf: &mut [u8]) { + self.__store.to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { + anon_0 { + __store: libcc2rs::UnionStorage::from_bytes(buf), + } + } +} +#[derive(Default)] +pub struct Container { + pub view: Value, +} +impl ByteRepr for Container { + fn byte_size() -> usize { + 256 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.view.borrow()).to_bytes(&mut buf[0..256]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + view: Rc::new(RefCell::new(::from_bytes(&buf[0..256]))), + } + } +} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let c: Value = >::default(); + { + ((c.as_pointer()) as Ptr) + .to_any() + .memset((0) as u8, 256usize as usize); + ((c.as_pointer()) as Ptr).to_any().clone() + }; + assert!( + (((((*(*(*(*c.borrow()).view.borrow()).a().upgrade().deref()) + .code + .borrow()) as i32) + == 0) as i32) + != 0) + ); + assert!( + (((((*(*(*(*c.borrow()).view.borrow()).b().upgrade().deref()) + .lo + .borrow()) as i32) + == 0) as i32) + != 0) + ); + assert!( + ((((((*(*c.borrow()).view.borrow()).raw_().read())[(0) as usize] as i32) == 0) as i32) + != 0) + ); + assert!( + ((((((*(*c.borrow()).view.borrow()).raw_().read())[(255) as usize] as i32) == 0) as i32) + != 0) + ); + let src: Value> = Rc::new(RefCell::new(Box::new([ + 0_u8, + ::default(), + ::default(), + ::default(), + ::default(), + ::default(), + ::default(), + ::default(), + ::default(), + ::default(), + ::default(), + ::default(), + ::default(), + ::default(), + ::default(), + ::default(), + ]))); + (*src.borrow_mut())[(0) as usize] = 2_u8; + (*src.borrow_mut())[(2) as usize] = 80_u8; + (*src.borrow_mut())[(3) as usize] = 0_u8; + (*src.borrow_mut())[(4) as usize] = 127_u8; + (*src.borrow_mut())[(5) as usize] = 0_u8; + (*src.borrow_mut())[(6) as usize] = 0_u8; + (*src.borrow_mut())[(7) as usize] = 1_u8; + let len: Value = Rc::new(RefCell::new(16_usize)); + assert!(((((*len.borrow()) <= ::std::mem::size_of::<[u8; 256]>()) as i32) != 0)); + { + ((*(*c.borrow()).view.borrow()).raw_()) + .reinterpret_cast::() + .to_any() + .memcpy( + &((src.as_pointer() as Ptr) as Ptr).to_any(), + (*len.borrow()) as usize, + ); + ((*(*c.borrow()).view.borrow()).raw_()) + .reinterpret_cast::() + .to_any() + .clone() + }; + assert!( + (((((*(*(*(*c.borrow()).view.borrow()).b().upgrade().deref()) + .code + .borrow()) as i32) + == 2) as i32) + != 0) + ); + assert!( + ((((((((*(*(*c.borrow()).view.borrow()).b().upgrade().deref()) + .lo + .as_pointer()) + .reinterpret_cast::()) + .offset((0) as isize) + .read()) as i32) + == 80) as i32) + != 0) + ); + { + ((c.as_pointer()) as Ptr) + .to_any() + .memset((0) as u8, 256usize as usize); + ((c.as_pointer()) as Ptr).to_any().clone() + }; + assert!( + (((((*(*(*(*c.borrow()).view.borrow()).b().upgrade().deref()) + .code + .borrow()) as i32) + == 0) as i32) + != 0) + ); + return 0; +} diff --git a/tests/unit/out/refcount/union_nested.rs b/tests/unit/out/refcount/union_nested.rs new file mode 100644 index 00000000..e0efd00c --- /dev/null +++ b/tests/unit/out/refcount/union_nested.rs @@ -0,0 +1,197 @@ +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()] +pub struct record { + pub code: Value, + pub pad: Value>, +} +impl Default for record { + fn default() -> Self { + record { + code: >::default(), + pad: Rc::new(RefCell::new( + (0..14).map(|_| ::default()).collect::>(), + )), + } + } +} +impl ByteRepr for record { + fn byte_size() -> usize { + 16 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.code.borrow()).to_bytes(&mut buf[0..2]); + (*self.pad.borrow()).to_bytes(&mut buf[2..16]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + code: Rc::new(RefCell::new(::from_bytes(&buf[0..2]))), + pad: Rc::new(RefCell::new(>::from_bytes(&buf[2..16]))), + } + } +} +#[derive(Clone)] +pub struct anon_0 { + __store: libcc2rs::UnionStorage, +} +impl anon_0 { + pub fn h(&self) -> Ptr { + self.__store.reinterpret(0) + } + pub fn raw_(&self) -> Ptr> { + self.__store.reinterpret(0) + } +} +impl Default for anon_0 { + fn default() -> Self { + anon_0 { + __store: libcc2rs::UnionStorage::new(128), + } + } +} +impl ByteRepr for anon_0 { + fn byte_size() -> usize { + 128 + } + fn to_bytes(&self, buf: &mut [u8]) { + self.__store.to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { + anon_0 { + __store: libcc2rs::UnionStorage::from_bytes(buf), + } + } +} +#[derive(Default)] +pub struct inner { + pub view: Value, +} +impl ByteRepr for inner { + fn byte_size() -> usize { + 128 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.view.borrow()).to_bytes(&mut buf[0..128]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + view: Rc::new(RefCell::new(::from_bytes(&buf[0..128]))), + } + } +} +#[derive(Clone)] +pub struct anon_1 { + __store: libcc2rs::UnionStorage, +} +impl anon_1 { + pub fn h(&self) -> Ptr { + self.__store.reinterpret(0) + } + pub fn nested(&self) -> Ptr { + self.__store.reinterpret(0) + } +} +impl Default for anon_1 { + fn default() -> Self { + anon_1 { + __store: libcc2rs::UnionStorage::new(128), + } + } +} +impl ByteRepr for anon_1 { + fn byte_size() -> usize { + 128 + } + fn to_bytes(&self, buf: &mut [u8]) { + self.__store.to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { + anon_1 { + __store: libcc2rs::UnionStorage::from_bytes(buf), + } + } +} +#[derive(Default)] +pub struct Outer { + pub kind: Value, + pub level: Value, + pub variant: Value, + pub len: Value, + pub body: Value, +} +impl ByteRepr for Outer { + fn byte_size() -> usize { + 144 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.kind.borrow()).to_bytes(&mut buf[0..4]); + (*self.level.borrow()).to_bytes(&mut buf[4..8]); + (*self.variant.borrow()).to_bytes(&mut buf[8..12]); + (*self.len.borrow()).to_bytes(&mut buf[12..16]); + (*self.body.borrow()).to_bytes(&mut buf[16..144]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + kind: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), + level: Rc::new(RefCell::new(::from_bytes(&buf[4..8]))), + variant: Rc::new(RefCell::new(::from_bytes(&buf[8..12]))), + len: Rc::new(RefCell::new(::from_bytes(&buf[12..16]))), + body: Rc::new(RefCell::new(::from_bytes(&buf[16..144]))), + } + } +} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let ex: Value = >::default(); + { + ((ex.as_pointer()) as Ptr) + .to_any() + .memset((0) as u8, 144usize as usize); + ((ex.as_pointer()) as Ptr).to_any().clone() + }; + (*(*ex.borrow()).kind.borrow_mut()) = 2; + (*(*ex.borrow()).level.borrow_mut()) = 1; + (*(*ex.borrow()).variant.borrow_mut()) = 6; + (*(*ex.borrow()).len.borrow_mut()) = (16usize as u32); + (*(*(*(*ex.borrow()).body.borrow()).h().upgrade().deref()) + .code + .borrow_mut()) = 2_u16; + (*(*(*(*ex.borrow()).body.borrow()).h().upgrade().deref()) + .pad + .borrow_mut())[(0) as usize] = (('X' as i32) as u8); + assert!( + (((((*(*(*(*ex.borrow()).body.borrow()).h().upgrade().deref()) + .code + .borrow()) as i32) + == 2) as i32) + != 0) + ); + assert!( + (((((*(*(*(*ex.borrow()).body.borrow()).h().upgrade().deref()) + .pad + .borrow())[(0) as usize] as i32) + == ('X' as i32)) as i32) + != 0) + ); + assert!( + (((((*(*(*(*(*(*ex.borrow()).body.borrow()).nested().upgrade().deref()) + .view + .borrow()) + .h() + .upgrade() + .deref()) + .code + .borrow()) as i32) + == 2) as i32) + != 0) + ); + return 0; +} diff --git a/tests/unit/out/refcount/union_pointer_pun_address.rs b/tests/unit/out/refcount/union_pointer_pun_address.rs new file mode 100644 index 00000000..9b6136dd --- /dev/null +++ b/tests/unit/out/refcount/union_pointer_pun_address.rs @@ -0,0 +1,82 @@ +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(Default)] +pub struct node_a { + pub n: Value, +} +impl ByteRepr for node_a { + fn byte_size() -> usize { + 4 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.n.borrow()).to_bytes(&mut buf[0..4]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + n: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), + } + } +} +#[derive(Default)] +pub struct node_b { + pub data: Value, + pub next: Value>, +} +impl ByteRepr for node_b {} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let a: Value = Rc::new(RefCell::new(node_a { + n: Rc::new(RefCell::new(123)), + })); + #[derive(Clone)] + pub struct anon_0 { + __store: libcc2rs::UnionStorage, + } + impl anon_0 { + pub fn to_a(&self) -> Ptr> { + self.__store.reinterpret(0) + } + pub fn to_b(&self) -> Ptr> { + self.__store.reinterpret(0) + } + } + impl Default for anon_0 { + fn default() -> Self { + anon_0 { + __store: libcc2rs::UnionStorage::new(8), + } + } + } + impl ByteRepr for anon_0 { + fn byte_size() -> usize { + 8 + } + fn to_bytes(&self, buf: &mut [u8]) { + self.__store.to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { + anon_0 { + __store: libcc2rs::UnionStorage::from_bytes(buf), + } + } + }; + let ptr: Value = >::default(); + (*ptr.borrow_mut()).to_a().write((a.as_pointer())); + let out: Value> = Rc::new(RefCell::new(((*ptr.borrow()).to_b().read()).clone())); + assert!( + ((({ + let _lhs = (*out.borrow()).clone().to_any(); + _lhs == (a.as_pointer()).to_any() + }) as i32) + != 0) + ); + return 0; +} diff --git a/tests/unit/out/refcount/union_struct_dual_use.rs b/tests/unit/out/refcount/union_struct_dual_use.rs new file mode 100644 index 00000000..6b9666ca --- /dev/null +++ b/tests/unit/out/refcount/union_struct_dual_use.rs @@ -0,0 +1,130 @@ +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(Default)] +pub struct Inner { + pub a: Value, + pub b: Value, +} +impl ByteRepr for Inner { + fn byte_size() -> usize { + 8 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.a.borrow()).to_bytes(&mut buf[0..4]); + (*self.b.borrow()).to_bytes(&mut buf[4..8]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + a: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), + b: Rc::new(RefCell::new(::from_bytes(&buf[4..8]))), + } + } +} +pub fn sum_inner_0(i: Ptr) -> i32 { + let i: Value> = Rc::new(RefCell::new(i)); + return { + let _lhs = (*(*(*i.borrow()).upgrade().deref()).a.borrow()); + _lhs + (*(*(*i.borrow()).upgrade().deref()).b.borrow()) + }; +} +#[derive(Clone)] +pub struct anon_1 { + __store: libcc2rs::UnionStorage, +} +impl anon_1 { + pub fn inner(&self) -> Ptr { + self.__store.reinterpret(0) + } + pub fn raw_(&self) -> Ptr> { + self.__store.reinterpret(0) + } +} +impl Default for anon_1 { + fn default() -> Self { + anon_1 { + __store: libcc2rs::UnionStorage::new(16), + } + } +} +impl ByteRepr for anon_1 { + fn byte_size() -> usize { + 16 + } + fn to_bytes(&self, buf: &mut [u8]) { + self.__store.to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { + anon_1 { + __store: libcc2rs::UnionStorage::from_bytes(buf), + } + } +} +#[derive(Default)] +pub struct Outer { + pub u: Value, +} +impl ByteRepr for Outer { + fn byte_size() -> usize { + 16 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.u.borrow()).to_bytes(&mut buf[0..16]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + u: Rc::new(RefCell::new(::from_bytes(&buf[0..16]))), + } + } +} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let standalone: Value = >::default(); + (*(*standalone.borrow()).a.borrow_mut()) = 3; + (*(*standalone.borrow()).b.borrow_mut()) = 4; + assert!( + (((({ + let _i: Ptr = (standalone.as_pointer()); + sum_inner_0(_i) + }) == 7) as i32) + != 0) + ); + let outer: Value = >::default(); + { + ((outer.as_pointer()) as Ptr) + .to_any() + .memset((0) as u8, 16usize as usize); + ((outer.as_pointer()) as Ptr).to_any().clone() + }; + (*(*(*(*outer.borrow()).u.borrow()).inner().upgrade().deref()) + .a + .borrow_mut()) = 3; + (*(*(*(*outer.borrow()).u.borrow()).inner().upgrade().deref()) + .b + .borrow_mut()) = 4; + assert!( + (((({ + let _i: Ptr = ((*(*outer.borrow()).u.borrow()).inner()).clone(); + sum_inner_0(_i) + }) == 7) as i32) + != 0) + ); + assert!( + (((((((*(*outer.borrow()).u.borrow()).raw_().read())[(0) as usize] as u8) as i32) == 3) + as i32) + != 0) + ); + assert!( + (((((((*(*outer.borrow()).u.borrow()).raw_().read())[(4) as usize] as u8) as i32) == 4) + as i32) + != 0) + ); + return 0; +} diff --git a/tests/unit/out/refcount/union_tagged_simple.rs b/tests/unit/out/refcount/union_tagged_simple.rs new file mode 100644 index 00000000..344a9c22 --- /dev/null +++ b/tests/unit/out/refcount/union_tagged_simple.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, Copy, PartialEq, Debug, Default)] +enum Kind_enum { + #[default] + KIND_NONE = 0, + KIND_DONE = 1, +} +impl From for Kind_enum { + fn from(n: i32) -> Kind_enum { + match n { + 0 => Kind_enum::KIND_NONE, + 1 => Kind_enum::KIND_DONE, + _ => panic!("invalid Kind_enum value: {}", n), + } + } +} +libcc2rs::impl_enum_inc_dec!(Kind_enum); +#[derive(Clone)] +pub struct anon_0 { + __store: libcc2rs::UnionStorage, +} +impl anon_0 { + pub fn obj(&self) -> Ptr { + self.__store.reinterpret(0) + } + pub fn code(&self) -> Ptr { + self.__store.reinterpret(0) + } +} +impl Default for anon_0 { + fn default() -> Self { + anon_0 { + __store: libcc2rs::UnionStorage::new(8), + } + } +} +impl ByteRepr for anon_0 { + fn byte_size() -> usize { + 8 + } + fn to_bytes(&self, buf: &mut [u8]) { + self.__store.to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { + anon_0 { + __store: libcc2rs::UnionStorage::from_bytes(buf), + } + } +} +#[derive(Default)] +pub struct Event { + pub kind: Value, + pub handle: Value, + pub payload: Value, +} +impl ByteRepr for Event {} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let dummy: Value = Rc::new(RefCell::new(0)); + let m1: Value = >::default(); + (*(*m1.borrow()).kind.borrow_mut()) = Kind_enum::KIND_DONE; + (*(*m1.borrow()).handle.borrow_mut()) = ((dummy.as_pointer()) as Ptr).to_any(); + (*(*m1.borrow()).payload.borrow_mut()).code().write(42); + assert!( + (((((*(*m1.borrow()).kind.borrow()) as u32) == ((Kind_enum::KIND_DONE as i32) as u32)) + as i32) + != 0) + ); + assert!((((((*(*m1.borrow()).payload.borrow()).code().read()) == 42) as i32) != 0)); + let m2: Value = >::default(); + (*(*m2.borrow()).kind.borrow_mut()) = Kind_enum::KIND_NONE; + (*(*m2.borrow()).handle.borrow_mut()) = ((dummy.as_pointer()) as Ptr).to_any(); + (*(*m2.borrow()).payload.borrow_mut()) + .obj() + .write(((dummy.as_pointer()) as Ptr).to_any()); + assert!( + ((({ + let _lhs = ((*(*m2.borrow()).payload.borrow()).obj().read()).clone(); + _lhs == ((dummy.as_pointer()) as Ptr).to_any() + }) as i32) + != 0) + ); + return 0; +} diff --git a/tests/unit/union_addrof_external.c b/tests/unit/union_addrof_external.c index 59dc281b..9682f467 100644 --- a/tests/unit/union_addrof_external.c +++ b/tests/unit/union_addrof_external.c @@ -1,4 +1,4 @@ -// no-compile: refcount +// panic: refcount #include #include #include diff --git a/tests/unit/union_memset_memcpy.c b/tests/unit/union_memset_memcpy.c index b4a270b6..175a1f47 100644 --- a/tests/unit/union_memset_memcpy.c +++ b/tests/unit/union_memset_memcpy.c @@ -1,4 +1,4 @@ -// no-compile: refcount +// panic: refcount #include #include #include From 25cf021c0e31a94a9ebb8adee8ee769a795c6636 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 24 Jun 2026 11:52:38 +0100 Subject: [PATCH 17/29] Reinterpret cast on aliasing pointers --- cpp2rust/converter/models/converter_refcount.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index 5156a730..e8ffa1f8 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -1296,9 +1296,17 @@ bool ConverterRefCount::VisitExplicitCastExpr(clang::ExplicitCastExpr *expr) { } else if (expr->getSubExpr()->getType()->isPointerType() && !expr->getSubExpr()->isNullPointerConstant( ctx_, clang::Expr::NPC_ValueDependentIsNull)) { - StrCat(std::format("({}.to_strong().as_pointer() as {})", - ToString(expr->getSubExpr()), - ToString(expr->getType()))); + auto src_pointee = expr->getSubExpr()->getType()->getPointeeType(); + auto dst_pointee = expr->getType()->getPointeeType(); + if (ctx_.hasSameUnqualifiedType(src_pointee, dst_pointee)) { + StrCat(std::format("({}.to_strong().as_pointer() as {})", + ToString(expr->getSubExpr()), + ToString(expr->getType()))); + } else { + StrCat(std::format("{}.reinterpret_cast::<{}>()", + ToString(expr->getSubExpr()), + ConvertPointeeType(expr->getType()))); + } return false; } return Converter::VisitExplicitCastExpr(expr); From 74532a73154bbf6875887d3f8d3f53bc7624c6e7 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 24 Jun 2026 11:55:04 +0100 Subject: [PATCH 18/29] Update tests --- .../out/refcount/union_addrof_external.rs | 113 ++++++++++++++---- tests/unit/union_addrof_external.c | 1 - 2 files changed, 87 insertions(+), 27 deletions(-) diff --git a/tests/unit/out/refcount/union_addrof_external.rs b/tests/unit/out/refcount/union_addrof_external.rs index c8a203d3..441338f9 100644 --- a/tests/unit/out/refcount/union_addrof_external.rs +++ b/tests/unit/out/refcount/union_addrof_external.rs @@ -25,18 +25,74 @@ impl Default for record { } } } -impl ByteRepr for record {} -#[derive()] -pub union anon_0 { - pub h: Value, - pub raw_: Value>, +impl ByteRepr for record { + fn byte_size() -> usize { + 16 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.code.borrow()).to_bytes(&mut buf[0..2]); + (*self.lo.borrow()).to_bytes(&mut buf[2..4]); + (*self.hi.borrow()).to_bytes(&mut buf[4..8]); + (*self.pad.borrow()).to_bytes(&mut buf[8..16]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + code: Rc::new(RefCell::new(::from_bytes(&buf[0..2]))), + lo: Rc::new(RefCell::new(::from_bytes(&buf[2..4]))), + hi: Rc::new(RefCell::new(::from_bytes(&buf[4..8]))), + pad: Rc::new(RefCell::new(>::from_bytes(&buf[8..16]))), + } + } +} +#[derive(Clone)] +pub struct anon_0 { + __store: libcc2rs::UnionStorage, +} +impl anon_0 { + pub fn h(&self) -> Ptr { + self.__store.reinterpret(0) + } + pub fn raw_(&self) -> Ptr> { + self.__store.reinterpret(0) + } +} +impl Default for anon_0 { + fn default() -> Self { + anon_0 { + __store: libcc2rs::UnionStorage::new(128), + } + } +} +impl ByteRepr for anon_0 { + fn byte_size() -> usize { + 128 + } + fn to_bytes(&self, buf: &mut [u8]) { + self.__store.to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { + anon_0 { + __store: libcc2rs::UnionStorage::from_bytes(buf), + } + } } -impl ByteRepr for anon_0 {} #[derive(Default)] pub struct Container { pub view: Value, } -impl ByteRepr for Container {} +impl ByteRepr for Container { + fn byte_size() -> usize { + 128 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.view.borrow()).to_bytes(&mut buf[0..128]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + view: Rc::new(RefCell::new(::from_bytes(&buf[0..128]))), + } + } +} pub fn fill_1(out: AnyPtr, cap: usize) { let out: Value = Rc::new(RefCell::new(out)); let cap: Value = Rc::new(RefCell::new(cap)); @@ -67,11 +123,11 @@ pub fn fill_1(out: AnyPtr, cap: usize) { (*src.borrow_mut())[(6) as usize] = 0_u8; (*src.borrow_mut())[(7) as usize] = 1_u8; let n: Value = Rc::new(RefCell::new( - if (((::std::mem::size_of::<[u8; 16]>() < (*cap.borrow())) as i32) != 0) { - ::std::mem::size_of::<[u8; 16]>() + (if (((::std::mem::size_of::<[u8; 16]>() < (*cap.borrow())) as i32) != 0) { + (::std::mem::size_of::<[u8; 16]>() as u64) } else { - (*cap.borrow()) - }, + ((*cap.borrow()) as u64) + } as usize), )); { (*out.borrow()).memcpy( @@ -89,42 +145,47 @@ fn main_0() -> i32 { { ((c.as_pointer()) as Ptr) .to_any() - .memset((0) as u8, ::std::mem::size_of::() as usize); + .memset((0) as u8, 128usize as usize); ((c.as_pointer()) as Ptr).to_any().clone() }; ({ let _out: AnyPtr = ((*c.borrow()).view.as_pointer()).to_any(); - let _cap: usize = ::std::mem::size_of::(); + let _cap: usize = 128usize; fill_1(_out, _cap) }); assert!( - (((((*(*(*(*c.borrow()).view.borrow()).h.borrow()).code.borrow()) as i32) == 2) as i32) + (((((*(*(*(*c.borrow()).view.borrow()).h().upgrade().deref()) + .code + .borrow()) as i32) + == 2) as i32) != 0) ); assert!( - ((((((((*(*(*c.borrow()).view.borrow()).h.borrow()).lo.as_pointer()) - .to_strong() - .as_pointer() as Ptr::) - .offset((0) as isize) - .read()) as i32) + ((((((((*(*(*c.borrow()).view.borrow()).h().upgrade().deref()) + .lo + .as_pointer()) + .reinterpret_cast::()) + .offset((0) as isize) + .read()) as i32) == 0) as i32) != 0) ); assert!( - ((((((((*(*(*c.borrow()).view.borrow()).h.borrow()).lo.as_pointer()) - .to_strong() - .as_pointer() as Ptr::) - .offset((1) as isize) - .read()) as i32) + ((((((((*(*(*c.borrow()).view.borrow()).h().upgrade().deref()) + .lo + .as_pointer()) + .reinterpret_cast::()) + .offset((1) as isize) + .read()) as i32) == 80) as i32) != 0) ); assert!( - (((((*(*(*c.borrow()).view.borrow()).raw_.borrow())[(0) as usize] as i32) == 2) as i32) + ((((((*(*c.borrow()).view.borrow()).raw_().read())[(0) as usize] as i32) == 2) as i32) != 0) ); assert!( - ((((((*(*(*c.borrow()).view.borrow()).raw_.borrow())[(3) as usize] as u8) as i32) == 80) + (((((((*(*c.borrow()).view.borrow()).raw_().read())[(3) as usize] as u8) as i32) == 80) as i32) != 0) ); diff --git a/tests/unit/union_addrof_external.c b/tests/unit/union_addrof_external.c index 9682f467..64adaf26 100644 --- a/tests/unit/union_addrof_external.c +++ b/tests/unit/union_addrof_external.c @@ -1,4 +1,3 @@ -// panic: refcount #include #include #include From 10182036c913b90bff44d20a5e1c90c2d17ea01a Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 24 Jun 2026 13:42:15 +0100 Subject: [PATCH 19/29] Create fresh pointer from union member --- cpp2rust/converter/models/converter_refcount.cpp | 2 +- tests/unit/out/refcount/union_cross_arm_cast.rs | 1 - tests/unit/out/refcount/union_struct_dual_use.rs | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index e8ffa1f8..74be1c18 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -1526,7 +1526,7 @@ bool ConverterRefCount::VisitMemberExpr(clang::MemberExpr *expr) { if (isAddrOf()) { StrCat(str); - computed_expr_type_ = ComputedExprType::Pointer; + computed_expr_type_ = ComputedExprType::FreshPointer; return false; } if (isLValue()) { diff --git a/tests/unit/out/refcount/union_cross_arm_cast.rs b/tests/unit/out/refcount/union_cross_arm_cast.rs index b6bfef6d..45f6c684 100644 --- a/tests/unit/out/refcount/union_cross_arm_cast.rs +++ b/tests/unit/out/refcount/union_cross_arm_cast.rs @@ -149,7 +149,6 @@ fn main_0() -> i32 { .borrow_mut()) = 10_u16; (*(*c.borrow()).len.borrow_mut()) = (28usize as u32); (*(*(((*(*c.borrow()).u.borrow()).a()) - .clone() .to_any() .cast::() .expect("ub:wrong type")) diff --git a/tests/unit/out/refcount/union_struct_dual_use.rs b/tests/unit/out/refcount/union_struct_dual_use.rs index 6b9666ca..82002175 100644 --- a/tests/unit/out/refcount/union_struct_dual_use.rs +++ b/tests/unit/out/refcount/union_struct_dual_use.rs @@ -111,7 +111,7 @@ fn main_0() -> i32 { .borrow_mut()) = 4; assert!( (((({ - let _i: Ptr = ((*(*outer.borrow()).u.borrow()).inner()).clone(); + let _i: Ptr = ((*(*outer.borrow()).u.borrow()).inner()); sum_inner_0(_i) }) == 7) as i32) != 0) From 78a63614b2a408466720ba29fccb9a4e63669530 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 24 Jun 2026 13:51:27 +0100 Subject: [PATCH 20/29] Add reinterpret_cast on addrof array --- cpp2rust/converter/models/converter_refcount.cpp | 10 +++++++++- tests/unit/out/refcount/union_cross_arm_cast.rs | 14 ++++++++------ tests/unit/out/refcount/union_memset_memcpy.rs | 10 ++++++---- 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index 74be1c18..7d2e64f4 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -1525,7 +1525,15 @@ bool ConverterRefCount::VisitMemberExpr(clang::MemberExpr *expr) { str += "()"; if (isAddrOf()) { - StrCat(str); + if (member->getType()->isArrayType()) { + PushConversionKind push(*this, ConversionKind::Unboxed); + StrCat(std::format( + "{}.reinterpret_cast::<{}>()", str, + ToString( + member->getType()->getAsArrayTypeUnsafe()->getElementType()))); + } else { + StrCat(str); + } computed_expr_type_ = ComputedExprType::FreshPointer; return false; } diff --git a/tests/unit/out/refcount/union_cross_arm_cast.rs b/tests/unit/out/refcount/union_cross_arm_cast.rs index 45f6c684..f1175091 100644 --- a/tests/unit/out/refcount/union_cross_arm_cast.rs +++ b/tests/unit/out/refcount/union_cross_arm_cast.rs @@ -174,16 +174,18 @@ fn main_0() -> i32 { .lo .borrow_mut()) = 8080_u16; assert!( - ((((((((*(*c.borrow()).u.borrow()).raw_()).reinterpret_cast::()) - .offset((2) as isize) - .read()) as i32) + ((((((((*(*c.borrow()).u.borrow()).raw_().reinterpret_cast::()) + .reinterpret_cast::()) + .offset((2) as isize) + .read()) as i32) == 144) as i32) != 0) ); assert!( - ((((((((*(*c.borrow()).u.borrow()).raw_()).reinterpret_cast::()) - .offset((3) as isize) - .read()) as i32) + ((((((((*(*c.borrow()).u.borrow()).raw_().reinterpret_cast::()) + .reinterpret_cast::()) + .offset((3) as isize) + .read()) as i32) == 31) as i32) != 0) ); diff --git a/tests/unit/out/refcount/union_memset_memcpy.rs b/tests/unit/out/refcount/union_memset_memcpy.rs index 712efc36..2bd6739e 100644 --- a/tests/unit/out/refcount/union_memset_memcpy.rs +++ b/tests/unit/out/refcount/union_memset_memcpy.rs @@ -187,15 +187,17 @@ fn main_0() -> i32 { let len: Value = Rc::new(RefCell::new(16_usize)); assert!(((((*len.borrow()) <= ::std::mem::size_of::<[u8; 256]>()) as i32) != 0)); { - ((*(*c.borrow()).view.borrow()).raw_()) - .reinterpret_cast::() + (((*(*c.borrow()).view.borrow()) + .raw_() + .reinterpret_cast::()) as Ptr) .to_any() .memcpy( &((src.as_pointer() as Ptr) as Ptr).to_any(), (*len.borrow()) as usize, ); - ((*(*c.borrow()).view.borrow()).raw_()) - .reinterpret_cast::() + (((*(*c.borrow()).view.borrow()) + .raw_() + .reinterpret_cast::()) as Ptr) .to_any() .clone() }; From ebcfc6ae0e3c0ca82f35aef78c430fa9e62f7621 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 24 Jun 2026 14:26:18 +0100 Subject: [PATCH 21/29] Panic on default byte_size implementation --- libcc2rs/src/reinterpret.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/libcc2rs/src/reinterpret.rs b/libcc2rs/src/reinterpret.rs index 623c7060..a05dcfb2 100644 --- a/libcc2rs/src/reinterpret.rs +++ b/libcc2rs/src/reinterpret.rs @@ -8,7 +8,7 @@ pub trait ByteRepr: 'static { where Self: Sized, { - std::mem::size_of::() + panic!("byte_size is not implemented for {}", std::any::type_name::()) } fn to_bytes(&self, _buf: &mut [u8]) { panic!("ByteRepr not supported for this type"); @@ -24,6 +24,10 @@ pub trait ByteRepr: 'static { macro_rules! impl_byte_repr { ($ty:ty) => { impl ByteRepr for $ty { + #[inline] + fn byte_size() -> usize { + std::mem::size_of::<$ty>() + } #[inline] fn to_bytes(&self, buf: &mut [u8]) { buf.copy_from_slice(&self.to_ne_bytes()); @@ -52,6 +56,10 @@ impl_byte_repr!(f32); impl_byte_repr!(f64); impl ByteRepr for bool { + #[inline] + fn byte_size() -> usize { + 1 + } #[inline] fn to_bytes(&self, buf: &mut [u8]) { buf[0] = *self as u8; From 039b9d07b09ac5c5b96cca7d26eded5acfb5a37e Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 24 Jun 2026 15:28:17 +0100 Subject: [PATCH 22/29] Add ReinterpretedView::byte_size to encode constant size of arrays --- .../converter/models/converter_refcount.cpp | 7 +-- libcc2rs/src/rc.rs | 43 ++++++++++--------- libcc2rs/src/reinterpret.rs | 5 ++- libcc2rs/src/union.rs | 4 +- .../refcount/tag_vs_identifier_collision.rs | 8 ++-- .../out/refcount/union_addrof_external.rs | 4 +- tests/unit/out/refcount/union_basic.rs | 4 +- .../unit/out/refcount/union_cross_arm_cast.rs | 6 +-- .../unit/out/refcount/union_memset_memcpy.rs | 6 +-- tests/unit/out/refcount/union_nested.rs | 8 ++-- .../out/refcount/union_pointer_pun_address.rs | 4 +- .../union_pointer_pun_writethrough.rs | 4 +- .../out/refcount/union_struct_dual_use.rs | 4 +- .../out/refcount/union_tagged_struct_arms.rs | 6 +-- tests/unit/union_memset_memcpy.c | 1 - 15 files changed, 60 insertions(+), 54 deletions(-) diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index 7d2e64f4..4c606925 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -500,9 +500,10 @@ void ConverterRefCount::EmitRustUnion(clang::RecordDecl *decl) { PushConversionKind push(*this, ConversionKind::FullRefCount); std::string storage_ty = ToString(field->getType()); Unwrap(storage_ty, "Value<", ">"); - StrCat(std::format( - "pub fn {}(&self) -> Ptr<{}> {{ self.__store.reinterpret(0) }}", - GetNamedDeclAsString(field), storage_ty)); + auto byte_size = ctx_.getTypeSize(field->getType()) / 8; + StrCat(std::format("pub fn {}(&self) -> Ptr<{}> {{ " + "self.__store.reinterpret_sized(0, {}) }}", + GetNamedDeclAsString(field), storage_ty, byte_size)); } } diff --git a/libcc2rs/src/rc.rs b/libcc2rs/src/rc.rs index 64fd4b72..6c70613c 100644 --- a/libcc2rs/src/rc.rs +++ b/libcc2rs/src/rc.rs @@ -19,8 +19,8 @@ pub type Value = Rc>; struct ReinterpretedView { // Pointer to the source of reinterpret alloc: Rc, - // C++ size of the reinterpreted view - elem_byte_size: usize, + // C++ byte size of one viewed value + byte_size: usize, } #[derive(Default)] @@ -48,6 +48,7 @@ pub enum StrongPtr { Reinterpreted { alloc: Rc, byte_offset: usize, + byte_size: usize, // Local buffer for deref(). None until first access. // Read-through: refreshed from alloc on every deref() call. cell: RefCell>, @@ -63,10 +64,11 @@ impl StrongPtr { StrongPtr::Reinterpreted { alloc, byte_offset, + byte_size, cell, } => { // Read-through: always re-read from the original allocation. - let mut buf = vec![0u8; T::byte_size()]; + let mut buf = vec![0u8; *byte_size]; alloc.read_bytes(*byte_offset, &mut buf); *cell.borrow_mut() = Some(T::from_bytes(&buf)); Ref::map(cell.borrow(), |opt| opt.as_ref().unwrap()) @@ -258,7 +260,7 @@ impl Ptr { #[inline] fn elem_step(&self) -> usize { match &self.kind { - PtrKind::Reinterpreted(view) => view.elem_byte_size, + PtrKind::Reinterpreted(view) => view.byte_size, _ => 1, } } @@ -272,7 +274,7 @@ impl Ptr { PtrKind::StackArray(weak) | PtrKind::HeapArray(weak) => { weak.upgrade().expect("ub: dangling pointer").borrow().len() } - PtrKind::Reinterpreted(view) => view.alloc.total_byte_len() / view.elem_byte_size, + PtrKind::Reinterpreted(view) => view.alloc.total_byte_len() / view.byte_size, } } @@ -349,6 +351,7 @@ impl Ptr { PtrKind::Reinterpreted(view) => StrongPtr::Reinterpreted { alloc: Rc::clone(&view.alloc), byte_offset: self.offset, + byte_size: view.byte_size, cell: RefCell::new(None), }, } @@ -373,7 +376,7 @@ impl Ptr { rc.borrow_mut()[self.offset] = value; } PtrKind::Reinterpreted(view) => { - let mut buf = vec![0u8; T::byte_size()]; + let mut buf = vec![0u8; view.byte_size]; value.to_bytes(&mut buf); view.alloc.write_bytes(self.offset, &buf); } @@ -402,20 +405,19 @@ impl Ptr { panic!("cannot reinterpret_cast to zero-sized type"); } - let src_byte_off = self.offset.wrapping_mul(T::byte_size()); let (alloc, abs_byte_off): (Rc, usize) = match &self.kind { PtrKind::Null => return Ptr::null(), PtrKind::StackSingle(weak) | PtrKind::HeapSingle(weak) => ( Rc::new(SingleOriginalAlloc { weak: weak.clone() }), - src_byte_off, + self.offset.wrapping_mul(T::byte_size()), ), PtrKind::Vec(weak) => ( Rc::new(SliceOriginalAlloc { weak: weak.clone() }), - src_byte_off, + self.offset.wrapping_mul(T::byte_size()), ), PtrKind::StackArray(weak) | PtrKind::HeapArray(weak) => ( Rc::new(SliceOriginalAlloc { weak: weak.clone() }), - src_byte_off, + self.offset.wrapping_mul(T::byte_size()), ), PtrKind::Reinterpreted(view) => (Rc::clone(&view.alloc), self.offset), }; @@ -424,7 +426,7 @@ impl Ptr { offset: abs_byte_off, kind: PtrKind::Reinterpreted(Rc::new(ReinterpretedView { alloc, - elem_byte_size: U::byte_size(), + byte_size: U::byte_size(), })), } } @@ -453,7 +455,7 @@ impl Ptr { f(&mut borrow[self.offset]) } PtrKind::Reinterpreted(view) => { - let mut buf = vec![0u8; T::byte_size()]; + let mut buf = vec![0u8; view.byte_size]; view.alloc.read_bytes(self.offset, &mut buf); let mut val = T::from_bytes(&buf); let ret = f(&mut val); @@ -486,7 +488,7 @@ impl Ptr { f(&borrow[self.offset]) } PtrKind::Reinterpreted(view) => { - let mut buf = vec![0u8; T::byte_size()]; + let mut buf = vec![0u8; view.byte_size]; view.alloc.read_bytes(self.offset, &mut buf); let val = T::from_bytes(&buf); f(&val) @@ -513,7 +515,7 @@ impl Ptr { weak.upgrade().expect("ub: dangling pointer").borrow()[self.offset].clone() } PtrKind::Reinterpreted(ref view) => { - let mut buf = vec![0u8; T::byte_size()]; + let mut buf = vec![0u8; view.byte_size]; view.alloc.read_bytes(self.offset, &mut buf); T::from_bytes(&buf) } @@ -1203,14 +1205,15 @@ impl AsPointerDyn for Rc> { impl ByteRepr for Ptr {} -impl Ptr { - pub(crate) fn reinterpreted(alloc: Rc, byte_offset: usize) -> Self { +impl Ptr { + pub(crate) fn reinterpreted_sized( + alloc: Rc, + byte_offset: usize, + byte_size: usize, + ) -> Self { Ptr { offset: byte_offset, - kind: PtrKind::Reinterpreted(Rc::new(ReinterpretedView { - alloc, - elem_byte_size: T::byte_size(), - })), + kind: PtrKind::Reinterpreted(Rc::new(ReinterpretedView { alloc, byte_size })), } } } diff --git a/libcc2rs/src/reinterpret.rs b/libcc2rs/src/reinterpret.rs index a05dcfb2..1c288f1a 100644 --- a/libcc2rs/src/reinterpret.rs +++ b/libcc2rs/src/reinterpret.rs @@ -8,7 +8,10 @@ pub trait ByteRepr: 'static { where Self: Sized, { - panic!("byte_size is not implemented for {}", std::any::type_name::()) + panic!( + "byte_size is not implemented for {}", + std::any::type_name::() + ) } fn to_bytes(&self, _buf: &mut [u8]) { panic!("ByteRepr not supported for this type"); diff --git a/libcc2rs/src/union.rs b/libcc2rs/src/union.rs index 759ace7e..f3d17ab7 100644 --- a/libcc2rs/src/union.rs +++ b/libcc2rs/src/union.rs @@ -17,11 +17,11 @@ impl UnionStorage { } } - pub fn reinterpret(&self, offset: usize) -> Ptr { + pub fn reinterpret_sized(&self, start: usize, end: usize) -> Ptr { let alloc: Rc = Rc::new(SliceOriginalAlloc { weak: Rc::downgrade(&self.bytes), }); - Ptr::reinterpreted(alloc, offset) + Ptr::reinterpreted_sized(alloc, start, end - start) } } diff --git a/tests/unit/out/refcount/tag_vs_identifier_collision.rs b/tests/unit/out/refcount/tag_vs_identifier_collision.rs index 5df7172a..e2269f41 100644 --- a/tests/unit/out/refcount/tag_vs_identifier_collision.rs +++ b/tests/unit/out/refcount/tag_vs_identifier_collision.rs @@ -56,10 +56,10 @@ pub struct point { } impl point { pub fn whole(&self) -> Ptr { - self.__store.reinterpret(0) + self.__store.reinterpret_sized(0, 4) } pub fn half(&self) -> Ptr { - self.__store.reinterpret(0) + self.__store.reinterpret_sized(0, 2) } } impl Default for point { @@ -88,10 +88,10 @@ pub struct slot_union { } impl slot_union { pub fn i(&self) -> Ptr { - self.__store.reinterpret(0) + self.__store.reinterpret_sized(0, 4) } pub fn u(&self) -> Ptr { - self.__store.reinterpret(0) + self.__store.reinterpret_sized(0, 4) } } impl Default for slot_union { diff --git a/tests/unit/out/refcount/union_addrof_external.rs b/tests/unit/out/refcount/union_addrof_external.rs index 441338f9..3411393e 100644 --- a/tests/unit/out/refcount/union_addrof_external.rs +++ b/tests/unit/out/refcount/union_addrof_external.rs @@ -50,10 +50,10 @@ pub struct anon_0 { } impl anon_0 { pub fn h(&self) -> Ptr { - self.__store.reinterpret(0) + self.__store.reinterpret_sized(0, 16) } pub fn raw_(&self) -> Ptr> { - self.__store.reinterpret(0) + self.__store.reinterpret_sized(0, 128) } } impl Default for anon_0 { diff --git a/tests/unit/out/refcount/union_basic.rs b/tests/unit/out/refcount/union_basic.rs index 96d01775..ac455be8 100644 --- a/tests/unit/out/refcount/union_basic.rs +++ b/tests/unit/out/refcount/union_basic.rs @@ -12,10 +12,10 @@ pub struct basic { } impl basic { pub fn i(&self) -> Ptr { - self.__store.reinterpret(0) + self.__store.reinterpret_sized(0, 4) } pub fn f(&self) -> Ptr { - self.__store.reinterpret(0) + self.__store.reinterpret_sized(0, 4) } } impl Default for basic { diff --git a/tests/unit/out/refcount/union_cross_arm_cast.rs b/tests/unit/out/refcount/union_cross_arm_cast.rs index f1175091..3478eb4d 100644 --- a/tests/unit/out/refcount/union_cross_arm_cast.rs +++ b/tests/unit/out/refcount/union_cross_arm_cast.rs @@ -84,13 +84,13 @@ pub struct anon_0 { } impl anon_0 { pub fn a(&self) -> Ptr { - self.__store.reinterpret(0) + self.__store.reinterpret_sized(0, 16) } pub fn b(&self) -> Ptr { - self.__store.reinterpret(0) + self.__store.reinterpret_sized(0, 28) } pub fn raw_(&self) -> Ptr> { - self.__store.reinterpret(0) + self.__store.reinterpret_sized(0, 64) } } impl Default for anon_0 { diff --git a/tests/unit/out/refcount/union_memset_memcpy.rs b/tests/unit/out/refcount/union_memset_memcpy.rs index 2bd6739e..58a2c94a 100644 --- a/tests/unit/out/refcount/union_memset_memcpy.rs +++ b/tests/unit/out/refcount/union_memset_memcpy.rs @@ -80,13 +80,13 @@ pub struct anon_0 { } impl anon_0 { pub fn a(&self) -> Ptr { - self.__store.reinterpret(0) + self.__store.reinterpret_sized(0, 16) } pub fn b(&self) -> Ptr { - self.__store.reinterpret(0) + self.__store.reinterpret_sized(0, 16) } pub fn raw_(&self) -> Ptr> { - self.__store.reinterpret(0) + self.__store.reinterpret_sized(0, 256) } } impl Default for anon_0 { diff --git a/tests/unit/out/refcount/union_nested.rs b/tests/unit/out/refcount/union_nested.rs index e0efd00c..bc91925d 100644 --- a/tests/unit/out/refcount/union_nested.rs +++ b/tests/unit/out/refcount/union_nested.rs @@ -42,10 +42,10 @@ pub struct anon_0 { } impl anon_0 { pub fn h(&self) -> Ptr { - self.__store.reinterpret(0) + self.__store.reinterpret_sized(0, 16) } pub fn raw_(&self) -> Ptr> { - self.__store.reinterpret(0) + self.__store.reinterpret_sized(0, 128) } } impl Default for anon_0 { @@ -91,10 +91,10 @@ pub struct anon_1 { } impl anon_1 { pub fn h(&self) -> Ptr { - self.__store.reinterpret(0) + self.__store.reinterpret_sized(0, 16) } pub fn nested(&self) -> Ptr { - self.__store.reinterpret(0) + self.__store.reinterpret_sized(0, 128) } } impl Default for anon_1 { diff --git a/tests/unit/out/refcount/union_pointer_pun_address.rs b/tests/unit/out/refcount/union_pointer_pun_address.rs index 9b6136dd..bb982414 100644 --- a/tests/unit/out/refcount/union_pointer_pun_address.rs +++ b/tests/unit/out/refcount/union_pointer_pun_address.rs @@ -42,10 +42,10 @@ fn main_0() -> i32 { } impl anon_0 { pub fn to_a(&self) -> Ptr> { - self.__store.reinterpret(0) + self.__store.reinterpret_sized(0, 8) } pub fn to_b(&self) -> Ptr> { - self.__store.reinterpret(0) + self.__store.reinterpret_sized(0, 8) } } impl Default for anon_0 { diff --git a/tests/unit/out/refcount/union_pointer_pun_writethrough.rs b/tests/unit/out/refcount/union_pointer_pun_writethrough.rs index 598e3921..430d2165 100644 --- a/tests/unit/out/refcount/union_pointer_pun_writethrough.rs +++ b/tests/unit/out/refcount/union_pointer_pun_writethrough.rs @@ -17,10 +17,10 @@ fn main_0() -> i32 { } impl anon_0 { pub fn as_unsigned(&self) -> Ptr> { - self.__store.reinterpret(0) + self.__store.reinterpret_sized(0, 8) } pub fn as_signed(&self) -> Ptr> { - self.__store.reinterpret(0) + self.__store.reinterpret_sized(0, 8) } } impl Default for anon_0 { diff --git a/tests/unit/out/refcount/union_struct_dual_use.rs b/tests/unit/out/refcount/union_struct_dual_use.rs index 82002175..c5a64d3d 100644 --- a/tests/unit/out/refcount/union_struct_dual_use.rs +++ b/tests/unit/out/refcount/union_struct_dual_use.rs @@ -39,10 +39,10 @@ pub struct anon_1 { } impl anon_1 { pub fn inner(&self) -> Ptr { - self.__store.reinterpret(0) + self.__store.reinterpret_sized(0, 8) } pub fn raw_(&self) -> Ptr> { - self.__store.reinterpret(0) + self.__store.reinterpret_sized(0, 16) } } impl Default for anon_1 { diff --git a/tests/unit/out/refcount/union_tagged_struct_arms.rs b/tests/unit/out/refcount/union_tagged_struct_arms.rs index d675186f..32d0de4e 100644 --- a/tests/unit/out/refcount/union_tagged_struct_arms.rs +++ b/tests/unit/out/refcount/union_tagged_struct_arms.rs @@ -92,13 +92,13 @@ pub struct anon_0 { } impl anon_0 { pub fn list(&self) -> Ptr { - self.__store.reinterpret(0) + self.__store.reinterpret_sized(0, 24) } pub fn letters(&self) -> Ptr { - self.__store.reinterpret(0) + self.__store.reinterpret_sized(0, 16) } pub fn integers(&self) -> Ptr { - self.__store.reinterpret(0) + self.__store.reinterpret_sized(0, 40) } } impl Default for anon_0 { diff --git a/tests/unit/union_memset_memcpy.c b/tests/unit/union_memset_memcpy.c index 175a1f47..4b9c7877 100644 --- a/tests/unit/union_memset_memcpy.c +++ b/tests/unit/union_memset_memcpy.c @@ -1,4 +1,3 @@ -// panic: refcount #include #include #include From 32194b114fc5bb396ee46760a668186823bacb5d Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 24 Jun 2026 15:38:09 +0100 Subject: [PATCH 23/29] Add name of struct that does not implement ByteRepr --- libcc2rs/src/reinterpret.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/libcc2rs/src/reinterpret.rs b/libcc2rs/src/reinterpret.rs index 1c288f1a..afb34376 100644 --- a/libcc2rs/src/reinterpret.rs +++ b/libcc2rs/src/reinterpret.rs @@ -14,13 +14,19 @@ pub trait ByteRepr: 'static { ) } fn to_bytes(&self, _buf: &mut [u8]) { - panic!("ByteRepr not supported for this type"); + panic!( + "to_bytes is not implemented for {}", + std::any::type_name::() + ) } fn from_bytes(_buf: &[u8]) -> Self where Self: Sized, { - panic!("ByteRepr not supported for this type"); + panic!( + "from_bytes is not implemented for {}", + std::any::type_name::() + ) } } From f6b734429b9e701bec1aa5fdf105009ad97e9373 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 24 Jun 2026 15:38:31 +0100 Subject: [PATCH 24/29] Add ByteRepr for enums --- cpp2rust/converter/converter.cpp | 3 +++ cpp2rust/converter/converter.h | 2 ++ cpp2rust/converter/converter_lib.cpp | 3 --- cpp2rust/converter/models/converter_refcount.cpp | 13 +++++++++++++ cpp2rust/converter/models/converter_refcount.h | 2 ++ 5 files changed, 20 insertions(+), 3 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 1a00fc6c..69cfbfab 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -3165,6 +3165,7 @@ bool Converter::VisitEnumDecl(clang::EnumDecl *decl) { AddFromImpl(decl); AddIncDecImpls(decl); + AddByteReprTrait(decl); return false; } @@ -3947,6 +3948,8 @@ void Converter::EmitDefaultStructLiteral(const clang::RecordDecl *decl) { void Converter::AddByteReprTrait(const clang::RecordDecl *decl) {} +void Converter::AddByteReprTrait(const clang::EnumDecl *decl) {} + void Converter::ConvertUnsignedArithBinaryOperator(clang::BinaryOperator *op, clang::Expr *expr) { StrCat(token::kDot); diff --git a/cpp2rust/converter/converter.h b/cpp2rust/converter/converter.h index 6fe344b2..fbdd4e59 100644 --- a/cpp2rust/converter/converter.h +++ b/cpp2rust/converter/converter.h @@ -541,6 +541,8 @@ class Converter : public clang::RecursiveASTVisitor { virtual void AddByteReprTrait(const clang::RecordDecl *decl); + virtual void AddByteReprTrait(const clang::EnumDecl *decl); + virtual void ConvertUnsignedArithBinaryOperator(clang::BinaryOperator *binary_operator, clang::Expr *expr); diff --git a/cpp2rust/converter/converter_lib.cpp b/cpp2rust/converter/converter_lib.cpp index 415601c3..720b86be 100644 --- a/cpp2rust/converter/converter_lib.cpp +++ b/cpp2rust/converter/converter_lib.cpp @@ -200,9 +200,6 @@ bool IsMut(clang::QualType qual_type) { } bool TypeImplementsByteRepr(clang::QualType qt) { - if (qt->isEnumeralType()) { - return false; - } if (qt->isIntegerType() || qt->isFloatingType()) { return true; } diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index 4c606925..2f37d396 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -606,6 +606,19 @@ void ConverterRefCount::AddByteReprTrait(const clang::RecordDecl *decl) { } } +void ConverterRefCount::AddByteReprTrait(const clang::EnumDecl *decl) { + auto name = GetRecordName(decl); + StrCat(std::format("impl ByteRepr for {}", name)); + PushBrace impl_brace(*this); + StrCat(std::format("fn byte_size() -> usize {{ {} }}", + ctx_.getTypeSize(ctx_.getCanonicalTagType(decl)) / 8)); + StrCat( + "fn to_bytes(&self, buf: &mut [u8]) { (*self as i32).to_bytes(buf); }"); + StrCat(std::format("fn from_bytes(buf: &[u8]) -> Self {{ " + "<{}>::from(i32::from_bytes(buf)) }}", + name)); +} + std::string ConverterRefCount::GetSelfMaybeWithMut(const clang::CXXMethodDecl *decl) { return "&self"; diff --git a/cpp2rust/converter/models/converter_refcount.h b/cpp2rust/converter/models/converter_refcount.h index 600e6026..cf2a1bcb 100644 --- a/cpp2rust/converter/models/converter_refcount.h +++ b/cpp2rust/converter/models/converter_refcount.h @@ -41,6 +41,8 @@ class ConverterRefCount final : public Converter { void AddByteReprTrait(const clang::RecordDecl *decl) override; + void AddByteReprTrait(const clang::EnumDecl *decl) override; + bool VisitUnaryExprOrTypeTraitExpr(clang::UnaryExprOrTypeTraitExpr *expr) override; From abd39cd56be30ac1fb3a6e9c3a0413214f0d3146 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 24 Jun 2026 15:52:46 +0100 Subject: [PATCH 25/29] Update tests --- .../refcount/cross_tu_anon_enum_collision.rs | 22 ++++++ .../out/refcount/cross_tu_tag_collision.rs | 11 +++ .../ub/out/refcount/enum_out_of_range_cast.rs | 11 +++ .../refcount/enum_out_of_range_increment.rs | 11 +++ tests/unit/out/refcount/anonymous_enum.rs | 71 ++++++++++++++++++- tests/unit/out/refcount/anonymous_enum_c.rs | 71 ++++++++++++++++++- .../unit/out/refcount/bool_condition_enum.rs | 11 +++ .../out/refcount/bool_condition_enum_c.rs | 11 +++ .../out/refcount/bool_condition_logical.rs | 11 +++ .../out/refcount/bool_condition_logical_c.rs | 11 +++ tests/unit/out/refcount/c_struct.rs | 29 +++++++- .../out/refcount/enum_default_in_static.rs | 27 ++++++- tests/unit/out/refcount/enum_increment.rs | 11 +++ tests/unit/out/refcount/enum_int_interop.rs | 33 +++++++++ tests/unit/out/refcount/enum_int_interop_c.rs | 33 +++++++++ tests/unit/out/refcount/switch_char.rs | 11 +++ tests/unit/out/refcount/switch_enum.rs | 11 +++ .../refcount/tag_vs_identifier_collision.rs | 38 +++++++++- .../out/refcount/union_tagged_struct_arms.rs | 29 +++++++- .../out/refcount/va_arg_non_primitive_ptrs.rs | 11 +++ tests/unit/union_cross_arm_cast.c | 1 - tests/unit/union_nested.c | 1 - tests/unit/union_struct_dual_use.c | 1 - tests/unit/union_tagged_struct_arms.c | 1 - 24 files changed, 468 insertions(+), 10 deletions(-) diff --git a/tests/multi-file/cross_tu_anon_enum_collision/out/refcount/cross_tu_anon_enum_collision.rs b/tests/multi-file/cross_tu_anon_enum_collision/out/refcount/cross_tu_anon_enum_collision.rs index c7edae33..a7d41726 100644 --- a/tests/multi-file/cross_tu_anon_enum_collision/out/refcount/cross_tu_anon_enum_collision.rs +++ b/tests/multi-file/cross_tu_anon_enum_collision/out/refcount/cross_tu_anon_enum_collision.rs @@ -20,6 +20,17 @@ impl From for anon_0 { } } libcc2rs::impl_enum_inc_dec!(anon_0); +impl ByteRepr for anon_0 { + fn byte_size() -> usize { + 4 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self as i32).to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { + ::from(i32::from_bytes(buf)) + } +} pub fn a_value_1() -> i32 { let x: Value = Rc::new(RefCell::new(0)); (*x.borrow_mut()) |= (anon_0::ALPHA as i32); @@ -47,6 +58,17 @@ impl From for anon_3 { } } libcc2rs::impl_enum_inc_dec!(anon_3); +impl ByteRepr for anon_3 { + fn byte_size() -> usize { + 4 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self as i32).to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { + ::from(i32::from_bytes(buf)) + } +} pub fn b_value_2() -> i32 { let x: Value = Rc::new(RefCell::new(0)); (*x.borrow_mut()) |= (anon_3::BETA as i32); diff --git a/tests/multi-file/cross_tu_tag_collision/out/refcount/cross_tu_tag_collision.rs b/tests/multi-file/cross_tu_tag_collision/out/refcount/cross_tu_tag_collision.rs index 457ab0e5..f68bcfba 100644 --- a/tests/multi-file/cross_tu_tag_collision/out/refcount/cross_tu_tag_collision.rs +++ b/tests/multi-file/cross_tu_tag_collision/out/refcount/cross_tu_tag_collision.rs @@ -54,6 +54,17 @@ impl From for widget_enum { } } libcc2rs::impl_enum_inc_dec!(widget_enum); +impl ByteRepr for widget_enum { + fn byte_size() -> usize { + 4 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self as i32).to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { + ::from(i32::from_bytes(buf)) + } +} pub fn b_value_1() -> i32 { let w: Value = Rc::new(RefCell::new(widget_enum::WIDGET_C)); return ((*w.borrow()) as i32).clone(); diff --git a/tests/ub/out/refcount/enum_out_of_range_cast.rs b/tests/ub/out/refcount/enum_out_of_range_cast.rs index 60538ac8..463b825e 100644 --- a/tests/ub/out/refcount/enum_out_of_range_cast.rs +++ b/tests/ub/out/refcount/enum_out_of_range_cast.rs @@ -24,6 +24,17 @@ impl From for Color { } } libcc2rs::impl_enum_inc_dec!(Color); +impl ByteRepr for Color { + fn byte_size() -> usize { + 4 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self as i32).to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { + ::from(i32::from_bytes(buf)) + } +} pub fn main() { std::process::exit(main_0()); } diff --git a/tests/ub/out/refcount/enum_out_of_range_increment.rs b/tests/ub/out/refcount/enum_out_of_range_increment.rs index 4809fa73..7dffcf97 100644 --- a/tests/ub/out/refcount/enum_out_of_range_increment.rs +++ b/tests/ub/out/refcount/enum_out_of_range_increment.rs @@ -24,6 +24,17 @@ impl From for color { } } libcc2rs::impl_enum_inc_dec!(color); +impl ByteRepr for color { + fn byte_size() -> usize { + 4 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self as i32).to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { + ::from(i32::from_bytes(buf)) + } +} pub fn main() { std::process::exit(main_0()); } diff --git a/tests/unit/out/refcount/anonymous_enum.rs b/tests/unit/out/refcount/anonymous_enum.rs index f63deffd..f248358e 100644 --- a/tests/unit/out/refcount/anonymous_enum.rs +++ b/tests/unit/out/refcount/anonymous_enum.rs @@ -22,6 +22,17 @@ impl From for anon_0 { } } libcc2rs::impl_enum_inc_dec!(anon_0); +impl ByteRepr for anon_0 { + fn byte_size() -> usize { + 4 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self as i32).to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { + ::from(i32::from_bytes(buf)) + } +} #[derive(Clone, Copy, PartialEq, Debug, Default)] enum anon_1 { #[default] @@ -38,6 +49,17 @@ impl From for anon_1 { } } libcc2rs::impl_enum_inc_dec!(anon_1); +impl ByteRepr for anon_1 { + fn byte_size() -> usize { + 4 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self as i32).to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { + ::from(i32::from_bytes(buf)) + } +} #[derive(Default)] pub struct S { pub a: Value, @@ -79,6 +101,17 @@ impl From for TdEnum { } } libcc2rs::impl_enum_inc_dec!(TdEnum); +impl ByteRepr for TdEnum { + fn byte_size() -> usize { + 4 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self as i32).to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { + ::from(i32::from_bytes(buf)) + } +} #[derive(Clone, Copy, PartialEq, Debug, Default)] enum anon_2 { #[default] @@ -95,6 +128,17 @@ impl From for anon_2 { } } libcc2rs::impl_enum_inc_dec!(anon_2); +impl ByteRepr for anon_2 { + fn byte_size() -> usize { + 4 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self as i32).to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { + ::from(i32::from_bytes(buf)) + } +} #[derive(Default)] pub struct WithAnonField { pub a: Value, @@ -109,7 +153,21 @@ impl Clone for WithAnonField { this } } -impl ByteRepr for WithAnonField {} +impl ByteRepr for WithAnonField { + fn byte_size() -> usize { + 8 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.a.borrow()).to_bytes(&mut buf[0..4]); + (*self.field.borrow()).to_bytes(&mut buf[4..8]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + a: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), + field: Rc::new(RefCell::new(::from_bytes(&buf[4..8]))), + } + } +} pub fn main() { std::process::exit(main_0()); } @@ -130,6 +188,17 @@ fn main_0() -> i32 { } } libcc2rs::impl_enum_inc_dec!(anon_3); + impl ByteRepr for anon_3 { + fn byte_size() -> usize { + 4 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self as i32).to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { + ::from(i32::from_bytes(buf)) + } + }; assert!(((anon_0::FIRST_A as i32) != (anon_0::FIRST_B as i32))); assert!(((anon_1::SECOND_A as i32) != (anon_1::SECOND_B as i32))); assert!(((anon_3::THIRD_A as i32) != (anon_3::THIRD_B as i32))); diff --git a/tests/unit/out/refcount/anonymous_enum_c.rs b/tests/unit/out/refcount/anonymous_enum_c.rs index 43dc943b..55d55567 100644 --- a/tests/unit/out/refcount/anonymous_enum_c.rs +++ b/tests/unit/out/refcount/anonymous_enum_c.rs @@ -22,6 +22,17 @@ impl From for anon_0 { } } libcc2rs::impl_enum_inc_dec!(anon_0); +impl ByteRepr for anon_0 { + fn byte_size() -> usize { + 4 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self as i32).to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { + ::from(i32::from_bytes(buf)) + } +} #[derive(Clone, Copy, PartialEq, Debug, Default)] enum anon_1 { #[default] @@ -38,6 +49,17 @@ impl From for anon_1 { } } libcc2rs::impl_enum_inc_dec!(anon_1); +impl ByteRepr for anon_1 { + fn byte_size() -> usize { + 4 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self as i32).to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { + ::from(i32::from_bytes(buf)) + } +} #[derive(Default)] pub struct S { pub a: Value, @@ -71,6 +93,17 @@ impl From for TdEnum_enum { } } libcc2rs::impl_enum_inc_dec!(TdEnum_enum); +impl ByteRepr for TdEnum_enum { + fn byte_size() -> usize { + 4 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self as i32).to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { + ::from(i32::from_bytes(buf)) + } +} #[derive(Clone, Copy, PartialEq, Debug, Default)] enum anon_2 { #[default] @@ -87,12 +120,37 @@ impl From for anon_2 { } } libcc2rs::impl_enum_inc_dec!(anon_2); +impl ByteRepr for anon_2 { + fn byte_size() -> usize { + 4 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self as i32).to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { + ::from(i32::from_bytes(buf)) + } +} #[derive(Default)] pub struct WithAnonField { pub a: Value, pub field: Value, } -impl ByteRepr for WithAnonField {} +impl ByteRepr for WithAnonField { + fn byte_size() -> usize { + 8 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.a.borrow()).to_bytes(&mut buf[0..4]); + (*self.field.borrow()).to_bytes(&mut buf[4..8]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + a: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), + field: Rc::new(RefCell::new(::from_bytes(&buf[4..8]))), + } + } +} pub fn main() { std::process::exit(main_0()); } @@ -113,6 +171,17 @@ fn main_0() -> i32 { } } libcc2rs::impl_enum_inc_dec!(anon_3); + impl ByteRepr for anon_3 { + fn byte_size() -> usize { + 4 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self as i32).to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { + ::from(i32::from_bytes(buf)) + } + }; assert!(((((anon_0::FIRST_A as i32) != (anon_0::FIRST_B as i32)) as i32) != 0)); assert!(((((anon_1::SECOND_A as i32) != (anon_1::SECOND_B as i32)) as i32) != 0)); assert!(((((anon_3::THIRD_A as i32) != (anon_3::THIRD_B as i32)) as i32) != 0)); diff --git a/tests/unit/out/refcount/bool_condition_enum.rs b/tests/unit/out/refcount/bool_condition_enum.rs index 1d7dc853..ddc111e8 100644 --- a/tests/unit/out/refcount/bool_condition_enum.rs +++ b/tests/unit/out/refcount/bool_condition_enum.rs @@ -24,6 +24,17 @@ impl From for Code { } } libcc2rs::impl_enum_inc_dec!(Code); +impl ByteRepr for Code { + fn byte_size() -> usize { + 4 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self as i32).to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { + ::from(i32::from_bytes(buf)) + } +} pub fn main() { std::process::exit(main_0()); } diff --git a/tests/unit/out/refcount/bool_condition_enum_c.rs b/tests/unit/out/refcount/bool_condition_enum_c.rs index f84c1a88..4dc973eb 100644 --- a/tests/unit/out/refcount/bool_condition_enum_c.rs +++ b/tests/unit/out/refcount/bool_condition_enum_c.rs @@ -24,6 +24,17 @@ impl From for Code { } } libcc2rs::impl_enum_inc_dec!(Code); +impl ByteRepr for Code { + fn byte_size() -> usize { + 4 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self as i32).to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { + ::from(i32::from_bytes(buf)) + } +} pub fn main() { std::process::exit(main_0()); } diff --git a/tests/unit/out/refcount/bool_condition_logical.rs b/tests/unit/out/refcount/bool_condition_logical.rs index 9b340849..f54fa8d9 100644 --- a/tests/unit/out/refcount/bool_condition_logical.rs +++ b/tests/unit/out/refcount/bool_condition_logical.rs @@ -24,6 +24,17 @@ impl From for Code { } } libcc2rs::impl_enum_inc_dec!(Code); +impl ByteRepr for Code { + fn byte_size() -> usize { + 4 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self as i32).to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { + ::from(i32::from_bytes(buf)) + } +} thread_local!( pub static side_effect_0: Value = Rc::new(RefCell::new(0)); ); diff --git a/tests/unit/out/refcount/bool_condition_logical_c.rs b/tests/unit/out/refcount/bool_condition_logical_c.rs index a878ce93..c7e77840 100644 --- a/tests/unit/out/refcount/bool_condition_logical_c.rs +++ b/tests/unit/out/refcount/bool_condition_logical_c.rs @@ -24,6 +24,17 @@ impl From for Code { } } libcc2rs::impl_enum_inc_dec!(Code); +impl ByteRepr for Code { + fn byte_size() -> usize { + 4 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self as i32).to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { + ::from(i32::from_bytes(buf)) + } +} thread_local!( pub static side_effect_0: Value = Rc::new(RefCell::new(0)); ); diff --git a/tests/unit/out/refcount/c_struct.rs b/tests/unit/out/refcount/c_struct.rs index a0985ec8..c83ea71e 100644 --- a/tests/unit/out/refcount/c_struct.rs +++ b/tests/unit/out/refcount/c_struct.rs @@ -70,6 +70,17 @@ impl From for Color { } } libcc2rs::impl_enum_inc_dec!(Color); +impl ByteRepr for Color { + fn byte_size() -> usize { + 4 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self as i32).to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { + ::from(i32::from_bytes(buf)) + } +} #[derive(Default)] pub struct Inner { pub a: Value, @@ -96,7 +107,23 @@ pub struct Container { pub color: Value, pub count: Value, } -impl ByteRepr for Container {} +impl ByteRepr for Container { + fn byte_size() -> usize { + 16 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.inner.borrow()).to_bytes(&mut buf[0..8]); + (*self.color.borrow()).to_bytes(&mut buf[8..12]); + (*self.count.borrow()).to_bytes(&mut buf[12..16]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + inner: Rc::new(RefCell::new(::from_bytes(&buf[0..8]))), + color: Rc::new(RefCell::new(::from_bytes(&buf[8..12]))), + count: Rc::new(RefCell::new(::from_bytes(&buf[12..16]))), + } + } +} pub fn main() { std::process::exit(main_0()); } diff --git a/tests/unit/out/refcount/enum_default_in_static.rs b/tests/unit/out/refcount/enum_default_in_static.rs index 96f3bd8e..0c8b8760 100644 --- a/tests/unit/out/refcount/enum_default_in_static.rs +++ b/tests/unit/out/refcount/enum_default_in_static.rs @@ -24,12 +24,37 @@ impl From for Mode { } } libcc2rs::impl_enum_inc_dec!(Mode); +impl ByteRepr for Mode { + fn byte_size() -> usize { + 4 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self as i32).to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { + ::from(i32::from_bytes(buf)) + } +} #[derive(Default)] pub struct Config { pub count: Value, pub mode: Value, } -impl ByteRepr for Config {} +impl ByteRepr for Config { + fn byte_size() -> usize { + 8 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.count.borrow()).to_bytes(&mut buf[0..4]); + (*self.mode.borrow()).to_bytes(&mut buf[4..8]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + count: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), + mode: Rc::new(RefCell::new(::from_bytes(&buf[4..8]))), + } + } +} thread_local!( pub static config_0: Value = >::default(); ); diff --git a/tests/unit/out/refcount/enum_increment.rs b/tests/unit/out/refcount/enum_increment.rs index 25a24a2f..a6802f27 100644 --- a/tests/unit/out/refcount/enum_increment.rs +++ b/tests/unit/out/refcount/enum_increment.rs @@ -26,6 +26,17 @@ impl From for color { } } libcc2rs::impl_enum_inc_dec!(color); +impl ByteRepr for color { + fn byte_size() -> usize { + 4 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self as i32).to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { + ::from(i32::from_bytes(buf)) + } +} pub fn main() { std::process::exit(main_0()); } diff --git a/tests/unit/out/refcount/enum_int_interop.rs b/tests/unit/out/refcount/enum_int_interop.rs index 01a28cd8..776ad212 100644 --- a/tests/unit/out/refcount/enum_int_interop.rs +++ b/tests/unit/out/refcount/enum_int_interop.rs @@ -24,6 +24,17 @@ impl From for Color { } } libcc2rs::impl_enum_inc_dec!(Color); +impl ByteRepr for Color { + fn byte_size() -> usize { + 4 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self as i32).to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { + ::from(i32::from_bytes(buf)) + } +} #[derive(Clone, Copy, PartialEq, Debug, Default)] enum Option { #[default] @@ -44,6 +55,17 @@ impl From for Option { } } libcc2rs::impl_enum_inc_dec!(Option); +impl ByteRepr for Option { + fn byte_size() -> usize { + 4 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self as i32).to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { +