Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
0dca34e
Use C size when size_of diverges between C and Rust
lucic71 Jun 24, 2026
8fa8bec
Add byte_size in ByteRepr to capture C size
lucic71 Jun 24, 2026
a07a40f
Delete unused function
lucic71 Jun 25, 2026
7db5002
Add correct from_bytes type
lucic71 Jun 25, 2026
c66a712
Update tests
lucic71 Jun 25, 2026
5af65da
Add panic default implementations
lucic71 Jun 25, 2026
8084fc9
Implement byte_size for primitives
lucic71 Jun 25, 2026
532c0b5
Allow enums to have byterepr
lucic71 Jun 25, 2026
0573f9c
Don't add ByteRepr for system header types
lucic71 Jun 25, 2026
32d916a
Ignore unions in ByteRepr for now
lucic71 Jun 25, 2026
96cd270
Update tests
lucic71 Jun 25, 2026
3402042
Memcpy a poitner to a struct through ErasedPtr
lucic71 Jun 23, 2026
fb7f030
Add memcpy_struct_bytes test
lucic71 Jun 25, 2026
e4bb83e
Update tests
lucic71 Jun 25, 2026
d979745
Merge branch 'master' into anyptr-reinterpreted
lucic71 Jun 29, 2026
48d6908
Trigger CI
lucic71 Jun 29, 2026
3436b46
Merge branch 'master' into anyptr-reinterpreted
lucic71 Jun 29, 2026
658b9ed
Use reinterpret_cast to round-trip through void
lucic71 Jul 1, 2026
ba3fd40
Update tests
lucic71 Jul 1, 2026
93681bd
clang-format
lucic71 Jul 1, 2026
70bf770
Fix expected output
lucic71 Jul 1, 2026
b1705c3
Merge branch 'master' into void-round-trip
lucic71 Jul 1, 2026
dd22145
Merge branch 'fix-union' into void-round-trip
lucic71 Jul 1, 2026
cde0270
Update tests
lucic71 Jul 1, 2026
2b7953e
Merge branch 'master' into void-round-trip
lucic71 Jul 1, 2026
fb91acc
Update tests
lucic71 Jul 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions cpp2rust/converter/models/converter_refcount.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ std::string ConverterRefCount::BuildFnAdapter(
closure += std::format("a{}", i);
} else if (src_pty->isPointerType() && tgt_pty->isPointerType()) {
if (tgt_pty->isVoidPointerType()) {
closure += std::format("a{}.cast::<{}>().unwrap()", i,
closure += std::format("a{}.reinterpret_cast::<{}>()", i,
ConvertPointeeType(src_pty));
} else if (src_pty->isVoidPointerType()) {
closure += std::format("a{}.to_any()", i);
Expand Down Expand Up @@ -1301,7 +1301,7 @@ bool ConverterRefCount::VisitExplicitCastExpr(clang::ExplicitCastExpr *expr) {
expr->getType()->isPointerType()) {
Convert(expr->getSubExpr());
PushConversionKind push(*this, ConversionKind::Unboxed);
StrCat(std::format(".cast::<{}>().expect(\"ub:wrong type\")",
StrCat(std::format(".reinterpret_cast::<{}>()",
ConvertPointeeType(expr->getType())));
return false;
} else if (expr->getType()->isVoidPointerType() &&
Expand Down
10 changes: 2 additions & 8 deletions libcc2rs/src/io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,7 @@ pub unsafe fn cerr_unsafe() -> *mut std::fs::File {

pub fn fread_refcount(a0: AnyPtr, a1: usize, a2: usize, a3: Ptr<::std::fs::File>) -> usize {
let total = a1.saturating_mul(a2);
let mut dst = a0
.cast::<u8>()
.expect("fread: only supporting u8 pointers")
.clone();
let mut dst = a0.reinterpret_cast::<u8>();

let f = (*a3.upgrade().deref())
.try_clone()
Expand Down Expand Up @@ -123,10 +120,7 @@ pub fn fread_refcount(a0: AnyPtr, a1: usize, a2: usize, a3: Ptr<::std::fs::File>

pub fn fwrite_refcount(a0: AnyPtr, a1: usize, a2: usize, a3: Ptr<::std::fs::File>) -> usize {
let total = a1.saturating_mul(a2);
let mut src = a0
.cast::<u8>()
.expect("fwrite: only supporting u8 pointers")
.clone();
let mut src = a0.reinterpret_cast::<u8>();

let f = (*a3.upgrade().deref())
.try_clone()
Expand Down
29 changes: 14 additions & 15 deletions libcc2rs/src/rc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1100,11 +1100,14 @@ impl Default for AnyPtr {
}

impl AnyPtr {
pub fn cast<T: 'static>(&self) -> Option<Ptr<T>> {
pub fn reinterpret_cast<T: ByteRepr>(&self) -> Ptr<T> {
if self.ptr.is_null() {
return Some(Ptr::<T>::null());
return Ptr::<T>::null();
}
self.ptr.as_any().downcast_ref::<Ptr<T>>().cloned()
if let Some(p) = self.ptr.as_any().downcast_ref::<Ptr<T>>() {
return p.clone();
}
self.ptr.as_bytes().reinterpret_cast::<T>()
}
}

Expand Down Expand Up @@ -1265,27 +1268,23 @@ mod tests {
fn anyptr_null_cast() {
// void* nullptr
let any = Ptr::<()>::null().to_any();
let p: Option<Ptr<u32>> = any.cast::<u32>();
assert!(p.is_some());
assert!(p.unwrap().is_null());
let p = any.reinterpret_cast::<u32>();
assert!(p.is_null());

let p2: Option<Ptr<u8>> = any.cast::<u8>();
assert!(p2.is_some());
assert!(p2.unwrap().is_null());
let p2 = any.reinterpret_cast::<u8>();
assert!(p2.is_null());

// int* nullptr
let any2 = Ptr::<i32>::null().to_any();
let p3: Option<Ptr<f32>> = any2.cast::<f32>();
assert!(p3.is_some());
assert!(p3.unwrap().is_null());
let p3 = any2.reinterpret_cast::<f32>();
assert!(p3.is_null());
}

#[test]
fn to_any_without_clone() {
let p: Ptr<std::fs::File> = Ptr::null(); // std::fs::File is not Clone
let any = p.to_any();
let recovered = any.cast::<std::fs::File>();
assert!(recovered.is_some());
assert!(recovered.unwrap().is_null());
let recovered = any.reinterpret_cast::<std::fs::File>();
assert!(recovered.is_null());
}
}
4 changes: 2 additions & 2 deletions libcc2rs/src/va_args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,10 +119,10 @@ impl<T> VaArgGet for *const T {
}
}

impl<T: 'static> VaArgGet for crate::rc::Ptr<T> {
impl<T: 'static + crate::ByteRepr> VaArgGet for crate::rc::Ptr<T> {
fn get(v: &VaArg) -> Self {
match v {
VaArg::Ptr(any) => any.cast::<T>().expect("VaArgGet: Ptr type mismatch"),
VaArg::Ptr(any) => any.reinterpret_cast::<T>(),
_ => panic!("VaArgGet: expected Ptr"),
}
}
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/out/refcount/fn_ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use std::os::fd::AsFd;
use std::rc::{Rc, Weak};
pub fn my_foo_0(p: AnyPtr) -> i32 {
let p: Value<AnyPtr> = Rc::new(RefCell::new(p));
return ((*p.borrow()).cast::<i32>().expect("ub:wrong type").read());
return ((*p.borrow()).reinterpret_cast::<i32>().read());
}
pub fn foo_1(fn_: FnPtr<fn(AnyPtr) -> i32>, pi: Ptr<i32>) -> i32 {
let fn_: Value<FnPtr<fn(AnyPtr) -> i32>> = Rc::new(RefCell::new(fn_));
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/out/refcount/fn_ptr_cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ pub fn add_offset_4(base: Ptr<i32>, offset: i32) -> i32 {
pub fn test_call_through_cast_5() {
let gfn: Value<FnPtr<fn(AnyPtr, i32) -> i32>> = Rc::new(RefCell::new(
FnPtr::<fn(Ptr<i32>, i32) -> i32>::new(add_offset_4).cast::<fn(AnyPtr, i32) -> i32>(Some(
(|a0: AnyPtr, a1: i32| -> i32 { add_offset_4(a0.cast::<i32>().unwrap(), a1) })
(|a0: AnyPtr, a1: i32| -> i32 { add_offset_4(a0.reinterpret_cast::<i32>(), a1) })
as fn(AnyPtr, i32) -> i32,
)),
));
Expand Down
13 changes: 9 additions & 4 deletions tests/unit/out/refcount/fn_ptr_stdlib_compare.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,12 @@ fn main_0() -> i32 {
)
.cast::<fn(Ptr<u8>, usize, usize, AnyPtr) -> usize>(Some(
(|a0: Ptr<u8>, a1: usize, a2: usize, a3: AnyPtr| -> usize {
libcc2rs::fread_refcount(a0.to_any(), a1, a2, a3.cast::<::std::fs::File>().unwrap())
libcc2rs::fread_refcount(
a0.to_any(),
a1,
a2,
a3.reinterpret_cast::<::std::fs::File>(),
)
}) as fn(Ptr<u8>, usize, usize, AnyPtr) -> usize,
)),
));
Expand All @@ -56,7 +61,7 @@ fn main_0() -> i32 {
FnPtr::<fn(Ptr<u8>, usize, usize, AnyPtr) -> usize>::new(my_alternative_fread_0)
.cast::<fn(AnyPtr, usize, usize, Ptr<::std::fs::File>) -> usize>(Some(
(|a0: AnyPtr, a1: usize, a2: usize, a3: Ptr<::std::fs::File>| -> usize {
my_alternative_fread_0(a0.cast::<u8>().unwrap(), a1, a2, a3.to_any())
my_alternative_fread_0(a0.reinterpret_cast::<u8>(), a1, a2, a3.to_any())
}) as fn(AnyPtr, usize, usize, Ptr<::std::fs::File>) -> usize,
)),
));
Expand Down Expand Up @@ -195,7 +200,7 @@ fn main_0() -> i32 {
a0.to_any(),
a1,
a2,
a3.cast::<::std::fs::File>().unwrap(),
a3.reinterpret_cast::<::std::fs::File>(),
)
}) as fn(Ptr<u8>, usize, usize, AnyPtr) -> usize,
)),
Expand All @@ -211,7 +216,7 @@ fn main_0() -> i32 {
FnPtr::<fn(Ptr<u8>, usize, usize, AnyPtr) -> usize>::new(my_alternative_fwrite_1)
.cast::<fn(AnyPtr, usize, usize, Ptr<::std::fs::File>) -> usize>(Some(
(|a0: AnyPtr, a1: usize, a2: usize, a3: Ptr<::std::fs::File>| -> usize {
my_alternative_fwrite_1(a0.cast::<u8>().unwrap(), a1, a2, a3.to_any())
my_alternative_fwrite_1(a0.reinterpret_cast::<u8>(), a1, a2, a3.to_any())
}) as fn(AnyPtr, usize, usize, Ptr<::std::fs::File>) -> usize,
)),
));
Expand Down
4 changes: 2 additions & 2 deletions tests/unit/out/refcount/fn_ptr_vtable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,11 @@ pub fn int_create_1(val: i32) -> AnyPtr {
}
pub fn int_get_2(p: AnyPtr) -> i32 {
let p: Value<AnyPtr> = Rc::new(RefCell::new(p));
return ((*p.borrow()).cast::<i32>().expect("ub:wrong type").read());
return ((*p.borrow()).reinterpret_cast::<i32>().read());
}
pub fn int_destroy_3(p: AnyPtr) {
let p: Value<AnyPtr> = Rc::new(RefCell::new(p));
(*p.borrow()).cast::<i32>().expect("ub:wrong type").write(0);
(*p.borrow()).reinterpret_cast::<i32>().write(0);
}
pub fn main() {
std::process::exit(main_0());
Expand Down
5 changes: 1 addition & 4 deletions tests/unit/out/refcount/ptr_to_incomplete_struct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,7 @@ fn main_0() -> i32 {
let fp: Value<Ptr<::std::fs::File>> = Rc::new(RefCell::new((libcc2rs::cout()).clone()));
let p: Value<AnyPtr> = Rc::new(RefCell::new((*fp.borrow()).clone().to_any()));
let fp2: Value<Ptr<::std::fs::File>> = Rc::new(RefCell::new(
((*p.borrow())
.cast::<::std::fs::File>()
.expect("ub:wrong type"))
.clone(),
((*p.borrow()).reinterpret_cast::<::std::fs::File>()).clone(),
));
assert!(
((({
Expand Down
3 changes: 1 addition & 2 deletions tests/unit/out/refcount/union_cross_arm_cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,8 +157,7 @@ fn main_0() -> i32 {
(*(*(((*(*c.borrow()).u.borrow()).a())
.clone()
.to_any()
.cast::<shape_b>()
.expect("ub:wrong type"))
.reinterpret_cast::<shape_b>())
.upgrade()
.deref())
.tail
Expand Down
9 changes: 3 additions & 6 deletions tests/unit/out/refcount/union_void_ptr_sized_deref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,26 +106,23 @@ pub fn write_count_1(s: Ptr<Sink>, count: i64) {
((*(*(*s.borrow()).upgrade().deref()).out.borrow())
.handle()
.read())
.cast::<i64>()
.expect("ub:wrong type")
.reinterpret_cast::<i64>()
.write((*count.borrow()));
break 'switch;
}
__v if __v == ((Width_enum::W_32 as i32) as u32) => {
((*(*(*s.borrow()).upgrade().deref()).out.borrow())
.handle()
.read())
.cast::<i32>()
.expect("ub:wrong type")
.reinterpret_cast::<i32>()
.write(((*count.borrow()) as i32));
break 'switch;
}
__v if __v == ((Width_enum::W_16 as i32) as u32) => {
((*(*(*s.borrow()).upgrade().deref()).out.borrow())
.handle()
.read())
.cast::<i16>()
.expect("ub:wrong type")
.reinterpret_cast::<i16>()
.write(((*count.borrow()) as i16));
break 'switch;
}
Expand Down
5 changes: 1 addition & 4 deletions tests/unit/out/refcount/va_arg_non_primitive_ptrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,10 +116,7 @@ fn main_0() -> i32 {
(((({
dispatch_0(
(opt::OPT_FILE as i32),
&[((AnyPtr::default())
.cast::<::std::fs::File>()
.expect("ub:wrong type"))
.into()],
&[((AnyPtr::default()).reinterpret_cast::<::std::fs::File>()).into()],
)
}) == 0) as i32)
!= 0)
Expand Down
16 changes: 16 additions & 0 deletions tests/unit/out/refcount/void_round_trip.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
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 a: Value<u32> = Rc::new(RefCell::new(42_u32));
assert!((((((a.as_pointer()).to_any().reinterpret_cast::<i32>().read()) == 42) as i32) != 0));
return 0;
}
2 changes: 1 addition & 1 deletion tests/unit/out/refcount/z_bit_cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ fn main_0() -> i32 {
_lhs == ((a1.as_pointer() as Ptr<u32>) as Ptr<u32>).to_any()
});
assert!({
let _lhs = (((*ptr.borrow()).cast::<u32>().expect("ub:wrong type"))
let _lhs = (((*ptr.borrow()).reinterpret_cast::<u32>())
.offset((0) as isize)
.read());
_lhs == (*a1.borrow())[(0) as usize]
Expand Down
20 changes: 20 additions & 0 deletions tests/unit/out/unsafe/void_round_trip.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
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;
pub fn main() {
unsafe {
std::process::exit(main_0() as i32);
}
}
unsafe fn main_0() -> i32 {
let mut a: u32 = 42_u32;
assert!(
((((*(((&mut a as *mut u32) as *mut ::libc::c_void) as *mut i32)) == (42)) as i32) != 0)
);
return 0;
}
8 changes: 8 additions & 0 deletions tests/unit/void_round_trip.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#include <assert.h>
#include <stdint.h>

int main() {
uint32_t a = 42;
assert(*(int32_t *)(void *)&a == 42);
return 0;
}
Loading