Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
10 changes: 10 additions & 0 deletions cpp2rust/converter/converter_lib.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<clang::MemberExpr>(base->IgnoreParenImpCasts())) {
if (auto *fd = clang::dyn_cast<clang::FieldDecl>(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();
Expand Down
2 changes: 2 additions & 0 deletions cpp2rust/converter/converter_lib.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
14 changes: 9 additions & 5 deletions cpp2rust/converter/models/converter_refcount.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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()) {
Expand Down Expand Up @@ -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<u8>).reinterpret_cast() }}",
GetNamedDeclAsString(field), storage_ty));
GetNamedDeclAsString(field), ty));
}
}

Expand Down
29 changes: 19 additions & 10 deletions libcc2rs/src/rc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ pub enum StrongPtr<T> {
Reinterpreted {
alloc: Rc<dyn OriginalAlloc>,
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<Option<T>>,
Expand All @@ -63,10 +64,11 @@ impl<T: ByteRepr> StrongPtr<T> {
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())
Expand Down Expand Up @@ -353,6 +355,7 @@ impl<T> Ptr<T> {
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),
},
}
Expand All @@ -377,7 +380,7 @@ impl<T> Ptr<T> {
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);
}
Expand Down Expand Up @@ -406,20 +409,26 @@ impl<T> Ptr<T> {
panic!("cannot reinterpret_cast to zero-sized type");
}

let src_byte_off = self.offset.wrapping_mul(T::byte_size());
self.reinterpret_sized::<U>(U::byte_size())
}

