diff --git a/cpp2rust/converter/converter_lib.cpp b/cpp2rust/converter/converter_lib.cpp index 1b837cd7..cbc88b54 100644 --- a/cpp2rust/converter/converter_lib.cpp +++ b/cpp2rust/converter/converter_lib.cpp @@ -150,6 +150,16 @@ bool IsCharArrayFieldFromLibc(const clang::ValueDecl *decl) { field->getParent()->getLocation()); } +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 d652735e..ed812ca0 100644 --- a/cpp2rust/converter/converter_lib.h +++ b/cpp2rust/converter/converter_lib.h @@ -44,6 +44,8 @@ bool IsCharPointerFieldFromLibc(const clang::ValueDecl *decl); bool IsCharArrayFieldFromLibc(const clang::ValueDecl *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 044bd580..043dde29 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -377,7 +377,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() || + IsUnionArrayMember(base)) { ConvertPointerSubscript(expr); } else { if (!base->IgnoreCasts()->getType()->isArrayType()) { @@ -503,13 +504,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)); } } diff --git a/libcc2rs/src/rc.rs b/libcc2rs/src/rc.rs index f13be101..53396f4b 100644 --- a/libcc2rs/src/rc.rs +++ b/libcc2rs/src/rc.rs @@ -48,6 +48,7 @@ pub enum StrongPtr { Reinterpreted { alloc: Rc, byte_offset: usize, + elem_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, + elem_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; *elem_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()) @@ -353,6 +355,7 @@ impl Ptr { PtrKind::Reinterpreted(data) => StrongPtr::Reinterpreted { alloc: Rc::clone(&data.alloc), byte_offset: self.offset, + elem_byte_size: data.elem_byte_size, cell: RefCell::new(None), }, } @@ -377,7 +380,7 @@ impl Ptr { rc.borrow_mut()[self.offset] = value; } PtrKind::Reinterpreted(data) => { - let mut buf = vec![0u8; T::byte_size()]; + let mut buf = vec![0u8; data.elem_byte_size]; value.to_bytes(&mut buf); data.alloc.write_bytes(self.offset, &buf); } @@ -406,20 +409,26 @@ impl Ptr { panic!("cannot reinterpret_cast to zero-sized type"); } - let src_byte_off = self.offset.wrapping_mul(T::byte_size()); + self.reinterpret_sized::(U::byte_size()) + } + + pub fn reinterpret_sized(&self, elem_byte_size: usize) -> Ptr + where + T: ByteRepr, + { 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(data) => (Rc::clone(&data.alloc), self.offset), }; @@ -428,7 +437,7 @@ impl Ptr { offset: abs_byte_off, kind: PtrKind::Reinterpreted(Rc::new(ReinterpretedView { alloc, - elem_byte_size: U::byte_size(), + elem_byte_size, })), } } @@ -457,7 +466,7 @@ impl Ptr { f(&mut borrow[self.offset]) } PtrKind::Reinterpreted(data) => { - let mut buf = vec![0u8; T::byte_size()]; + let mut buf = vec![0u8; data.elem_byte_size]; data.alloc.read_bytes(self.offset, &mut buf); let mut val = T::from_bytes(&buf); let ret = f(&mut val); @@ -490,7 +499,7 @@ impl Ptr { f(&borrow[self.offset]) } PtrKind::Reinterpreted(data) => { - let mut buf = vec![0u8; T::byte_size()]; + let mut buf = vec![0u8; data.elem_byte_size]; data.alloc.read_bytes(self.offset, &mut buf); let val = T::from_bytes(&buf); f(&val) @@ -517,7 +526,7 @@ impl Ptr { weak.upgrade().expect("ub: dangling pointer").borrow()[self.offset].clone() } PtrKind::Reinterpreted(ref data) => { - let mut buf = vec![0u8; T::byte_size()]; + let mut buf = vec![0u8; data.elem_byte_size]; data.alloc.read_bytes(self.offset, &mut buf); T::from_bytes(&buf) } diff --git a/libcc2rs/src/reinterpret.rs b/libcc2rs/src/reinterpret.rs index b496f8b2..04f05016 100644 --- a/libcc2rs/src/reinterpret.rs +++ b/libcc2rs/src/reinterpret.rs @@ -85,7 +85,18 @@ 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 = T::byte_size(); + 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 = T::byte_size(); + buf.chunks(size).map(|c| T::from_bytes(c)).collect() + } +} impl ByteRepr for Box {} impl ByteRepr for *const T {} impl ByteRepr for *mut T {} 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 new file mode 100644 index 00000000..1abb6a3d --- /dev/null +++ b/tests/unit/out/refcount/union_field_alignment.rs @@ -0,0 +1,84 @@ +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().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_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 diff --git a/tests/unit/union_field_alignment.c b/tests/unit/union_field_alignment.c index 63c957d1..0205d532 100644 --- a/tests/unit/union_field_alignment.c +++ b/tests/unit/union_field_alignment.c @@ -1,4 +1,3 @@ -// no-compile: refcount #include #include #include 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