diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index fa484685..d096ff5c 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -503,10 +503,13 @@ 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.__bytes.as_pointer() " "as Ptr).reinterpret_cast() }}", - GetNamedDeclAsString(field), Mapper::Map(field->getType()))); + GetNamedDeclAsString(field), storage_ty)); } } @@ -1299,9 +1302,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); @@ -1488,6 +1499,7 @@ bool ConverterRefCount::VisitInitListExpr(clang::InitListExpr *expr) { } void ConverterRefCount::ConvertUnionMemberAccessor(clang::MemberExpr *expr) { + auto member = expr->getMemberDecl(); std::string str; { Buffer buf(*this); @@ -1498,15 +1510,24 @@ void ConverterRefCount::ConvertUnionMemberAccessor(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::Pointer; return; } + if (isLValue()) { pending_deref_.set(str); return; } - StrCat(DerefPtrExpr(str, expr->getMemberDecl()->getType())); + StrCat(DerefPtrExpr(str, member->getType())); } bool ConverterRefCount::VisitMemberExpr(clang::MemberExpr *expr) { 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 ac09c80c..ce8bf501 100644 --- a/libcc2rs/src/rc.rs +++ b/libcc2rs/src/rc.rs @@ -1042,49 +1042,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 { @@ -1118,66 +1102,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) } } diff --git a/tests/unit/memcpy_struct_bytes.c b/tests/unit/memcpy_struct_bytes.c new file mode 100644 index 00000000..ae767639 --- /dev/null +++ b/tests/unit/memcpy_struct_bytes.c @@ -0,0 +1,23 @@ +#include +#include +#include + +struct point { + int32_t x; + int32_t y; +}; + +int main(void) { + struct point src = {3, 7}; + + unsigned char buf[sizeof(struct point)]; + memcpy(buf, &src, sizeof(buf)); + + struct point dst; + memcpy(&dst, buf, sizeof(dst)); + + assert(dst.x == 3); + assert(dst.y == 7); + + return 0; +} diff --git a/tests/unit/out/refcount/memcpy_struct_bytes.rs b/tests/unit/out/refcount/memcpy_struct_bytes.rs new file mode 100644 index 00000000..d233b346 --- /dev/null +++ b/tests/unit/out/refcount/memcpy_struct_bytes.rs @@ -0,0 +1,58 @@ +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 point { + pub x: Value, + 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]); + } + 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]))), + } + } +} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let src: Value = Rc::new(RefCell::new(point { + x: Rc::new(RefCell::new(3)), + y: Rc::new(RefCell::new(7)), + })); + let buf: Value> = Rc::new(RefCell::new( + (0..8).map(|_| ::default()).collect::>(), + )); + { + ((buf.as_pointer() as Ptr) as Ptr).to_any().memcpy( + &((src.as_pointer()) as Ptr).to_any(), + ::std::mem::size_of::<[u8; 8]>() as usize, + ); + ((buf.as_pointer() as Ptr) as Ptr).to_any().clone() + }; + let dst: Value = >::default(); + { + ((dst.as_pointer()) as Ptr).to_any().memcpy( + &((buf.as_pointer() as Ptr) as Ptr).to_any(), + 8usize as usize, + ); + ((dst.as_pointer()) as Ptr).to_any().clone() + }; + assert!(((((*(*dst.borrow()).x.borrow()) == 3) as i32) != 0)); + assert!(((((*(*dst.borrow()).y.borrow()) == 7) as i32) != 0)); + return 0; +} diff --git a/tests/unit/out/refcount/union_addrof_external.rs b/tests/unit/out/refcount/union_addrof_external.rs index c8a203d3..f4e7e792 100644 --- a/tests/unit/out/refcount/union_addrof_external.rs +++ b/tests/unit/out/refcount/union_addrof_external.rs @@ -25,11 +25,49 @@ 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]))), + } + } +} +pub struct anon_0 { + __bytes: Value>, +} +impl anon_0 { + pub fn h(&self) -> Ptr { + (self.__bytes.as_pointer() as Ptr).reinterpret_cast() + } + pub fn raw_(&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; 128]))), + } + } } impl ByteRepr for anon_0 {} #[derive(Default)] @@ -67,11 +105,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 +127,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/out/unsafe/memcpy_struct_bytes.rs b/tests/unit/out/unsafe/memcpy_struct_bytes.rs new file mode 100644 index 00000000..110b0a87 --- /dev/null +++ b/tests/unit/out/unsafe/memcpy_struct_bytes.rs @@ -0,0 +1,47 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::{Read, Seek, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct point { + pub x: i32, + pub y: i32, +} +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut src: point = point { x: 3, y: 7 }; + let mut buf: [u8; 8] = [0_u8; 8]; + { + if ::std::mem::size_of::<[u8; 8]>() != 0 { + ::std::ptr::copy_nonoverlapping( + ((&mut src as *mut point) as *const point as *const ::libc::c_void), + (buf.as_mut_ptr() as *mut u8 as *mut ::libc::c_void), + ::std::mem::size_of::<[u8; 8]>() as usize, + ) + } + (buf.as_mut_ptr() as *mut u8 as *mut ::libc::c_void) + }; + let mut dst: point = ::default(); + { + if ::std::mem::size_of::() != 0 { + ::std::ptr::copy_nonoverlapping( + (buf.as_mut_ptr() as *const u8 as *const ::libc::c_void), + ((&mut dst as *mut point) as *mut point as *mut ::libc::c_void), + ::std::mem::size_of::() as usize, + ) + } + ((&mut dst as *mut point) as *mut point as *mut ::libc::c_void) + }; + assert!(((((dst.x) == (3)) as i32) != 0)); + assert!(((((dst.y) == (7)) 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_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_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 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