pub fn reinterpret_sized<U>(&self, elem_byte_size: usize) -> Ptr<U>
where
T: ByteRepr,
{
let (alloc, abs_byte_off): (Rc<dyn OriginalAlloc>, 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),
};
Expand All @@ -428,7 +437,7 @@ impl<T> Ptr<T> {
offset: abs_byte_off,
kind: PtrKind::Reinterpreted(Rc::new(ReinterpretedView {
alloc,
elem_byte_size: U::byte_size(),
elem_byte_size,
})),
}
}
Expand Down Expand Up @@ -457,7 +466,7 @@ impl<T> Ptr<T> {
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);
Expand Down Expand Up @@ -490,7 +499,7 @@ impl<T> Ptr<T> {
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)
Expand All @@ -517,7 +526,7 @@ impl<T: Clone + ByteRepr> Ptr<T> {
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)
}
Expand Down
13 changes: 12 additions & 1 deletion libcc2rs/src/reinterpret.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,18 @@ impl<T: ByteRepr> ByteRepr for Vec<T> {}
impl<T: ByteRepr> ByteRepr for Option<T> {}
impl<T: ByteRepr> ByteRepr for std::rc::Rc<T> {}
impl<T: ByteRepr> ByteRepr for std::cell::RefCell<T> {}
impl<T: ByteRepr> ByteRepr for Box<[T]> {}
impl<T: ByteRepr> 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<T: ByteRepr> ByteRepr for Box<T> {}
impl<T: 'static> ByteRepr for *const T {}
impl<T: 'static> ByteRepr for *mut T {}
Expand Down
17 changes: 13 additions & 4 deletions tests/unit/out/refcount/union_addrof_external.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ impl anon_0 {
pub fn h(&self) -> Ptr<record> {
(self.__bytes.as_pointer() as Ptr<u8>).reinterpret_cast()
}
pub fn raw_(&self) -> Ptr<Box<[u8]>> {
pub fn raw_(&self) -> Ptr<u8> {
(self.__bytes.as_pointer() as Ptr<u8>).reinterpret_cast()
}
}
Expand Down Expand Up @@ -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::<u8>() as Ptr::<u8>)
.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::<u8>() as Ptr::<u8>)
.offset((3) as isize)
.read()) as u8) as i32)
== 80) as i32)
!= 0)
);
return 0;
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/out/refcount/union_cross_arm_cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ impl anon_0 {
pub fn b(&self) -> Ptr<shape_b> {
(self.__bytes.as_pointer() as Ptr<u8>).reinterpret_cast()
}
pub fn raw_(&self) -> Ptr<Box<[u8]>> {
pub fn raw_(&self) -> Ptr<u8> {
(self.__bytes.as_pointer() as Ptr<u8>).reinterpret_cast()
}
}
Expand Down
84 changes: 84 additions & 0 deletions tests/unit/out/refcount/union_field_alignment.rs
Original file line number Diff line number Diff line change
@@ -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<Box<[u8]>>,
}
impl anon_0 {
pub fn bytes(&self) -> Ptr<u8> {
(self.__bytes.as_pointer() as Ptr<u8>).reinterpret_cast()
}
pub fn aligner(&self) -> Ptr<AnyPtr> {
(self.__bytes.as_pointer() as Ptr<u8>).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<Ptr<node>>,
pub x: Value<anon_0>,
}
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(<Ptr<node>>::from_bytes(&buf[0..8]))),
x: Rc::new(RefCell::new(<anon_0>::from_bytes(&buf[8..16]))),
}
}
}
pub fn main() {
std::process::exit(main_0());
}
fn main_0() -> i32 {
let n: Value<node> = <Value<node>>::default();
(*(*n.borrow()).next.borrow_mut()) = Ptr::<node>::null();
((*(*n.borrow()).x.borrow()).bytes().reinterpret_cast::<u8>() as Ptr<u8>)
.offset((0) as isize)
.write(171_u8);
assert!(
(((((((*(*n.borrow()).x.borrow()).bytes().reinterpret_cast::<u8>() as Ptr::<u8>)
.offset((0) as isize)
.read()) as i32)
== 171) as i32)
!= 0)
);
return 0;
}
16 changes: 13 additions & 3 deletions tests/unit/out/refcount/union_memset_memcpy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ impl anon_0 {
pub fn b(&self) -> Ptr<shape_b> {
(self.__bytes.as_pointer() as Ptr<u8>).reinterpret_cast()
}
pub fn raw_(&self) -> Ptr<Box<[u8]>> {
pub fn raw_(&self) -> Ptr<u8> {
(self.__bytes.as_pointer() as Ptr<u8>).reinterpret_cast()
}
}
Expand Down Expand Up @@ -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::<u8>() as Ptr::<u8>)
.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::<u8>() as Ptr::<u8>)
.offset((255) as isize)
.read()) as i32)
== 0) as i32)
!= 0)
);
let src: Value<Box<[u8]>> = Rc::new(RefCell::new(Box::new([
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/out/refcount/union_nested.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ impl anon_0 {
pub fn h(&self) -> Ptr<record> {
(self.__bytes.as_pointer() as Ptr<u8>).reinterpret_cast()
}
pub fn raw_(&self) -> Ptr<Box<[u8]>> {
pub fn raw_(&self) -> Ptr<u8> {
(self.__bytes.as_pointer() as Ptr<u8>).reinterpret_cast()
}
}
Expand Down
18 changes: 13 additions & 5 deletions tests/unit/out/refcount/union_struct_dual_use.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ impl anon_1 {
pub fn inner(&self) -> Ptr<Inner> {
(self.__bytes.as_pointer() as Ptr<u8>).reinterpret_cast()
}
pub fn raw_(&self) -> Ptr<Box<[u8]>> {
pub fn raw_(&self) -> Ptr<u8> {
(self.__bytes.as_pointer() as Ptr<u8>).reinterpret_cast()
}
}
Expand Down Expand Up @@ -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::<u8>() as Ptr::<u8>)
.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::<u8>() as Ptr::<u8>)
.offset((4) as isize)
.read()) as u8) as i32)
== 4) as i32)
!= 0)
);
return 0;
Expand Down
1 change: 0 additions & 1 deletion tests/unit/union_addrof_external.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// panic: refcount
#include <assert.h>
#include <stddef.h>
#include <stdint.h>
Expand Down
1 change: 0 additions & 1 deletion tests/unit/union_field_alignment.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// no-compile: refcount
#include <assert.h>
#include <stddef.h>
#include <stdint.h>
Expand Down
Loading