diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index f1c291e0..9de781d7 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -3052,6 +3052,24 @@ bool Converter::VisitTypeTraitExpr(clang::TypeTraitExpr *expr) { return false; } +bool Converter::VisitOffsetOfExpr(clang::OffsetOfExpr *expr) { + std::string member_path; + for (unsigned i = 0; i < expr->getNumComponents(); ++i) { + const clang::OffsetOfNode &node = expr->getComponent(i); + ENSURE(node.getKind() == clang::OffsetOfNode::Field); + if (!member_path.empty()) { + member_path += '.'; + } + member_path += GetNamedDeclAsString(node.getField()); + } + StrCat( + std::format("::std::mem::offset_of!({}, {}) as u64", + GetUnsafeTypeAsString(expr->getTypeSourceInfo()->getType()), + member_path)); + computed_expr_type_ = ComputedExprType::FreshValue; + return false; +} + bool Converter::VisitEnumDecl(clang::EnumDecl *decl) { ENSURE(decl_ids_.insert(GetID(decl)).second); if (Mapper::Contains(ctx_.getCanonicalTagType(decl))) { diff --git a/cpp2rust/converter/converter.h b/cpp2rust/converter/converter.h index 9d64ef22..fc1d8f54 100644 --- a/cpp2rust/converter/converter.h +++ b/cpp2rust/converter/converter.h @@ -349,6 +349,8 @@ class Converter : public clang::RecursiveASTVisitor { virtual bool VisitTypeTraitExpr(clang::TypeTraitExpr *expr); + virtual bool VisitOffsetOfExpr(clang::OffsetOfExpr *expr); + virtual bool VisitEnumDecl(clang::EnumDecl *decl); virtual void AddFromImpl(clang::EnumDecl *decl); diff --git a/tests/unit/offsetof.cpp b/tests/unit/offsetof.cpp new file mode 100644 index 00000000..16b99134 --- /dev/null +++ b/tests/unit/offsetof.cpp @@ -0,0 +1,36 @@ +// no-compile: refcount +#include +#include +#include + +struct Layout { + uint8_t a; + uint32_t b; + uint16_t c; +}; + +struct Inner { + uint16_t x; + uint32_t y; +}; + +struct Outer { + uint8_t pad; + struct Inner inner; +}; + +int main(void) { + assert(offsetof(struct Layout, a) == 0); + 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); + + return 0; +} diff --git a/tests/unit/out/unsafe/offsetof.rs b/tests/unit/out/unsafe/offsetof.rs new file mode 100644 index 00000000..fc9c6ad8 --- /dev/null +++ b/tests/unit/out/unsafe/offsetof.rs @@ -0,0 +1,49 @@ +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 Layout { + pub a: u8, + pub b: u32, + pub c: u16, +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct Inner { + pub x: u16, + pub y: u32, +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct Outer { + pub pad: u8, + pub inner: Inner, +} +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + assert!(((::std::mem::offset_of!(Layout, a) as u64) == (0_u64))); + assert!(((::std::mem::offset_of!(Layout, b) as u64) == (4_u64))); + assert!(((::std::mem::offset_of!(Layout, c) as u64) == (8_u64))); + assert!(((::std::mem::offset_of!(Outer, inner.y) as u64) == (8_u64))); + let mut v: Layout = Layout { + a: 0_u8, + b: 0_u32, + c: 0_u16, + }; + v.b = 3735928559_u32; + let mut base: *mut u8 = ((&mut v as *mut Layout) as *mut u8); + let mut bp: *mut u32 = + ((base.offset((::std::mem::offset_of!(Layout, b) as u64) as isize)) as *mut u32); + assert!(((*bp) == (3735928559_u32))); + return 0; +}