Skip to content
Open
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
15 changes: 15 additions & 0 deletions cpp2rust/converter/converter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -669,6 +669,15 @@ bool Converter::VisitVarDecl(clang::VarDecl *decl) {
}
EmitScopedDestructor(decl);

if (auto *decomp = clang::dyn_cast<clang::DecompositionDecl>(decl)) {
for (auto *binding : decomp->bindings()) {
if (auto *holding = binding->getHoldingVar()) {
StrCat(token::kSemiColon);
VisitVarDecl(holding);
}
}
}

return false;
}

Expand Down Expand Up @@ -3299,10 +3308,16 @@ bool Converter::VisitDeclRefExpr(clang::DeclRefExpr *expr) {
computed_expr_type_ = ComputedExprType::FreshValue;
return false;
}

if (auto init = AsLambdaUncapturedConstant(curr_function_, expr)) {
Convert(init);
return false;
}

if (auto *binding = clang::dyn_cast<clang::BindingDecl>(expr->getDecl())) {
Convert(binding->getBinding());
return false;
}
ConvertDeclRefValue(expr, expr->getDecl());
return false;
}
Expand Down
47 changes: 37 additions & 10 deletions cpp2rust/converter/converter_lib.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -528,12 +528,21 @@ IsConvertibleImplicitMemberParent(const clang::CXXRecordDecl *decl) {
decl->getNumBases() == 0;
}

static bool HasFieldWithMoveFrom(const clang::RecordDecl *decl) {
return llvm::any_of(decl->fields(), [](const clang::FieldDecl *field) {
auto *record = field->getType()->getAsRecordDecl();
return record && HasMoveFromConstructor(record);
});
}

bool IsConvertibleMoveConstructor(const clang::CXXConstructorDecl *ctor) {
return ctor->isMoveConstructor() && !ctor->isDeleted() &&
IsConvertibleImplicitMemberParent(ctor->getParent()) &&
(ctor->isUserProvided() ||
!HasDefaultedCopyConstructor(ctor->getParent())) &&
ctor->hasBody();
auto *parent = ctor->getParent();
if (!ctor->isMoveConstructor() || ctor->isDeleted() || !ctor->hasBody() ||
!IsConvertibleImplicitMemberParent(parent)) {
return false;
}
return ctor->isUserProvided() || !HasDefaultedCopyConstructor(parent) ||
HasFieldWithMoveFrom(parent);
}

bool HasMoveFromConstructor(const clang::RecordDecl *decl) {
Expand All @@ -544,12 +553,23 @@ bool HasMoveFromConstructor(const clang::RecordDecl *decl) {
});
}

static bool HasFieldWithMoveAssign(const clang::RecordDecl *decl) {
return llvm::any_of(decl->fields(), [](const clang::FieldDecl *field) {
auto *record = field->getType()->getAsCXXRecordDecl();
return record && llvm::any_of(record->methods(), [](auto *method) {
return IsConvertibleMoveAssignment(method);
});
});
}

bool IsConvertibleMoveAssignment(const clang::CXXMethodDecl *method) {
return method->isMoveAssignmentOperator() && !method->isDeleted() &&
IsConvertibleImplicitMemberParent(method->getParent()) &&
(method->isUserProvided() ||
!HasDefaultedCopyAssignment(method->getParent())) &&
method->hasBody();
auto *parent = method->getParent();
if (!method->isMoveAssignmentOperator() || method->isDeleted() ||
!method->hasBody() || !IsConvertibleImplicitMemberParent(parent)) {
return false;
}
return method->isUserProvided() || !HasDefaultedCopyAssignment(parent) ||
HasFieldWithMoveAssign(parent);
}

bool IsConvertibleImplicitMember(const clang::CXXMethodDecl *method) {
Expand Down Expand Up @@ -998,6 +1018,13 @@ std::string GetNamedDeclAsString(const clang::NamedDecl *decl) {
}
}

if (clang::isa<clang::DecompositionDecl>(decl)) {
return std::format(
"__decomp_{}",
type_mapping.try_emplace(GetID(decl), type_mapping.size())
.first->second);
}

