From 9e2e0ad8e4540e79d5ab9467d56f4396250dda3c Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Fri, 10 Jul 2026 12:53:44 +0100 Subject: [PATCH 1/2] Translate offsetof in refcount --- .../converter/models/converter_refcount.cpp | 8 ++ .../converter/models/converter_refcount.h | 2 + tests/unit/offsetof.cpp | 23 ++-- tests/unit/out/refcount/offsetof.rs | 119 ++++++++++++++++++ tests/unit/out/unsafe/offsetof.rs | 28 +++-- 5 files changed, 159 insertions(+), 21 deletions(-) create mode 100644 tests/unit/out/refcount/offsetof.rs diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index 483c7fdb..a346cb0d 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -417,6 +417,14 @@ bool ConverterRefCount::VisitCXXRecordDecl(clang::CXXRecordDecl *decl) { return false; } +bool ConverterRefCount::VisitOffsetOfExpr(clang::OffsetOfExpr *expr) { + clang::Expr::EvalResult result; + ENSURE(expr->EvaluateAsInt(result, ctx_)); + StrCat(std::format("{}_usize", result.Val.getInt().getZExtValue())); + computed_expr_type_ = ComputedExprType::FreshValue; + return false; +} + void ConverterRefCount::ConvertOrdAndPartialOrdTraits( const clang::CXXRecordDecl *decl, const clang::FunctionDecl *op) { std::string first_branch, second_branch, first_return, second_return; diff --git a/cpp2rust/converter/models/converter_refcount.h b/cpp2rust/converter/models/converter_refcount.h index e58853e1..4b29299b 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; + bool VisitOffsetOfExpr(clang::OffsetOfExpr *expr) override; + void EmitRustUnion(clang::RecordDecl *decl) override; bool EmitsReprCForRecords() const override { return false; } diff --git a/tests/unit/offsetof.cpp b/tests/unit/offsetof.cpp index 16b99134..f4e9309b 100644 --- a/tests/unit/offsetof.cpp +++ b/tests/unit/offsetof.cpp @@ -1,7 +1,7 @@ -// no-compile: refcount #include #include #include +#include struct Layout { uint8_t a; @@ -9,14 +9,9 @@ struct Layout { uint16_t c; }; -struct Inner { - uint16_t x; - uint32_t y; -}; - -struct Outer { - uint8_t pad; - struct Inner inner; +struct Frame { + uint16_t tag; + char body[64]; }; int main(void) { @@ -24,13 +19,19 @@ int main(void) { assert(offsetof(struct Layout, b) == 4); assert(offsetof(struct Layout, c) == 8); - assert(offsetof(struct Outer, inner.y) == 8); - struct Layout v = {0}; v.b = 0xDEADBEEF; unsigned char *base = (unsigned char *)&v; uint32_t *bp = (uint32_t *)(base + offsetof(struct Layout, b)); assert(*bp == 0xDEADBEEF); + *(uint32_t *)(base + offsetof(struct Layout, b)) = 0x12345678; + assert(v.b == 0x12345678); + + const char *text = "example-body"; + size_t len = strlen(text) + 1; + size_t total = offsetof(struct Frame, body) + len; + assert(total == 2 + len); + return 0; } diff --git a/tests/unit/out/refcount/offsetof.rs b/tests/unit/out/refcount/offsetof.rs new file mode 100644 index 00000000..d0c2cf5a --- /dev/null +++ b/tests/unit/out/refcount/offsetof.rs @@ -0,0 +1,119 @@ +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 Layout { + pub a: Value, + pub b: Value, + pub c: Value, +} +impl Clone for Layout { + fn clone(&self) -> Self { + let mut this = Self { + a: Rc::new(RefCell::new((*self.a.borrow()))), + b: Rc::new(RefCell::new((*self.b.borrow()))), + c: Rc::new(RefCell::new((*self.c.borrow()))), + }; + this + } +} +impl ByteRepr for Layout { + fn byte_size() -> usize { + 12 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.a.borrow()).to_bytes(&mut buf[0..1]); + (*self.b.borrow()).to_bytes(&mut buf[4..8]); + (*self.c.borrow()).to_bytes(&mut buf[8..10]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + a: Rc::new(RefCell::new(::from_bytes(&buf[0..1]))), + b: Rc::new(RefCell::new(::from_bytes(&buf[4..8]))), + c: Rc::new(RefCell::new(::from_bytes(&buf[8..10]))), + } + } +} +#[derive()] +pub struct Frame { + pub tag: Value, + pub body: Value>, +} +impl Clone for Frame { + fn clone(&self) -> Self { + let mut this = Self { + tag: Rc::new(RefCell::new((*self.tag.borrow()))), + body: Rc::new(RefCell::new((*self.body.borrow()).clone())), + }; + this + } +} +impl Default for Frame { + fn default() -> Self { + Frame { + tag: >::default(), + body: Rc::new(RefCell::new( + (0..64).map(|_| ::default()).collect::>(), + )), + } + } +} +impl ByteRepr for Frame { + fn byte_size() -> usize { + 66 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.tag.borrow()).to_bytes(&mut buf[0..2]); + (*self.body.borrow()).to_bytes(&mut buf[2..66]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + tag: Rc::new(RefCell::new(::from_bytes(&buf[0..2]))), + body: Rc::new(RefCell::new(>::from_bytes(&buf[2..66]))), + } + } +} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + assert!((0_usize == 0_usize)); + assert!((4_usize == 4_usize)); + assert!((8_usize == 8_usize)); + let v: Value = Rc::new(RefCell::new(Layout { + a: Rc::new(RefCell::new(0_u8)), + b: Rc::new(RefCell::new(::default())), + c: Rc::new(RefCell::new(::default())), + })); + (*(*v.borrow()).b.borrow_mut()) = 3735928559_u32; + let base: Value> = Rc::new(RefCell::new((v.as_pointer()).reinterpret_cast::())); + let bp: Value> = Rc::new(RefCell::new( + ((*base.borrow()).offset((4_usize) as isize)).reinterpret_cast::(), + )); + assert!((((*bp.borrow()).read()) == 3735928559_u32)); + ((*base.borrow()).offset((4_usize) as isize)) + .reinterpret_cast::() + .write(305419896_u32); + assert!(((*(*v.borrow()).b.borrow()) == 305419896_u32)); + let text: Value> = Rc::new(RefCell::new(Ptr::from_string_literal(b"example-body"))); + let len: Value = Rc::new(RefCell::new( + ({ + let mut __i: usize = 0; + while (*text.borrow()).offset(__i).read() != 0 { + __i += 1; + } + __i + }) + .wrapping_add(1_usize), + )); + let total: Value = Rc::new(RefCell::new( + ((2_usize as u64).wrapping_add(((*len.borrow()) as u64)) as usize), + )); + assert!(((*total.borrow()) == (2_usize).wrapping_add((*len.borrow())))); + return 0; +} diff --git a/tests/unit/out/unsafe/offsetof.rs b/tests/unit/out/unsafe/offsetof.rs index 1562f269..560e0415 100644 --- a/tests/unit/out/unsafe/offsetof.rs +++ b/tests/unit/out/unsafe/offsetof.rs @@ -14,16 +14,18 @@ pub struct Layout { pub c: u16, } #[repr(C)] -#[derive(Copy, Clone, Default)] -pub struct Inner { - pub x: u16, - pub y: u32, +#[derive(Copy, Clone)] +pub struct Frame { + pub tag: u16, + pub body: [libc::c_char; 64], } -#[repr(C)] -#[derive(Copy, Clone, Default)] -pub struct Outer { - pub pad: u8, - pub inner: Inner, +impl Default for Frame { + fn default() -> Self { + Frame { + tag: 0_u16, + body: [(0 as libc::c_char); 64], + } + } } pub fn main() { unsafe { @@ -34,7 +36,6 @@ unsafe fn main_0() -> i32 { assert!(((::std::mem::offset_of!(Layout, a)) == (0_usize))); assert!(((::std::mem::offset_of!(Layout, b)) == (4_usize))); assert!(((::std::mem::offset_of!(Layout, c)) == (8_usize))); - assert!(((::std::mem::offset_of!(Outer, inner.y)) == (8_usize))); let mut v: Layout = Layout { a: 0_u8, b: 0_u32, @@ -45,5 +46,12 @@ unsafe fn main_0() -> i32 { let mut bp: *mut u32 = ((base.offset((::std::mem::offset_of!(Layout, b)) as isize)) as *mut u32); assert!(((*bp) == (3735928559_u32))); + (*((base.offset((::std::mem::offset_of!(Layout, b)) as isize)) as *mut u32)) = 305419896_u32; + assert!(((v.b) == (305419896_u32))); + let mut text: *const libc::c_char = c"example-body".as_ptr(); + let mut len: usize = (libc::strlen(text)).wrapping_add(1_usize); + let mut total: usize = + ((::std::mem::offset_of!(Frame, body) as u64).wrapping_add((len as u64)) as usize); + assert!(((total) == ((2_usize).wrapping_add(len)))); return 0; } From ecd69437c7f715dc923061c4e7f97fdacd1f5157 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Mon, 13 Jul 2026 22:54:19 +0100 Subject: [PATCH 2/2] Update tests --- tests/unit/out/refcount/offsetof.rs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/tests/unit/out/refcount/offsetof.rs b/tests/unit/out/refcount/offsetof.rs index d0c2cf5a..ffb50b8b 100644 --- a/tests/unit/out/refcount/offsetof.rs +++ b/tests/unit/out/refcount/offsetof.rs @@ -102,14 +102,7 @@ fn main_0() -> i32 { assert!(((*(*v.borrow()).b.borrow()) == 305419896_u32)); let text: Value> = Rc::new(RefCell::new(Ptr::from_string_literal(b"example-body"))); let len: Value = Rc::new(RefCell::new( - ({ - let mut __i: usize = 0; - while (*text.borrow()).offset(__i).read() != 0 { - __i += 1; - } - __i - }) - .wrapping_add(1_usize), + ((*text.borrow()).to_string_iterator().count()).wrapping_add(1_usize), )); let total: Value = Rc::new(RefCell::new( ((2_usize as u64).wrapping_add(((*len.borrow()) as u64)) as usize),