From 931d40da57c973736bc6a01b7f8bbf4117abe33f Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 1 Jul 2026 11:20:09 +0100 Subject: [PATCH 1/4] Fix translation of union array members --- cpp2rust/converter/converter_lib.cpp | 10 ++++++++++ cpp2rust/converter/converter_lib.h | 2 ++ cpp2rust/converter/models/converter_refcount.cpp | 3 ++- 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/cpp2rust/converter/converter_lib.cpp b/cpp2rust/converter/converter_lib.cpp index 702e57ef..6d335e29 100644 --- a/cpp2rust/converter/converter_lib.cpp +++ b/cpp2rust/converter/converter_lib.cpp @@ -130,6 +130,16 @@ bool IsInMainFile(const clang::Decl *decl) { return src_mgr.isInMainFile(src_mgr.getExpansionLoc(loc)); } +bool IsUnionArrayMember(const clang::Expr *base) { + if (auto *me = + clang::dyn_cast(base->IgnoreParenImpCasts())) { + if (auto *fd = clang::dyn_cast(me->getMemberDecl())) { + return fd->getParent()->isUnion() && fd->getType()->isArrayType(); + } + } + return false; +} + bool IsUserDefinedDecl(const clang::Decl *decl) { const auto &ctx = decl->getASTContext(); const auto &src_mgr = ctx.getSourceManager(); diff --git a/cpp2rust/converter/converter_lib.h b/cpp2rust/converter/converter_lib.h index 8c281261..110b501d 100644 --- a/cpp2rust/converter/converter_lib.h +++ b/cpp2rust/converter/converter_lib.h @@ -40,6 +40,8 @@ bool IsComparisonWithNullOp(const clang::BinaryOperator *expr); bool IsInMainFile(const clang::Decl *decl); +bool IsUnionArrayMember(const clang::Expr *base); + bool IsUserDefinedDecl(const clang::Decl *decl); bool RefersToUserDefinedDecl(const clang::Expr *expr); diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index 2af0f071..f822df9b 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -378,7 +378,8 @@ std::string ConverterRefCount::ConvertPtrType(clang::QualType type) { bool ConverterRefCount::VisitArraySubscriptExpr( clang::ArraySubscriptExpr *expr) { auto *base = expr->getBase(); - if (base->IgnoreCasts()->getType()->isPointerType()) { + if (base->IgnoreCasts()->getType()->isPointerType() || + (isLValue() && IsUnionArrayMember(base))) { ConvertPointerSubscript(expr); } else { if (!base->IgnoreCasts()->getType()->isArrayType()) { From aa251f6339af8869c0277b0e6d963686717d0750 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 1 Jul 2026 14:08:58 +0100 Subject: [PATCH 2/4] Update tests --- .../out/refcount/union_field_alignment.rs | 81 +++++++++++++++++++ tests/unit/union_field_alignment.c | 2 +- 2 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 tests/unit/out/refcount/union_field_alignment.rs diff --git a/tests/unit/out/refcount/union_field_alignment.rs b/tests/unit/out/refcount/union_field_alignment.rs new file mode 100644 index 00000000..72bc366f --- /dev/null +++ b/tests/unit/out/refcount/union_field_alignment.rs @@ -0,0 +1,81 @@ +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 struct anon_0 { + __bytes: Value>, +} +impl anon_0 { + pub fn bytes(&self) -> Ptr> { + (self.__bytes.as_pointer() as Ptr).reinterpret_cast() + } + pub fn aligner(&self) -> Ptr { + (self.__bytes.as_pointer() as Ptr).reinterpret_cast() + } +} +impl Clone for anon_0 { + fn clone(&self) -> Self { + anon_0 { + __bytes: Rc::new(RefCell::new(self.__bytes.borrow().clone())), + } + } +} +impl Default for anon_0 { + fn default() -> Self { + anon_0 { + __bytes: Rc::new(RefCell::new(Box::from([0u8; 8]))), + } + } +} +impl ByteRepr for anon_0 { + fn byte_size() -> usize { + 8 + } + fn to_bytes(&self, buf: &mut [u8]) { + buf.copy_from_slice(&self.__bytes.borrow()); + } + fn from_bytes(buf: &[u8]) -> Self { + anon_0 { + __bytes: Rc::new(RefCell::new(Box::from(buf))), + } + } +} +#[derive(Default)] +pub struct node { + pub next: Value>, + pub x: Value, +} +impl ByteRepr for node { + fn byte_size() -> usize { + 16 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.next.borrow()).to_bytes(&mut buf[0..8]); + (*self.x.borrow()).to_bytes(&mut buf[8..16]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + next: Rc::new(RefCell::new(>::from_bytes(&buf[0..8]))), + x: Rc::new(RefCell::new(::from_bytes(&buf[8..16]))), + } + } +} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let n: Value = >::default(); + (*(*n.borrow()).next.borrow_mut()) = Ptr::::null(); + ((*(*n.borrow()).x.borrow()).bytes().reinterpret_cast::() as Ptr) + .offset((0) as isize) + .write(171_u8); + assert!( + ((((((*(*n.borrow()).x.borrow()).bytes().read())[(0) as usize] as i32) == 171) as i32) + != 0) + ); + return 0; +} diff --git a/tests/unit/union_field_alignment.c b/tests/unit/union_field_alignment.c index 63c957d1..bc4013ff 100644 --- a/tests/unit/union_field_alignment.c +++ b/tests/unit/union_field_alignment.c @@ -1,4 +1,4 @@ -// no-compile: refcount +// panic: refcount #include #include #include From e6eea5469fa50d8332995fe4f6273b15e5c02357 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Thu, 2 Jul 2026 10:36:28 +0100 Subject: [PATCH 3/4] Translate accessor of array member as Ptr instead of Ptr> --- cpp2rust/converter/models/converter_refcount.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index f822df9b..de3463c5 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -379,7 +379,7 @@ bool ConverterRefCount::VisitArraySubscriptExpr( clang::ArraySubscriptExpr *expr) { auto *base = expr->getBase(); if (base->IgnoreCasts()->getType()->isPointerType() || - (isLValue() && IsUnionArrayMember(base))) { + IsUnionArrayMember(base)) { ConvertPointerSubscript(expr); } else { if (!base->IgnoreCasts()->getType()->isArrayType()) { @@ -505,13 +505,16 @@ 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<", ">"); + PushConversionKind push(*this, ConversionKind::Unboxed); + auto ty = + field->getType()->isArrayType() + ? ToString( + field->getType()->getAsArrayTypeUnsafe()->getElementType()) + : ToString(field->getType()); StrCat(std::format( "pub fn {}(&self) -> Ptr<{}> {{ (self.__bytes.as_pointer() " "as Ptr).reinterpret_cast() }}", - GetNamedDeclAsString(field), storage_ty)); + GetNamedDeclAsString(field), ty)); } } From 11dcbb209a7dae7409afb8e1e9a5fb682a723b9b Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Thu, 2 Jul 2026 10:51:19 +0100 Subject: [PATCH 4/4] Update tests --- .../unit/out/refcount/union_addrof_external.rs | 17 +++++++++++++---- .../unit/out/refcount/union_cross_arm_cast.rs | 2 +- .../unit/out/refcount/union_field_alignment.rs | 7 +++++-- tests/unit/out/refcount/union_memset_memcpy.rs | 16 +++++++++++++--- tests/unit/out/refcount/union_nested.rs | 2 +- .../unit/out/refcount/union_struct_dual_use.rs | 18 +++++++++++++----- tests/unit/union_field_alignment.c | 1 - 7 files changed, 46 insertions(+), 17 deletions(-) diff --git a/tests/unit/out/refcount/union_addrof_external.rs b/tests/unit/out/refcount/union_addrof_external.rs index a68fdf87..d5e5cf8c 100644 --- a/tests/unit/out/refcount/union_addrof_external.rs +++ b/tests/unit/out/refcount/union_addrof_external.rs @@ -51,7 +51,7 @@ impl anon_0 { pub fn h(&self) -> Ptr { (self.__bytes.as_pointer() as Ptr).reinterpret_cast() } - pub fn raw_(&self) -> Ptr> { + pub fn raw_(&self) -> Ptr { (self.__bytes.as_pointer() as Ptr).reinterpret_cast() } } @@ -187,12 +187,21 @@ fn main_0() -> i32 { != 0) ); assert!( - ((((((*(*c.borrow()).view.borrow()).raw_().read())[(0) as usize] as i32) == 2) as i32) + (((((((*(*c.borrow()).view.borrow()) + .raw_() + .reinterpret_cast::() as Ptr::) + .offset((0) as isize) + .read()) as i32) + == 2) as i32) != 0) ); assert!( - (((((((*(*c.borrow()).view.borrow()).raw_().read())[(3) as usize] as u8) as i32) == 80) - as i32) + ((((((((*(*c.borrow()).view.borrow()) + .raw_() + .reinterpret_cast::() as Ptr::) + .offset((3) as isize) + .read()) as u8) as i32) + == 80) as i32) != 0) ); return 0; diff --git a/tests/unit/out/refcount/union_cross_arm_cast.rs b/tests/unit/out/refcount/union_cross_arm_cast.rs index e14b8762..6a6139d8 100644 --- a/tests/unit/out/refcount/union_cross_arm_cast.rs +++ b/tests/unit/out/refcount/union_cross_arm_cast.rs @@ -88,7 +88,7 @@ impl anon_0 { pub fn b(&self) -> Ptr { (self.__bytes.as_pointer() as Ptr).reinterpret_cast() } - pub fn raw_(&self) -> Ptr> { + pub fn raw_(&self) -> Ptr { (self.__bytes.as_pointer() as Ptr).reinterpret_cast() } } diff --git a/tests/unit/out/refcount/union_field_alignment.rs b/tests/unit/out/refcount/union_field_alignment.rs index 72bc366f..1abb6a3d 100644 --- a/tests/unit/out/refcount/union_field_alignment.rs +++ b/tests/unit/out/refcount/union_field_alignment.rs @@ -10,7 +10,7 @@ pub struct anon_0 { __bytes: Value>, } impl anon_0 { - pub fn bytes(&self) -> Ptr> { + pub fn bytes(&self) -> Ptr { (self.__bytes.as_pointer() as Ptr).reinterpret_cast() } pub fn aligner(&self) -> Ptr { @@ -74,7 +74,10 @@ fn main_0() -> i32 { .offset((0) as isize) .write(171_u8); assert!( - ((((((*(*n.borrow()).x.borrow()).bytes().read())[(0) as usize] as i32) == 171) as i32) + (((((((*(*n.borrow()).x.borrow()).bytes().reinterpret_cast::() as Ptr::) + .offset((0) as isize) + .read()) as i32) + == 171) 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 index 95de7573..4466270c 100644 --- a/tests/unit/out/refcount/union_memset_memcpy.rs +++ b/tests/unit/out/refcount/union_memset_memcpy.rs @@ -84,7 +84,7 @@ impl anon_0 { pub fn b(&self) -> Ptr { (self.__bytes.as_pointer() as Ptr).reinterpret_cast() } - pub fn raw_(&self) -> Ptr> { + pub fn raw_(&self) -> Ptr { (self.__bytes.as_pointer() as Ptr).reinterpret_cast() } } @@ -158,11 +158,21 @@ fn main_0() -> i32 { != 0) ); assert!( - ((((((*(*c.borrow()).view.borrow()).raw_().read())[(0) as usize] as i32) == 0) as i32) + (((((((*(*c.borrow()).view.borrow()) + .raw_() + .reinterpret_cast::() as Ptr::) + .offset((0) as isize) + .read()) as i32) + == 0) as i32) != 0) ); assert!( - ((((((*(*c.borrow()).view.borrow()).raw_().read())[(255) as usize] as i32) == 0) as i32) + (((((((*(*c.borrow()).view.borrow()) + .raw_() + .reinterpret_cast::() as Ptr::) + .offset((255) as isize) + .read()) as i32) + == 0) as i32) != 0) ); let src: Value> = Rc::new(RefCell::new(Box::new([ diff --git a/tests/unit/out/refcount/union_nested.rs b/tests/unit/out/refcount/union_nested.rs index d1810f2a..dbf8aed8 100644 --- a/tests/unit/out/refcount/union_nested.rs +++ b/tests/unit/out/refcount/union_nested.rs @@ -43,7 +43,7 @@ impl anon_0 { pub fn h(&self) -> Ptr { (self.__bytes.as_pointer() as Ptr).reinterpret_cast() } - pub fn raw_(&self) -> Ptr> { + pub fn raw_(&self) -> Ptr { (self.__bytes.as_pointer() as Ptr).reinterpret_cast() } } diff --git a/tests/unit/out/refcount/union_struct_dual_use.rs b/tests/unit/out/refcount/union_struct_dual_use.rs index 98225b6d..d4a8bd78 100644 --- a/tests/unit/out/refcount/union_struct_dual_use.rs +++ b/tests/unit/out/refcount/union_struct_dual_use.rs @@ -40,7 +40,7 @@ impl anon_1 { pub fn inner(&self) -> Ptr { (self.__bytes.as_pointer() as Ptr).reinterpret_cast() } - pub fn raw_(&self) -> Ptr> { + pub fn raw_(&self) -> Ptr { (self.__bytes.as_pointer() as Ptr).reinterpret_cast() } } @@ -114,13 +114,21 @@ fn main_0() -> i32 { != 0) ); assert!( - (((((((*(*outer.borrow()).u.borrow()).raw_().read())[(0) as usize] as u8) as i32) == 3) - as i32) + ((((((((*(*outer.borrow()).u.borrow()) + .raw_() + .reinterpret_cast::() as Ptr::) + .offset((0) as isize) + .read()) 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) + ((((((((*(*outer.borrow()).u.borrow()) + .raw_() + .reinterpret_cast::() as Ptr::) + .offset((4) as isize) + .read()) as u8) as i32) + == 4) as i32) != 0) ); return 0; diff --git a/tests/unit/union_field_alignment.c b/tests/unit/union_field_alignment.c index bc4013ff..0205d532 100644 --- a/tests/unit/union_field_alignment.c +++ b/tests/unit/union_field_alignment.c @@ -1,4 +1,3 @@ -// panic: refcount #include #include #include