// Anonymous record or enum
if (name.empty() &&
(clang::isa<clang::RecordDecl>(decl) ||
Expand Down
1 change: 1 addition & 0 deletions cpp2rust/converter/models/boxed_vars.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ bool CanUnbox(const clang::VarDecl *decl) {
}
return (decl->isLocalVarDecl() || clang::isa<clang::ParmVarDecl>(decl)) &&
!IsGlobalVar(decl) && !decl->isInitCapture() &&
!clang::isa<clang::DecompositionDecl>(decl) &&
!IsVaListType(decl->getType());
}

Expand Down
8 changes: 8 additions & 0 deletions rules/pair/src.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,11 @@ template <typename T1, typename T2> const T1 &f19(const std::pair<T1, T2> &a0) {
template <typename T1, typename T2> const T2 &f20(const std::pair<T1, T2> &a0) {
return std::get<1>(a0);
}

template <typename T1, typename T2> T1 &&f21(std::pair<T1, T2> &&a0) {
return std::get<0>(std::move(a0));
}

template <typename T1, typename T2> T2 &&f22(std::pair<T1, T2> &&a0) {
return std::get<1>(std::move(a0));
}
8 changes: 8 additions & 0 deletions rules/pair/tgt_refcount.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,11 @@ fn f19<T1, T2>(a0: (Value<T1>, Value<T2>)) -> Ptr<T1> {
fn f20<T1, T2>(a0: (Value<T1>, Value<T2>)) -> Ptr<T2> {
a0.1.as_pointer()
}

fn f21<T1, T2>(a0: (Value<T1>, Value<T2>)) -> Ptr<T1> {
a0.0.as_pointer()
}

fn f22<T1, T2>(a0: (Value<T1>, Value<T2>)) -> Ptr<T2> {
a0.1.as_pointer()
}
8 changes: 8 additions & 0 deletions rules/pair/tgt_unsafe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,11 @@ unsafe fn f19<T1, T2>(a0: &(T1, T2)) -> *const T1 {
unsafe fn f20<T1, T2>(a0: &(T1, T2)) -> *const T2 {
&a0.1
}

unsafe fn f21<T1, T2>(a0: &mut (T1, T2)) -> *mut T1 {
&mut a0.0
}

unsafe fn f22<T1, T2>(a0: &mut (T1, T2)) -> *mut T2 {
&mut a0.1
}
11 changes: 9 additions & 2 deletions tests/unit/out/refcount/copy_ctor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,13 +143,20 @@ impl Clone for Box_int_ {
Box_int_::copy_from(__src.as_pointer())
}
}
#[derive(Clone, Record, ByteRepr, VaArg, FnPtrArg, Default)]
#[derive(Clone, Record, ByteRepr, VaArg, FnPtrArg, MoveCtor, Default)]
#[byte_size(4)]
pub struct Owner {
#[offset(0)]
#[byte_size(4)]
pub box_: Box_int_,
}
impl Owner {
pub fn move_from(_a0: Ptr<Owner>) -> Self {
Self {
box_: Box_int_::move_from({ field_ptr!(_a0, box_) }),
}
}
}
#[derive(Record, ByteRepr, VaArg, FnPtrArg, Default)]
#[byte_size(4)]
pub struct OutOfLine {
Expand Down Expand Up @@ -272,7 +279,7 @@ fn main_0() -> i32 {
let o: Value<Owner> = Rc::new(RefCell::new(Owner {
box_: Box_int_::new({ 3 }),
}));
let mut o2: Owner = (*o.borrow()).clone();
let mut o2: Owner = Owner::move_from({ o.as_pointer() });
assert!((o2.box_.val == 3));
let ol1: Value<OutOfLine> = Rc::new(RefCell::new(OutOfLine::new({ 5 })));
let mut ol2: OutOfLine = OutOfLine::copy_from({ ol1.as_pointer() });
Expand Down
34 changes: 34 additions & 0 deletions tests/unit/out/refcount/structured_binding_array.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
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() {
__cpp2rust_init_globals();
std::process::exit(main_0());
}
fn main_0() -> i32 {
let arr: Value<Box<[i32]>> = Rc::new(RefCell::new(Box::new([1, 2, 3])));
let __decomp_0: Value<Box<[i32]>> =
Rc::new(RefCell::new(Box::new(std::array::from_fn::<_, 3, _>(
|__i: usize| (*arr.borrow())[(__i) as usize],
))));
(*__decomp_0.borrow_mut())[(0) as usize] = 10;
assert!(((*__decomp_0.borrow())[(0) as usize] == 10));
assert!(((*__decomp_0.borrow())[(1) as usize] == 2));
assert!(((*__decomp_0.borrow())[(2) as usize] == 3));
assert!(((*arr.borrow())[(0) as usize] == 1));
let __decomp_1: Ptr<i32> = arr.as_pointer();
elem!((__decomp_1), 0).write(7);
{
let __rhs = (elem!((__decomp_1), 1).read());
elem!((__decomp_1), 2).with_mut(|__v| *__v = *__v + __rhs)
};
assert!(((*arr.borrow())[(0) as usize] == 7));
assert!(((*arr.borrow())[(2) as usize] == 5));
return 0;
}
pub fn __cpp2rust_init_globals() {}
70 changes: 70 additions & 0 deletions tests/unit/out/refcount/structured_binding_copy_ctor.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
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};
thread_local!(
pub static copies_0: Value<i32> = Rc::new(RefCell::new(0));
);
#[derive(Record, ByteRepr, VaArg, FnPtrArg, Default)]
#[byte_size(8)]
pub struct Counted {
#[offset(0)]
pub x: i32,
#[offset(4)]
pub y: i32,
}
impl Counted {
pub fn new(mut x: i32, mut y: i32) -> Self {
Self { x: x, y: y }
}
pub fn copy_from(other: Ptr<Counted>) -> Self {
let __this: Counted = Self {
x: (other.with(|__s| __s.x) * 2),
y: (other.with(|__s| __s.y) * 2),
};
(*copies_0.with(Value::clone).borrow_mut()).prefix_inc();
__this
}
}
impl Clone for Counted {
fn clone(&self) -> Self {
let __src: Value<Counted> = Rc::new(RefCell::new(Counted {
x: self.x.clone(),
y: self.y.clone(),
}));
Counted::copy_from(__src.as_pointer())
}
}
pub fn make_counted_1() -> Counted {
return Counted::new({ 5 }, { 6 });
}
pub fn main() {
__cpp2rust_init_globals();
std::process::exit(main_0());
}
fn main_0() -> i32 {
let s: Value<Counted> = Rc::new(RefCell::new(Counted::new({ 1 }, { 2 })));
let __decomp_2: Value<Counted> = Rc::new(RefCell::new(Counted::copy_from({ s.as_pointer() })));
assert!((copies_0.with(|rc| *rc.borrow()) == 1));
assert!(({ (*__decomp_2.borrow()).x } == 2));
assert!(({ (*__decomp_2.borrow()).y } == 4));
let __decomp_3: Ptr<Counted> = s.as_pointer();
assert!((copies_0.with(|rc| *rc.borrow()) == 1));
assert!((__decomp_3.with(|__s| __s.x) == 1));
assert!((__decomp_3.with(|__s| __s.y) == 2));
let __decomp_4: Ptr<Counted> = s.as_pointer();
assert!((copies_0.with(|rc| *rc.borrow()) == 1));
assert!((__decomp_4.with(|__s| __s.x) == 1));
let __decomp_5: Value<Counted> = Rc::new(RefCell::new(({ make_counted_1() })));
assert!((copies_0.with(|rc| *rc.borrow()) == 1));
assert!(({ (*__decomp_5.borrow()).x } == 5));
assert!(({ (*__decomp_5.borrow()).y } == 6));
return 0;
}
pub fn __cpp2rust_init_globals() {
let _ = copies_0.with(|_| ());
}
Loading
Loading