diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 5aba7cecc..6232f7d3b 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -669,6 +669,15 @@ bool Converter::VisitVarDecl(clang::VarDecl *decl) { } EmitScopedDestructor(decl); + if (auto *decomp = clang::dyn_cast(decl)) { + for (auto *binding : decomp->bindings()) { + if (auto *holding = binding->getHoldingVar()) { + StrCat(token::kSemiColon); + VisitVarDecl(holding); + } + } + } + return false; } @@ -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(expr->getDecl())) { + Convert(binding->getBinding()); + return false; + } ConvertDeclRefValue(expr, expr->getDecl()); return false; } diff --git a/cpp2rust/converter/converter_lib.cpp b/cpp2rust/converter/converter_lib.cpp index edfdaa46f..ad718cfe6 100644 --- a/cpp2rust/converter/converter_lib.cpp +++ b/cpp2rust/converter/converter_lib.cpp @@ -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) { @@ -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) { @@ -998,6 +1018,13 @@ std::string GetNamedDeclAsString(const clang::NamedDecl *decl) { } } + if (clang::isa(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(decl) || diff --git a/cpp2rust/converter/models/boxed_vars.cpp b/cpp2rust/converter/models/boxed_vars.cpp index 467d53302..ee70f95f0 100644 --- a/cpp2rust/converter/models/boxed_vars.cpp +++ b/cpp2rust/converter/models/boxed_vars.cpp @@ -53,6 +53,7 @@ bool CanUnbox(const clang::VarDecl *decl) { } return (decl->isLocalVarDecl() || clang::isa(decl)) && !IsGlobalVar(decl) && !decl->isInitCapture() && + !clang::isa(decl) && !IsVaListType(decl->getType()); } diff --git a/rules/pair/src.cpp b/rules/pair/src.cpp index 508e96f77..b81a3c3ac 100644 --- a/rules/pair/src.cpp +++ b/rules/pair/src.cpp @@ -64,3 +64,11 @@ template const T1 &f19(const std::pair &a0) { template const T2 &f20(const std::pair &a0) { return std::get<1>(a0); } + +template T1 &&f21(std::pair &&a0) { + return std::get<0>(std::move(a0)); +} + +template T2 &&f22(std::pair &&a0) { + return std::get<1>(std::move(a0)); +} diff --git a/rules/pair/tgt_refcount.rs b/rules/pair/tgt_refcount.rs index 5cfff3711..07757ab39 100644 --- a/rules/pair/tgt_refcount.rs +++ b/rules/pair/tgt_refcount.rs @@ -84,3 +84,11 @@ fn f19(a0: (Value, Value)) -> Ptr { fn f20(a0: (Value, Value)) -> Ptr { a0.1.as_pointer() } + +fn f21(a0: (Value, Value)) -> Ptr { + a0.0.as_pointer() +} + +fn f22(a0: (Value, Value)) -> Ptr { + a0.1.as_pointer() +} diff --git a/rules/pair/tgt_unsafe.rs b/rules/pair/tgt_unsafe.rs index d679f6594..c9c5bcff5 100644 --- a/rules/pair/tgt_unsafe.rs +++ b/rules/pair/tgt_unsafe.rs @@ -53,3 +53,11 @@ unsafe fn f19(a0: &(T1, T2)) -> *const T1 { unsafe fn f20(a0: &(T1, T2)) -> *const T2 { &a0.1 } + +unsafe fn f21(a0: &mut (T1, T2)) -> *mut T1 { + &mut a0.0 +} + +unsafe fn f22(a0: &mut (T1, T2)) -> *mut T2 { + &mut a0.1 +} diff --git a/tests/unit/out/refcount/copy_ctor.rs b/tests/unit/out/refcount/copy_ctor.rs index 5fe0d932a..070c80b57 100644 --- a/tests/unit/out/refcount/copy_ctor.rs +++ b/tests/unit/out/refcount/copy_ctor.rs @@ -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) -> Self { + Self { + box_: Box_int_::move_from({ field_ptr!(_a0, box_) }), + } + } +} #[derive(Record, ByteRepr, VaArg, FnPtrArg, Default)] #[byte_size(4)] pub struct OutOfLine { @@ -272,7 +279,7 @@ fn main_0() -> i32 { let o: Value = 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 = Rc::new(RefCell::new(OutOfLine::new({ 5 }))); let mut ol2: OutOfLine = OutOfLine::copy_from({ ol1.as_pointer() }); diff --git a/tests/unit/out/refcount/structured_binding_array.rs b/tests/unit/out/refcount/structured_binding_array.rs new file mode 100644 index 000000000..1d8f51014 --- /dev/null +++ b/tests/unit/out/refcount/structured_binding_array.rs @@ -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> = Rc::new(RefCell::new(Box::new([1, 2, 3]))); + let __decomp_0: Value> = + 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 = 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() {} diff --git a/tests/unit/out/refcount/structured_binding_copy_ctor.rs b/tests/unit/out/refcount/structured_binding_copy_ctor.rs new file mode 100644 index 000000000..41d029a1f --- /dev/null +++ b/tests/unit/out/refcount/structured_binding_copy_ctor.rs @@ -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 = 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) -> 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 = 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 = Rc::new(RefCell::new(Counted::new({ 1 }, { 2 }))); + let __decomp_2: Value = 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 = 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 = s.as_pointer(); + assert!((copies_0.with(|rc| *rc.borrow()) == 1)); + assert!((__decomp_4.with(|__s| __s.x) == 1)); + let __decomp_5: Value = 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(|_| ()); +} diff --git a/tests/unit/out/refcount/structured_binding_element_ctor.rs b/tests/unit/out/refcount/structured_binding_element_ctor.rs new file mode 100644 index 000000000..85fef2b42 --- /dev/null +++ b/tests/unit/out/refcount/structured_binding_element_ctor.rs @@ -0,0 +1,126 @@ +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 = Rc::new(RefCell::new(0)); +); +thread_local!( + pub static moves_1: Value = Rc::new(RefCell::new(0)); +); +#[derive(Record, ByteRepr, VaArg, FnPtrArg, MoveCtor, Default)] +#[byte_size(4)] +pub struct Elem { + #[offset(0)] + pub v: i32, +} +impl Elem { + pub fn new(mut v: i32) -> Self { + Self { v: v } + } + pub fn copy_from(other: Ptr) -> Self { + let __this: Elem = Self { + v: (other.with(|__s| __s.v) + 100), + }; + (*copies_0.with(Value::clone).borrow_mut()).prefix_inc(); + __this + } + pub fn move_from(other: Ptr) -> Self { + let __this: Elem = Self { + v: (other.with(|__s| __s.v) + 1000), + }; + field!(other, v).write(-1_i32); + (*moves_1.with(Value::clone).borrow_mut()).prefix_inc(); + __this + } +} +impl Clone for Elem { + fn clone(&self) -> Self { + let __src: Value = Rc::new(RefCell::new(Elem { v: self.v.clone() })); + Elem::copy_from(__src.as_pointer()) + } +} +#[derive(Clone, Record, ByteRepr, VaArg, FnPtrArg, MoveCtor, Default)] +#[byte_size(8)] +pub struct Two { + #[offset(0)] + #[byte_size(4)] + pub a: Elem, + #[offset(4)] + #[byte_size(4)] + pub b: Elem, +} +impl Two { + pub fn move_from(_a0: Ptr) -> Self { + Self { + a: Elem::move_from({ field_ptr!(_a0, a) }), + b: Elem::move_from({ field_ptr!(_a0, b) }), + } + } +} +pub fn make_two_2() -> Two { + return Two { + a: Elem::new({ 1 }), + b: Elem::new({ 2 }), + }; +} +pub fn main() { + __cpp2rust_init_globals(); + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let t: Value = Rc::new(RefCell::new(Two { + a: Elem::new({ 1 }), + b: Elem::new({ 2 }), + })); + let mut base_copies: i32 = copies_0.with(|rc| *rc.borrow()); + let mut base_moves: i32 = moves_1.with(|rc| *rc.borrow()); + let __decomp_3: Value = Rc::new(RefCell::new((*t.borrow()).clone())); + assert!((copies_0.with(|rc| *rc.borrow()) == (base_copies + 2))); + assert!((moves_1.with(|rc| *rc.borrow()) == base_moves)); + assert!(({ (*__decomp_3.borrow()).a.v } == 101)); + assert!(({ (*__decomp_3.borrow()).b.v } == 102)); + let __decomp_4: Ptr = t.as_pointer(); + assert!((copies_0.with(|rc| *rc.borrow()) == (base_copies + 2))); + assert!(({ (*__decomp_4.upgrade().deref()).a.v } == 1)); + field!(field!(__decomp_4, a), v).write(50); + assert!(({ (*t.borrow()).a.v } == 50)); + let __decomp_5: Value = Rc::new(RefCell::new(Two::move_from({ t.as_pointer() }))); + assert!((moves_1.with(|rc| *rc.borrow()) == (base_moves + 2))); + assert!(({ (*__decomp_5.borrow()).a.v } == 1050)); + assert!(({ (*__decomp_5.borrow()).b.v } == 1002)); + assert!(({ (*t.borrow()).a.v } == -1_i32)); + let mut before_copies: i32 = copies_0.with(|rc| *rc.borrow()); + let mut before_moves: i32 = moves_1.with(|rc| *rc.borrow()); + let __decomp_6: Value = Rc::new(RefCell::new(({ make_two_2() }))); + assert!((copies_0.with(|rc| *rc.borrow()) == before_copies)); + assert!((moves_1.with(|rc| *rc.borrow()) == before_moves)); + assert!(({ (*__decomp_6.borrow()).a.v } == 1)); + let p: Value<(Value, Value)> = Rc::new(RefCell::new(( + Rc::new(RefCell::new( + Elem::new({ 7 }).try_into().expect("failed conversion"), + )), + Rc::new(RefCell::new( + Elem::new({ 8 }).try_into().expect("failed conversion"), + )), + ))); + before_copies = copies_0.with(|rc| *rc.borrow()); + let __decomp_7: Value<(Value, Value)> = Rc::new(RefCell::new(( + Rc::new(RefCell::new((*p.borrow()).0.borrow().clone())), + Rc::new(RefCell::new((*p.borrow()).1.borrow().clone())), + ))); + let x: Ptr = (*__decomp_7.borrow()).0.as_pointer(); + let y: Ptr = (*__decomp_7.borrow()).1.as_pointer(); + assert!((copies_0.with(|rc| *rc.borrow()) == (before_copies + 2))); + assert!(({ (*x.upgrade().deref()).v } == ({ (*(*p.borrow()).0.borrow()).v } + 100))); + assert!(({ (*y.upgrade().deref()).v } == ({ (*(*p.borrow()).1.borrow()).v } + 100))); + return 0; +} +pub fn __cpp2rust_init_globals() { + let _ = copies_0.with(|_| ()); + let _ = moves_1.with(|_| ()); +} diff --git a/tests/unit/out/refcount/structured_binding_move_ctor.rs b/tests/unit/out/refcount/structured_binding_move_ctor.rs new file mode 100644 index 000000000..2686fc4ef --- /dev/null +++ b/tests/unit/out/refcount/structured_binding_move_ctor.rs @@ -0,0 +1,124 @@ +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 = Rc::new(RefCell::new(0)); +); +thread_local!( + pub static moves_1: Value = Rc::new(RefCell::new(0)); +); +#[derive(Record, ByteRepr, VaArg, FnPtrArg, MoveCtor, Default)] +#[byte_size(8)] +pub struct Movable { + #[offset(0)] + pub x: i32, + #[offset(4)] + pub y: i32, +} +impl Movable { + pub fn new(mut x: i32, mut y: i32) -> Self { + Self { x: x, y: y } + } + pub fn copy_from(other: Ptr) -> Self { + let __this: Movable = Self { + x: other.with(|__s| __s.x), + y: other.with(|__s| __s.y), + }; + (*copies_0.with(Value::clone).borrow_mut()).prefix_inc(); + __this + } + pub fn move_from(other: Ptr) -> Self { + let __this: Movable = Self { + x: other.with(|__s| __s.x), + y: other.with(|__s| __s.y), + }; + field!(other, x).write(0); + field!(other, y).write(0); + (*moves_1.with(Value::clone).borrow_mut()).prefix_inc(); + __this + } +} +impl Clone for Movable { + fn clone(&self) -> Self { + let __src: Value = Rc::new(RefCell::new(Movable { + x: self.x.clone(), + y: self.y.clone(), + })); + Movable::copy_from(__src.as_pointer()) + } +} +#[derive(DeepClone, Record, ByteRepr, VaArg, FnPtrArg, Default)] +#[byte_size(48)] +pub struct Holder { + #[offset(0)] + #[byte_size(24)] + pub xs: Value>, + #[offset(24)] + #[byte_size(24)] + pub ys: Value>, +} +pub fn main() { + __cpp2rust_init_globals(); + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let m: Value = Rc::new(RefCell::new(Movable::new({ 3 }, { 4 }))); + let __decomp_2: Value = Rc::new(RefCell::new(Movable::move_from({ m.as_pointer() }))); + assert!((moves_1.with(|rc| *rc.borrow()) == 1)); + assert!((copies_0.with(|rc| *rc.borrow()) == 0)); + assert!(({ (*__decomp_2.borrow()).x } == 3)); + assert!(({ (*__decomp_2.borrow()).y } == 4)); + assert!(({ (*m.borrow()).x } == 0)); + assert!(({ (*m.borrow()).y } == 0)); + let h: Value = Rc::new(RefCell::new(Holder { + xs: Rc::new(RefCell::new(vec![1, 2, 3])), + ys: Rc::new(RefCell::new(vec![4, 5])), + })); + let __decomp_3: Value = + Rc::new(RefCell::new(({ HolderImpl::extract(&h.as_pointer()) }))); + assert!(((*{ (*__decomp_3.borrow()).xs.clone() }.borrow()).len() == 3_usize)); + assert!(((*{ (*__decomp_3.borrow()).ys.clone() }.borrow()).len() == 2_usize)); + assert!( + ((elem!( + ({ (*__decomp_3.borrow()).xs.as_pointer() } as Ptr), + 2_usize + ) + .read()) + == 3) + ); + assert!( + ((elem!( + ({ (*__decomp_3.borrow()).ys.as_pointer() } as Ptr), + 0_usize + ) + .read()) + == 4) + ); + assert!((*{ (*h.borrow()).xs.clone() }.borrow()).is_empty()); + assert!((*{ (*h.borrow()).ys.clone() }.borrow()).is_empty()); + return 0; +} +pub trait HolderImpl { + fn extract(&self) -> Holder; +} +impl HolderImpl for Ptr { + fn extract(&self) -> Holder { + return Holder { + xs: Rc::new(RefCell::new(std::mem::take( + &mut (*(*self).with(|__s| __s.xs.clone()).borrow_mut()), + ))), + ys: Rc::new(RefCell::new(std::mem::take( + &mut (*(*self).with(|__s| __s.ys.clone()).borrow_mut()), + ))), + }; + } +} +pub fn __cpp2rust_init_globals() { + let _ = copies_0.with(|_| ()); + let _ = moves_1.with(|_| ()); +} diff --git a/tests/unit/out/refcount/structured_binding_pair.rs b/tests/unit/out/refcount/structured_binding_pair.rs new file mode 100644 index 000000000..c00bd9f9a --- /dev/null +++ b/tests/unit/out/refcount/structured_binding_pair.rs @@ -0,0 +1,51 @@ +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 make_std_pair_0(mut x: i32) -> (Value, Value) { + return ( + Rc::new(RefCell::new(x.try_into().expect("failed conversion"))), + Rc::new(RefCell::new((x > 0).try_into().expect("failed conversion"))), + ); +} +pub fn main() { + __cpp2rust_init_globals(); + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let __decomp_1: Value<(Value, Value)> = + Rc::new(RefCell::new(({ make_std_pair_0(5) }))); + let value: Ptr = (*__decomp_1.borrow()).0.as_pointer(); + let positive: Ptr = (*__decomp_1.borrow()).1.as_pointer(); + assert!(((value.read()) == 5)); + assert!(((positive.read()) as bool)); + let p: Value<(Value, Value)> = Rc::new(RefCell::new(( + Rc::new(RefCell::new(1.try_into().expect("failed conversion"))), + Rc::new(RefCell::new(2.try_into().expect("failed conversion"))), + ))); + let __decomp_2: Value<(Value, Value)> = Rc::new(RefCell::new(( + Rc::new(RefCell::new((*p.borrow()).0.borrow().clone())), + Rc::new(RefCell::new((*p.borrow()).1.borrow().clone())), + ))); + let a: Ptr = (*__decomp_2.borrow()).0.as_pointer(); + let b: Ptr = (*__decomp_2.borrow()).1.as_pointer(); + a.write(10); + assert!(((a.read()) == 10)); + assert!(((b.read()) == 2)); + assert!(((*(*p.borrow()).0.borrow()) == 1)); + let __decomp_3: Ptr<(Value, Value)> = p.as_pointer(); + let x: Ptr = (*__decomp_3.upgrade().deref()).0.as_pointer(); + let y: Ptr = (*__decomp_3.upgrade().deref()).1.as_pointer(); + x.write(3); + { + y.with_mut(|__v| *__v = *__v + 4) + }; + assert!(((*(*p.borrow()).0.borrow()) == 3)); + assert!(((*(*p.borrow()).1.borrow()) == 6)); + return 0; +} +pub fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/refcount/structured_binding_range_for.rs b/tests/unit/out/refcount/structured_binding_range_for.rs new file mode 100644 index 000000000..7005eb29c --- /dev/null +++ b/tests/unit/out/refcount/structured_binding_range_for.rs @@ -0,0 +1,58 @@ +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(Clone, Record, ByteRepr, VaArg, FnPtrArg, Default)] +#[byte_size(8)] +pub struct Pair { + #[offset(0)] + pub first: i32, + #[offset(4)] + pub second: i32, +} +pub fn main() { + __cpp2rust_init_globals(); + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let arr: Value> = Rc::new(RefCell::new(Box::new([ + Pair { + first: 1, + second: 2, + }, + Pair { + first: 3, + second: 4, + }, + Pair { + first: 5, + second: 6, + }, + ]))); + 'loop_: for mut __decomp_0 in arr.as_pointer() as Ptr { + { + let __rhs = __decomp_0.with(|__s| __s.second); + field!(__decomp_0, first).with_mut(|__v| *__v = *__v + __rhs) + }; + } + assert!(({ (*arr.borrow())[(0) as usize].first } == 3)); + assert!(({ (*arr.borrow())[(2) as usize].first } == 11)); + 'loop_: for mut __decomp_1 in arr.as_pointer() as Ptr { + let __decomp_1: Value = Rc::new(RefCell::new(__decomp_1.upgrade().deref().clone())); + (*__decomp_1.borrow_mut()).first = 0; + (*__decomp_1.borrow_mut()).second = 0; + } + assert!(({ (*arr.borrow())[(1) as usize].first } == 7)); + assert!(({ (*arr.borrow())[(1) as usize].second } == 4)); + let mut sum: i32 = 0; + 'loop_: for mut __decomp_2 in arr.as_pointer() as Ptr { + sum += (__decomp_2.with(|__s| __s.first) * __decomp_2.with(|__s| __s.second)); + } + assert!((sum == (((3 * 2) + (7 * 4)) + (11 * 6)))); + return 0; +} +pub fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/refcount/structured_binding_ref.rs b/tests/unit/out/refcount/structured_binding_ref.rs new file mode 100644 index 000000000..ba4e6f54e --- /dev/null +++ b/tests/unit/out/refcount/structured_binding_ref.rs @@ -0,0 +1,53 @@ +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(Clone, Record, ByteRepr, VaArg, FnPtrArg, Default)] +#[byte_size(12)] +pub struct Triple { + #[offset(0)] + pub a: i32, + #[offset(4)] + pub b: bool, + #[offset(8)] + pub c: i32, +} +pub fn sum_0(t: Ptr) -> i32 { + let __decomp_1: Ptr = (t).clone(); + return ((__decomp_1.with(|__s| __s.a) + (if __decomp_1.with(|__s| __s.b) { 1 } else { 0 })) + + __decomp_1.with(|__s| __s.c)); +} +pub fn main() { + __cpp2rust_init_globals(); + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let t: Value = Rc::new(RefCell::new(Triple { + a: 10, + b: false, + c: 20, + })); + let __decomp_2: Ptr = t.as_pointer(); + field!(__decomp_2, a).write(11); + field!(__decomp_2, b).write(true); + { + field!(__decomp_2, c).with_mut(|__v| *__v = *__v + 1) + }; + assert!(({ (*t.borrow()).a } == 11)); + assert!({ (*t.borrow()).b }); + assert!(({ (*t.borrow()).c } == 21)); + (*t.borrow_mut()).a = 12; + assert!((__decomp_2.with(|__s| __s.a) == 12)); + let __decomp_3: Ptr = t.as_pointer(); + (*t.borrow_mut()).c = 30; + assert!((__decomp_3.with(|__s| __s.a) == 12)); + assert!(__decomp_3.with(|__s| __s.b)); + assert!((__decomp_3.with(|__s| __s.c) == 30)); + assert!((({ sum_0(t.as_pointer(),) }) == 43)); + return 0; +} +pub fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/refcount/structured_binding_trivial.rs b/tests/unit/out/refcount/structured_binding_trivial.rs new file mode 100644 index 000000000..a968d0cb2 --- /dev/null +++ b/tests/unit/out/refcount/structured_binding_trivial.rs @@ -0,0 +1,41 @@ +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(Clone, Record, ByteRepr, VaArg, FnPtrArg, Default)] +#[byte_size(8)] +pub struct Pair { + #[offset(0)] + pub first: i32, + #[offset(4)] + pub second: i32, +} +pub fn main() { + __cpp2rust_init_globals(); + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let __decomp_0: Value = Rc::new(RefCell::new(Pair { + first: 1, + second: 2, + })); + assert!(({ (*__decomp_0.borrow()).first } == 1)); + assert!(({ (*__decomp_0.borrow()).second } == 2)); + let mut p: Pair = Pair { + first: 10, + second: 20, + }; + let __decomp_1: Value = Rc::new(RefCell::new((p).clone())); + (*__decomp_1.borrow_mut()).first = 11; + (*__decomp_1.borrow_mut()).second += 1; + assert!(({ (*__decomp_1.borrow()).first } == 11)); + assert!(({ (*__decomp_1.borrow()).second } == 21)); + assert!((p.first == 10)); + assert!((p.second == 20)); + return 0; +} +pub fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/unsafe/copy_ctor.rs b/tests/unit/out/unsafe/copy_ctor.rs index f6aaee237..d25d2dd8f 100644 --- a/tests/unit/out/unsafe/copy_ctor.rs +++ b/tests/unit/out/unsafe/copy_ctor.rs @@ -113,10 +113,18 @@ impl Clone for Box_int_ { } } #[repr(C)] -#[derive(Clone, VaArg, FnPtrArg, Default)] +#[derive(Clone, VaArg, FnPtrArg, MoveCtorUnsafe, Default)] pub struct Owner { pub box_: Box_int_, } +impl Owner { + pub unsafe fn move_from(_a0: *mut Owner) -> Self { + let mut this = Self { + box_: Box_int_::move_from({ &mut (*_a0).box_ }), + }; + this + } +} #[repr(C)] #[derive(VaArg, FnPtrArg, Default)] pub struct OutOfLine { @@ -226,7 +234,7 @@ unsafe fn main_0() -> i32 { let mut o: Owner = Owner { box_: Box_int_::new({ 3 }), }; - let mut o2: Owner = o.clone(); + let mut o2: Owner = Owner::move_from({ &mut o }); assert!(((o2.box_.val) == (3))); let mut ol1: OutOfLine = OutOfLine::new({ 5 }); let mut ol2: OutOfLine = OutOfLine::copy_from({ &ol1 }); diff --git a/tests/unit/out/unsafe/structured_binding_array.rs b/tests/unit/out/unsafe/structured_binding_array.rs new file mode 100644 index 000000000..1bbfef98c --- /dev/null +++ b/tests/unit/out/unsafe/structured_binding_array.rs @@ -0,0 +1,30 @@ +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 { + __cpp2rust_init_globals(); + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut arr: [i32; 3] = [1, 2, 3]; + let mut __decomp_0: [i32; 3] = std::array::from_fn::<_, 3, _>(|__i: usize| arr[(__i)]); + __decomp_0[(0) as usize] = 10; + assert!(((__decomp_0[(0) as usize]) == (10))); + assert!(((__decomp_0[(1) as usize]) == (2))); + assert!(((__decomp_0[(2) as usize]) == (3))); + assert!(((arr[(0) as usize]) == (1))); + let __decomp_1: *mut [i32; 3] = &mut arr; + (*__decomp_1)[(0) as usize] = 7; + (*__decomp_1)[(2) as usize] += (*__decomp_1)[(1) as usize]; + assert!(((arr[(0) as usize]) == (7))); + assert!(((arr[(2) as usize]) == (5))); + return 0; +} +pub unsafe fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/unsafe/structured_binding_copy_ctor.rs b/tests/unit/out/unsafe/structured_binding_copy_ctor.rs new file mode 100644 index 000000000..003a2be14 --- /dev/null +++ b/tests/unit/out/unsafe/structured_binding_copy_ctor.rs @@ -0,0 +1,65 @@ +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 static mut copies_0: std::cell::LazyCell = std::cell::LazyCell::new(|| unsafe { 0 }); +#[repr(C)] +#[derive(VaArg, FnPtrArg, Default)] +pub struct Counted { + pub x: i32, + pub y: i32, +} +impl Counted { + pub unsafe fn new(mut x: i32, mut y: i32) -> Self { + let mut this = Self { x: x, y: y }; + this + } + pub unsafe fn copy_from(other: *const Counted) -> Self { + let mut this = Self { + x: (((*other).x) * (2)), + y: (((*other).y) * (2)), + }; + (*std::cell::LazyCell::force_mut(&mut *&raw mut copies_0)).prefix_inc(); + this + } +} +impl Clone for Counted { + fn clone(&self) -> Self { + unsafe { Counted::copy_from(self as *const Counted) } + } +} +pub unsafe fn make_counted_1() -> Counted { + return Counted::new({ 5 }, { 6 }); +} +pub fn main() { + unsafe { + __cpp2rust_init_globals(); + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut s: Counted = Counted::new({ 1 }, { 2 }); + let mut __decomp_2: Counted = Counted::copy_from({ &s }); + assert!(((*std::cell::LazyCell::force_mut(&mut *&raw mut copies_0)) == (1))); + assert!(((__decomp_2.x) == (2))); + assert!(((__decomp_2.y) == (4))); + let __decomp_3: *mut Counted = &mut s; + assert!(((*std::cell::LazyCell::force_mut(&mut *&raw mut copies_0)) == (1))); + assert!((((*__decomp_3).x) == (1))); + assert!((((*__decomp_3).y) == (2))); + let __decomp_4: *const Counted = &s; + assert!(((*std::cell::LazyCell::force_mut(&mut *&raw mut copies_0)) == (1))); + assert!((((*__decomp_4).x) == (1))); + let mut __decomp_5: Counted = (unsafe { make_counted_1() }); + assert!(((*std::cell::LazyCell::force_mut(&mut *&raw mut copies_0)) == (1))); + assert!(((__decomp_5.x) == (5))); + assert!(((__decomp_5.y) == (6))); + return 0; +} +pub unsafe fn __cpp2rust_init_globals() { + std::cell::LazyCell::force(&*&raw const copies_0); +} diff --git a/tests/unit/out/unsafe/structured_binding_element_ctor.rs b/tests/unit/out/unsafe/structured_binding_element_ctor.rs new file mode 100644 index 000000000..db6370f5b --- /dev/null +++ b/tests/unit/out/unsafe/structured_binding_element_ctor.rs @@ -0,0 +1,112 @@ +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 static mut copies_0: std::cell::LazyCell = std::cell::LazyCell::new(|| unsafe { 0 }); +pub static mut moves_1: std::cell::LazyCell = std::cell::LazyCell::new(|| unsafe { 0 }); +#[repr(C)] +#[derive(VaArg, FnPtrArg, MoveCtorUnsafe, Default)] +pub struct Elem { + pub v: i32, +} +impl Elem { + pub unsafe fn new(mut v: i32) -> Self { + let mut this = Self { v: v }; + this + } + pub unsafe fn copy_from(other: *const Elem) -> Self { + let mut this = Self { + v: (((*other).v) + (100)), + }; + (*std::cell::LazyCell::force_mut(&mut *&raw mut copies_0)).prefix_inc(); + this + } + pub unsafe fn move_from(other: *mut Elem) -> Self { + let mut this = Self { + v: (((*other).v) + (1000)), + }; + (*other).v = -1_i32; + (*std::cell::LazyCell::force_mut(&mut *&raw mut moves_1)).prefix_inc(); + this + } +} +impl Clone for Elem { + fn clone(&self) -> Self { + unsafe { Elem::copy_from(self as *const Elem) } + } +} +#[repr(C)] +#[derive(Clone, VaArg, FnPtrArg, MoveCtorUnsafe, Default)] +pub struct Two { + pub a: Elem, + pub b: Elem, +} +impl Two { + pub unsafe fn move_from(_a0: *mut Two) -> Self { + let mut this = Self { + a: Elem::move_from({ &mut (*_a0).a }), + b: Elem::move_from({ &mut (*_a0).b }), + }; + this + } +} +pub unsafe fn make_two_2() -> Two { + return Two { + a: Elem::new({ 1 }), + b: Elem::new({ 2 }), + }; +} +pub fn main() { + unsafe { + __cpp2rust_init_globals(); + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut t: Two = Two { + a: Elem::new({ 1 }), + b: Elem::new({ 2 }), + }; + let mut base_copies: i32 = (*std::cell::LazyCell::force_mut(&mut *&raw mut copies_0)); + let mut base_moves: i32 = (*std::cell::LazyCell::force_mut(&mut *&raw mut moves_1)); + let mut __decomp_3: Two = t.clone(); + assert!(((*std::cell::LazyCell::force_mut(&mut *&raw mut copies_0)) == ((base_copies) + (2)))); + assert!(((*std::cell::LazyCell::force_mut(&mut *&raw mut moves_1)) == (base_moves))); + assert!(((__decomp_3.a.v) == (101))); + assert!(((__decomp_3.b.v) == (102))); + let __decomp_4: *mut Two = &mut t; + assert!(((*std::cell::LazyCell::force_mut(&mut *&raw mut copies_0)) == ((base_copies) + (2)))); + assert!((((*__decomp_4).a.v) == (1))); + (*__decomp_4).a.v = 50; + assert!(((t.a.v) == (50))); + let mut __decomp_5: Two = Two::move_from({ &mut t }); + assert!(((*std::cell::LazyCell::force_mut(&mut *&raw mut moves_1)) == ((base_moves) + (2)))); + assert!(((__decomp_5.a.v) == (1050))); + assert!(((__decomp_5.b.v) == (1002))); + assert!(((t.a.v) == (-1_i32))); + let mut before_copies: i32 = (*std::cell::LazyCell::force_mut(&mut *&raw mut copies_0)); + let mut before_moves: i32 = (*std::cell::LazyCell::force_mut(&mut *&raw mut moves_1)); + let mut __decomp_6: Two = (unsafe { make_two_2() }); + assert!(((*std::cell::LazyCell::force_mut(&mut *&raw mut copies_0)) == (before_copies))); + assert!(((*std::cell::LazyCell::force_mut(&mut *&raw mut moves_1)) == (before_moves))); + assert!(((__decomp_6.a.v) == (1))); + let mut p: (Elem, Elem) = (Elem::new({ 7 }).into(), Elem::new({ 8 }).into()); + before_copies = (*std::cell::LazyCell::force_mut(&mut *&raw mut copies_0)); + let mut __decomp_7: (Elem, Elem) = p.clone(); + let x: *mut Elem = &mut __decomp_7.0; + let y: *mut Elem = &mut __decomp_7.1; + assert!( + ((*std::cell::LazyCell::force_mut(&mut *&raw mut copies_0)) == ((before_copies) + (2))) + ); + assert!((((*x).v) == ((p.0.v) + (100)))); + assert!((((*y).v) == ((p.1.v) + (100)))); + return 0; +} +pub unsafe fn __cpp2rust_init_globals() { + std::cell::LazyCell::force(&*&raw const copies_0); + std::cell::LazyCell::force(&*&raw const moves_1); +} diff --git a/tests/unit/out/unsafe/structured_binding_move_ctor.rs b/tests/unit/out/unsafe/structured_binding_move_ctor.rs new file mode 100644 index 000000000..21baab73d --- /dev/null +++ b/tests/unit/out/unsafe/structured_binding_move_ctor.rs @@ -0,0 +1,91 @@ +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 static mut copies_0: std::cell::LazyCell = std::cell::LazyCell::new(|| unsafe { 0 }); +pub static mut moves_1: std::cell::LazyCell = std::cell::LazyCell::new(|| unsafe { 0 }); +#[repr(C)] +#[derive(VaArg, FnPtrArg, MoveCtorUnsafe, Default)] +pub struct Movable { + pub x: i32, + pub y: i32, +} +impl Movable { + pub unsafe fn new(mut x: i32, mut y: i32) -> Self { + let mut this = Self { x: x, y: y }; + this + } + pub unsafe fn copy_from(other: *const Movable) -> Self { + let mut this = Self { + x: (*other).x, + y: (*other).y, + }; + (*std::cell::LazyCell::force_mut(&mut *&raw mut copies_0)).prefix_inc(); + this + } + pub unsafe fn move_from(other: *mut Movable) -> Self { + let mut this = Self { + x: (*other).x, + y: (*other).y, + }; + (*other).x = 0; + (*other).y = 0; + (*std::cell::LazyCell::force_mut(&mut *&raw mut moves_1)).prefix_inc(); + this + } +} +impl Clone for Movable { + fn clone(&self) -> Self { + unsafe { Movable::copy_from(self as *const Movable) } + } +} +#[repr(C)] +#[derive(Clone, VaArg, FnPtrArg, Default)] +pub struct Holder { + pub xs: Vec, + pub ys: Vec, +} +impl Holder { + pub unsafe fn extract(&mut self) -> Holder { + return Holder { + xs: std::mem::take(&mut self.xs), + ys: std::mem::take(&mut self.ys), + }; + } +} +pub fn main() { + unsafe { + __cpp2rust_init_globals(); + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut m: Movable = Movable::new({ 3 }, { 4 }); + let mut __decomp_2: Movable = Movable::move_from({ &mut m }); + assert!(((*std::cell::LazyCell::force_mut(&mut *&raw mut moves_1)) == (1))); + assert!(((*std::cell::LazyCell::force_mut(&mut *&raw mut copies_0)) == (0))); + assert!(((__decomp_2.x) == (3))); + assert!(((__decomp_2.y) == (4))); + assert!(((m.x) == (0))); + assert!(((m.y) == (0))); + let mut h: Holder = Holder { + xs: vec![1, 2, 3], + ys: vec![4, 5], + }; + let mut __decomp_3: Holder = (unsafe { Holder::extract(&mut h) }); + assert!(((__decomp_3.xs.len()) == (3_usize))); + assert!(((__decomp_3.ys.len()) == (2_usize))); + assert!(((__decomp_3.xs[(2_usize)]) == (3))); + assert!(((__decomp_3.ys[(0_usize)]) == (4))); + assert!(h.xs.is_empty()); + assert!(h.ys.is_empty()); + return 0; +} +pub unsafe fn __cpp2rust_init_globals() { + std::cell::LazyCell::force(&*&raw const copies_0); + std::cell::LazyCell::force(&*&raw const moves_1); +} diff --git a/tests/unit/out/unsafe/structured_binding_pair.rs b/tests/unit/out/unsafe/structured_binding_pair.rs new file mode 100644 index 000000000..0bf6e072c --- /dev/null +++ b/tests/unit/out/unsafe/structured_binding_pair.rs @@ -0,0 +1,41 @@ +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 unsafe fn make_std_pair_0(mut x: i32) -> (i32, bool) { + return (x.into(), ((x) > (0)).into()); +} +pub fn main() { + unsafe { + __cpp2rust_init_globals(); + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut __decomp_1: (i32, bool) = (unsafe { make_std_pair_0(5) }); + let value: *mut i32 = &mut __decomp_1.0; + let positive: *mut bool = &mut __decomp_1.1; + assert!(((*value) == (5))); + assert!(((*positive) as bool)); + let mut p: (i32, i32) = (1.into(), 2.into()); + let mut __decomp_2: (i32, i32) = p.clone(); + let a: *mut i32 = &mut __decomp_2.0; + let b: *mut i32 = &mut __decomp_2.1; + (*a) = 10; + assert!(((*a) == (10))); + assert!(((*b) == (2))); + assert!(((p.0) == (1))); + let __decomp_3: *mut (i32, i32) = &mut p; + let x: *mut i32 = &mut (*__decomp_3).0; + let y: *mut i32 = &mut (*__decomp_3).1; + (*x) = 3; + (*y) += 4; + assert!(((p.0) == (3))); + assert!(((p.1) == (6))); + return 0; +} +pub unsafe fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/unsafe/structured_binding_range_for.rs b/tests/unit/out/unsafe/structured_binding_range_for.rs new file mode 100644 index 000000000..b9de2db73 --- /dev/null +++ b/tests/unit/out/unsafe/structured_binding_range_for.rs @@ -0,0 +1,57 @@ +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, VaArg, FnPtrArg, Default)] +pub struct Pair { + pub first: i32, + pub second: i32, +} +pub fn main() { + unsafe { + __cpp2rust_init_globals(); + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut arr: [Pair; 3] = [ + Pair { + first: 1, + second: 2, + }, + Pair { + first: 3, + second: 4, + }, + Pair { + first: 5, + second: 6, + }, + ]; + 'loop_: for __decomp_0 in 0..(arr.len()) { + let mut __decomp_0 = arr.as_mut_ptr().add(__decomp_0); + (*__decomp_0).first += (*__decomp_0).second; + } + assert!(((arr[(0) as usize].first) == (3))); + assert!(((arr[(2) as usize].first) == (11))); + 'loop_: for __decomp_1 in 0..(arr.len()) { + let mut __decomp_1 = arr[__decomp_1].clone(); + __decomp_1.first = 0; + __decomp_1.second = 0; + } + assert!(((arr[(1) as usize].first) == (7))); + assert!(((arr[(1) as usize].second) == (4))); + let mut sum: i32 = 0; + 'loop_: for __decomp_2 in 0..(arr.len()) { + let mut __decomp_2 = arr.as_ptr().add(__decomp_2); + sum += (((*__decomp_2).first) * ((*__decomp_2).second)); + } + assert!(((sum) == ((((3) * (2)) + ((7) * (4))) + ((11) * (6))))); + return 0; +} +pub unsafe fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/unsafe/structured_binding_ref.rs b/tests/unit/out/unsafe/structured_binding_ref.rs new file mode 100644 index 000000000..d4a1d567a --- /dev/null +++ b/tests/unit/out/unsafe/structured_binding_ref.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, VaArg, FnPtrArg, Default)] +pub struct Triple { + pub a: i32, + pub b: bool, + pub c: i32, +} +pub unsafe fn sum_0(t: *const Triple) -> i32 { + let __decomp_1: *const Triple = t; + return ((((*__decomp_1).a) + (if (*__decomp_1).b { 1 } else { 0 })) + ((*__decomp_1).c)); +} +pub fn main() { + unsafe { + __cpp2rust_init_globals(); + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut t: Triple = Triple { + a: 10, + b: false, + c: 20, + }; + let __decomp_2: *mut Triple = &mut t; + (*__decomp_2).a = 11; + (*__decomp_2).b = true; + (*__decomp_2).c += 1; + assert!(((t.a) == (11))); + assert!(t.b); + assert!(((t.c) == (21))); + t.a = 12; + assert!((((*__decomp_2).a) == (12))); + let __decomp_3: *const Triple = &t; + t.c = 30; + assert!((((*__decomp_3).a) == (12))); + assert!((*__decomp_3).b); + assert!((((*__decomp_3).c) == (30))); + assert!(((unsafe { sum_0(&t,) }) == (43))); + return 0; +} +pub unsafe fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/unsafe/structured_binding_trivial.rs b/tests/unit/out/unsafe/structured_binding_trivial.rs new file mode 100644 index 000000000..83de1cec1 --- /dev/null +++ b/tests/unit/out/unsafe/structured_binding_trivial.rs @@ -0,0 +1,41 @@ +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, VaArg, FnPtrArg, Default)] +pub struct Pair { + pub first: i32, + pub second: i32, +} +pub fn main() { + unsafe { + __cpp2rust_init_globals(); + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut __decomp_0: Pair = Pair { + first: 1, + second: 2, + }; + assert!(((__decomp_0.first) == (1))); + assert!(((__decomp_0.second) == (2))); + let mut p: Pair = Pair { + first: 10, + second: 20, + }; + let mut __decomp_1: Pair = p; + __decomp_1.first = 11; + __decomp_1.second += 1; + assert!(((__decomp_1.first) == (11))); + assert!(((__decomp_1.second) == (21))); + assert!(((p.first) == (10))); + assert!(((p.second) == (20))); + return 0; +} +pub unsafe fn __cpp2rust_init_globals() {} diff --git a/tests/unit/structured_binding_array.cpp b/tests/unit/structured_binding_array.cpp new file mode 100644 index 000000000..b7a6fc1b6 --- /dev/null +++ b/tests/unit/structured_binding_array.cpp @@ -0,0 +1,20 @@ +// ADDITIONAL_COMPILE_FLAGS: -std=c++17 +#include + +int main() { + int arr[3] = {1, 2, 3}; + + auto [a, b, c] = arr; + a = 10; + assert(a == 10); + assert(b == 2); + assert(c == 3); + assert(arr[0] == 1); + + auto &[x, y, z] = arr; + x = 7; + z += y; + assert(arr[0] == 7); + assert(arr[2] == 5); + return 0; +} diff --git a/tests/unit/structured_binding_copy_ctor.cpp b/tests/unit/structured_binding_copy_ctor.cpp new file mode 100644 index 000000000..0caf645bb --- /dev/null +++ b/tests/unit/structured_binding_copy_ctor.cpp @@ -0,0 +1,38 @@ +// ADDITIONAL_COMPILE_FLAGS: -std=c++17 +#include + +static int copies = 0; + +struct Counted { + int x; + int y; + + Counted(int x, int y) : x(x), y(y) {} + Counted(const Counted &other) : x(other.x * 2), y(other.y * 2) { ++copies; } +}; + +static Counted make_counted() { return Counted(5, 6); } + +int main() { + Counted s(1, 2); + + auto [a, b] = s; + assert(copies == 1); + assert(a == 2); + assert(b == 4); + + auto &[ra, rb] = s; + assert(copies == 1); + assert(ra == 1); + assert(rb == 2); + + const auto &[ca, cb] = s; + assert(copies == 1); + assert(ca == 1); + + auto [pa, pb] = make_counted(); + assert(copies == 1); + assert(pa == 5); + assert(pb == 6); + return 0; +} diff --git a/tests/unit/structured_binding_element_ctor.cpp b/tests/unit/structured_binding_element_ctor.cpp new file mode 100644 index 000000000..c55d6c223 --- /dev/null +++ b/tests/unit/structured_binding_element_ctor.cpp @@ -0,0 +1,63 @@ +// ADDITIONAL_COMPILE_FLAGS: -std=c++17 +#include +#include + +static int copies = 0; +static int moves = 0; + +struct Elem { + int v; + + Elem(int v) : v(v) {} + Elem(const Elem &other) : v(other.v + 100) { ++copies; } + Elem(Elem &&other) : v(other.v + 1000) { + other.v = -1; + ++moves; + } +}; + +struct Two { + Elem a; + Elem b; +}; + +static Two make_two() { return Two{Elem(1), Elem(2)}; } + +int main() { + Two t{Elem(1), Elem(2)}; + int base_copies = copies; + int base_moves = moves; + + auto [a, b] = t; + assert(copies == base_copies + 2); + assert(moves == base_moves); + assert(a.v == 101); + assert(b.v == 102); + + auto &[ra, rb] = t; + assert(copies == base_copies + 2); + assert(ra.v == 1); + ra.v = 50; + assert(t.a.v == 50); + + auto [ma, mb] = std::move(t); + assert(moves == base_moves + 2); + assert(ma.v == 1050); + assert(mb.v == 1002); + assert(t.a.v == -1); + + int before_copies = copies; + int before_moves = moves; + auto [pa, pb] = make_two(); + assert(copies == before_copies); + assert(moves == before_moves); + assert(pa.v == 1); + + std::pair p{Elem(7), Elem(8)}; + before_copies = copies; + auto [x, y] = p; + assert(copies == before_copies + 2); + assert(x.v == p.first.v + 100); + assert(y.v == p.second.v + 100); + return 0; +} diff --git a/tests/unit/structured_binding_move_ctor.cpp b/tests/unit/structured_binding_move_ctor.cpp new file mode 100644 index 000000000..04bdf3694 --- /dev/null +++ b/tests/unit/structured_binding_move_ctor.cpp @@ -0,0 +1,48 @@ +// ADDITIONAL_COMPILE_FLAGS: -std=c++17 +#include +#include +#include + +static int copies = 0; +static int moves = 0; + +struct Movable { + int x; + int y; + + Movable(int x, int y) : x(x), y(y) {} + Movable(const Movable &other) : x(other.x), y(other.y) { ++copies; } + Movable(Movable &&other) : x(other.x), y(other.y) { + other.x = 0; + other.y = 0; + ++moves; + } +}; + +struct Holder { + std::vector xs; + std::vector ys; + + Holder extract() && { return {std::move(xs), std::move(ys)}; } +}; + +int main() { + Movable m(3, 4); + auto [a, b] = std::move(m); + assert(moves == 1); + assert(copies == 0); + assert(a == 3); + assert(b == 4); + assert(m.x == 0); + assert(m.y == 0); + + Holder h{{1, 2, 3}, {4, 5}}; + auto [ks, vs] = std::move(h).extract(); + assert(ks.size() == 3); + assert(vs.size() == 2); + assert(ks[2] == 3); + assert(vs[0] == 4); + assert(h.xs.empty()); + assert(h.ys.empty()); + return 0; +} diff --git a/tests/unit/structured_binding_pair.cpp b/tests/unit/structured_binding_pair.cpp new file mode 100644 index 000000000..08f6dc0e5 --- /dev/null +++ b/tests/unit/structured_binding_pair.cpp @@ -0,0 +1,25 @@ +// ADDITIONAL_COMPILE_FLAGS: -std=c++17 +#include +#include + +static std::pair make_std_pair(int x) { return {x, x > 0}; } + +int main() { + auto [value, positive] = make_std_pair(5); + assert(value == 5); + assert(positive); + + std::pair p{1, 2}; + auto [a, b] = p; + a = 10; + assert(a == 10); + assert(b == 2); + assert(p.first == 1); + + auto &[x, y] = p; + x = 3; + y += 4; + assert(p.first == 3); + assert(p.second == 6); + return 0; +} diff --git a/tests/unit/structured_binding_range_for.cpp b/tests/unit/structured_binding_range_for.cpp new file mode 100644 index 000000000..904650583 --- /dev/null +++ b/tests/unit/structured_binding_range_for.cpp @@ -0,0 +1,31 @@ +// ADDITIONAL_COMPILE_FLAGS: -std=c++17 +#include + +struct Pair { + int first; + int second; +}; + +int main() { + Pair arr[3] = {{1, 2}, {3, 4}, {5, 6}}; + + for (auto &[x, y] : arr) { + x += y; + } + assert(arr[0].first == 3); + assert(arr[2].first == 11); + + for (auto [x, y] : arr) { + x = 0; + y = 0; + } + assert(arr[1].first == 7); + assert(arr[1].second == 4); + + int sum = 0; + for (const auto &[x, y] : arr) { + sum += x * y; + } + assert(sum == 3 * 2 + 7 * 4 + 11 * 6); + return 0; +} diff --git a/tests/unit/structured_binding_ref.cpp b/tests/unit/structured_binding_ref.cpp new file mode 100644 index 000000000..1d2eaf004 --- /dev/null +++ b/tests/unit/structured_binding_ref.cpp @@ -0,0 +1,36 @@ +// ADDITIONAL_COMPILE_FLAGS: -std=c++17 +#include + +struct Triple { + int a; + bool b; + int c; +}; + +static int sum(const Triple &t) { + const auto &[x, y, z] = t; + return x + (y ? 1 : 0) + z; +} + +int main() { + Triple t{10, false, 20}; + auto &[pos, ins, nod] = t; + pos = 11; + ins = true; + nod += 1; + assert(t.a == 11); + assert(t.b); + assert(t.c == 21); + + t.a = 12; + assert(pos == 12); + + const auto &[ca, cb, cc] = t; + t.c = 30; + assert(ca == 12); + assert(cb); + assert(cc == 30); + + assert(sum(t) == 43); + return 0; +} diff --git a/tests/unit/structured_binding_trivial.cpp b/tests/unit/structured_binding_trivial.cpp new file mode 100644 index 000000000..823b0f44b --- /dev/null +++ b/tests/unit/structured_binding_trivial.cpp @@ -0,0 +1,23 @@ +// ADDITIONAL_COMPILE_FLAGS: -std=c++17 +#include + +struct Pair { + int first; + int second; +}; + +int main() { + auto [in, fun] = Pair{1, 2}; + assert(in == 1); + assert(fun == 2); + + Pair p{10, 20}; + auto [a, b] = p; + a = 11; + b += 1; + assert(a == 11); + assert(b == 21); + assert(p.first == 10); + assert(p.second == 20); + return 0; +}