diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 09e9d526..98abbbaa 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -753,6 +753,11 @@ void Converter::EmitRustStructOrUnion(clang::RecordDecl *decl) { } } + if (decl->isUnion()) { + EmitRustUnion(decl); + return; + } + // Derived traits if (EmitsReprCForRecords()) { StrCat("#[repr(C)]"); @@ -770,8 +775,7 @@ void Converter::EmitRustStructOrUnion(clang::RecordDecl *decl) { auto access = clang::dyn_cast(decl) ? AccessSpecifierAsString(decl->getAccess()) : keyword::kPub; - StrCat(access, decl->isUnion() ? keyword::kUnion : keyword::kStruct, - GetRecordName(decl)); + StrCat(access, keyword::kStruct, GetRecordName(decl)); { PushBrace brace(*this); for (auto *field : decl->fields()) { @@ -817,6 +821,29 @@ void Converter::EmitRustStructOrUnion(clang::RecordDecl *decl) { AddByteReprTrait(decl); } +void Converter::EmitRustUnion(clang::RecordDecl *decl) { + StrCat("#[repr(C)]"); + auto attrs = GetStructAttributes(decl); + Mapper::SetDerives(ctx_.getCanonicalTagType(decl), + std::vector(attrs.begin(), attrs.end())); + StrCat("#[derive("); + for (auto *attr : attrs) { + StrCat(attr, ','); + } + StrCat(")]"); + + StrCat(keyword::kPub, keyword::kUnion, GetRecordName(decl)); + { + PushBrace brace(*this); + for (auto *field : decl->fields()) { + VisitFieldDecl(field); + } + } + + AddDefaultTrait(decl); + AddByteReprTrait(decl); +} + bool Converter::VisitCXXRecordDecl(clang::CXXRecordDecl *decl) { if (clang::isa(decl)) { materializeTemplateSpecialization(decl); @@ -3878,7 +3905,7 @@ void Converter::AddOrdTrait(const clang::CXXRecordDecl *decl) { ConvertOrdAndPartialOrdTraits(decl, methods[0]); } -void Converter::AddCloneTrait(const clang::CXXRecordDecl *decl) {} +void Converter::AddCloneTrait(const clang::RecordDecl *decl) {} void Converter::AddDropTrait(const clang::CXXRecordDecl *decl) {} diff --git a/cpp2rust/converter/converter.h b/cpp2rust/converter/converter.h index 735b118e..9c3fc5f1 100644 --- a/cpp2rust/converter/converter.h +++ b/cpp2rust/converter/converter.h @@ -112,6 +112,8 @@ class Converter : public clang::RecursiveASTVisitor { virtual void EmitRustStructOrUnion(clang::RecordDecl *decl); + virtual void EmitRustUnion(clang::RecordDecl *decl); + virtual bool EmitsReprCForRecords() const { return true; } virtual bool VisitCXXMethodDecl(clang::CXXMethodDecl *decl); @@ -527,7 +529,7 @@ class Converter : public clang::RecursiveASTVisitor { std::string_view second_return, std::string_view record_name); - virtual void AddCloneTrait(const clang::CXXRecordDecl *decl); + virtual void AddCloneTrait(const clang::RecordDecl *decl); virtual void AddDropTrait(const clang::CXXRecordDecl *decl); diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index 17b4f149..eb89d496 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -441,17 +441,28 @@ void ConverterRefCount::ConvertOrdAndPartialOrdTraits( second_return, GetRecordName(decl)); } -void ConverterRefCount::AddCloneTrait(const clang::CXXRecordDecl *decl) { - if (decl->defaultedCopyConstructorIsDeleted()) { +void ConverterRefCount::AddCloneTrait(const clang::RecordDecl *decl) { + auto record_name = GetRecordName(decl); + + if (decl->isUnion()) { + StrCat("impl Clone for", record_name); + PushBrace impl_brace(*this); + StrCat("fn clone(&self) -> Self"); + PushBrace fn_brace(*this); + StrCat(record_name, + "{ __bytes: Rc::new(RefCell::new(self.__bytes.borrow().clone())) }"); return; } - auto record_name = GetRecordName(decl); + auto *cxx = clang::dyn_cast(decl); + if (!cxx || cxx->defaultedCopyConstructorIsDeleted()) { + return; + } StrCat(keyword::kImpl, "Clone for", record_name, '{'); StrCat("fn clone(&self) -> Self {"); - for (auto ctor : decl->ctors()) { + for (auto ctor : cxx->ctors()) { if (ctor->isCopyConstructor()) { PushConversionKind push(*this, ConversionKind::FullRefCount); ConvertCXXConstructorBody(ctor); @@ -469,6 +480,39 @@ void ConverterRefCount::AddDefaultTrait(const clang::RecordDecl *decl) { } void ConverterRefCount::AddDefaultTraitForUnion(const clang::RecordDecl *decl) { + auto name = GetRecordName(decl); + StrCat("impl Default for", name); + PushBrace impl_brace(*this); + StrCat("fn default() -> Self"); + PushBrace fn_brace(*this); + StrCat(std::format( + "{} {{ __bytes: Rc::new(RefCell::new(Box::from([0u8; {}]))) }}", name, + ctx_.getASTRecordLayout(decl).getSize().getQuantity())); +} + +void ConverterRefCount::EmitRustUnion(clang::RecordDecl *decl) { + auto name = GetRecordName(decl); + + auto attrs = GetStructAttributes(decl); + Mapper::SetDerives(ctx_.getCanonicalTagType(decl), + std::vector(attrs.begin(), attrs.end())); + + StrCat(std::format("pub struct {} {{ __bytes: Value> }}", name)); + + StrCat("impl", name); + { + PushBrace impl_brace(*this); + for (auto *field : decl->fields()) { + StrCat(std::format( + "pub fn {}(&self) -> Ptr<{}> {{ (self.__bytes.as_pointer() " + "as Ptr).reinterpret_cast() }}", + GetNamedDeclAsString(field), Mapper::Map(field->getType()))); + } + } + + AddCloneTrait(decl); + AddDefaultTrait(decl); + AddByteReprTrait(decl); } void ConverterRefCount::AddDropTrait(const clang::CXXRecordDecl *decl) { @@ -1441,6 +1485,28 @@ bool ConverterRefCount::VisitInitListExpr(clang::InitListExpr *expr) { return false; } +void ConverterRefCount::ConvertUnionMemberAccessor(clang::MemberExpr *expr) { + std::string str; + { + Buffer buf(*this); + PushExprKind push(*this, isLValue() ? ExprKind::LValue : ExprKind::RValue); + Converter::ConvertMemberExpr(expr); + str = std::move(buf).str(); + } + str += "()"; + + if (isAddrOf()) { + StrCat(str); + computed_expr_type_ = ComputedExprType::Pointer; + return; + } + if (isLValue()) { + pending_deref_.set(str); + return; + } + StrCat(DerefPtrExpr(str, expr->getMemberDecl()->getType())); +} + bool ConverterRefCount::VisitMemberExpr(clang::MemberExpr *expr) { auto *member = expr->getMemberDecl(); bool known = Mapper::Contains(expr); @@ -1460,6 +1526,13 @@ bool ConverterRefCount::VisitMemberExpr(clang::MemberExpr *expr) { return false; } + if (auto *parent = + clang::dyn_cast(member->getDeclContext()); + parent && parent->isUnion() && clang::isa(member)) { + ConvertUnionMemberAccessor(expr); + return false; + } + std::string str; if (known) { str = GetMappedAsString(expr); @@ -1798,6 +1871,10 @@ std::vector ConverterRefCount::GetStructAttributes(const clang::RecordDecl *decl) { std::vector attrs; + if (decl->isUnion()) { + return attrs; + } + if (RecordDerivesDefault(decl)) { attrs.emplace_back("Default"); } diff --git a/cpp2rust/converter/models/converter_refcount.h b/cpp2rust/converter/models/converter_refcount.h index 122a930d..1a3634a3 100644 --- a/cpp2rust/converter/models/converter_refcount.h +++ b/cpp2rust/converter/models/converter_refcount.h @@ -28,12 +28,14 @@ class ConverterRefCount final : public Converter { bool VisitCXXRecordDecl(clang::CXXRecordDecl *decl) override; + void EmitRustUnion(clang::RecordDecl *decl) override; + bool EmitsReprCForRecords() const override { return false; } void ConvertOrdAndPartialOrdTraits(const clang::CXXRecordDecl *decl, const clang::FunctionDecl *op) override; - void AddCloneTrait(const clang::CXXRecordDecl *decl) override; + void AddCloneTrait(const clang::RecordDecl *decl) override; void AddDropTrait(const clang::CXXRecordDecl *decl) override; @@ -103,6 +105,8 @@ class ConverterRefCount final : public Converter { bool VisitMemberExpr(clang::MemberExpr *expr) override; + void ConvertUnionMemberAccessor(clang::MemberExpr *expr); + bool VisitCXXNewExpr(clang::CXXNewExpr *expr) override; bool VisitCXXDeleteExpr(clang::CXXDeleteExpr *expr) override; diff --git a/tests/unit/out/refcount/tag_vs_identifier_collision.rs b/tests/unit/out/refcount/tag_vs_identifier_collision.rs new file mode 100644 index 00000000..eccceda4 --- /dev/null +++ b/tests/unit/out/refcount/tag_vs_identifier_collision.rs @@ -0,0 +1,221 @@ +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, Copy, PartialEq, Debug, Default)] +enum widget_enum { + #[default] + MODE_IDLE = 0, + MODE_ACTIVE = 1, + MODE_DONE = 2, +} +impl From for widget_enum { + fn from(n: i32) -> widget_enum { + match n { + 0 => widget_enum::MODE_IDLE, + 1 => widget_enum::MODE_ACTIVE, + 2 => widget_enum::MODE_DONE, + _ => panic!("invalid widget_enum value: {}", n), + } + } +} +libcc2rs::impl_enum_inc_dec!(widget_enum); +impl ByteRepr for widget_enum { + fn to_bytes(&self, buf: &mut [u8]) { + (*self as i32).to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { + ::from(i32::from_bytes(buf)) + } +} +#[derive(Default)] +pub struct widget { + pub id: Value, + pub mode: Value, +} +impl ByteRepr for widget { + fn to_bytes(&self, buf: &mut [u8]) { + (*self.id.borrow()).to_bytes(&mut buf[0..4]); + (*self.mode.borrow()).to_bytes(&mut buf[4..8]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + id: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), + mode: Rc::new(RefCell::new(::from_bytes(&buf[4..8]))), + } + } +} +#[derive(Default)] +pub struct point_struct { + pub x: Value, + pub y: Value, +} +impl ByteRepr for point_struct { + fn to_bytes(&self, buf: &mut [u8]) { + (*self.x.borrow()).to_bytes(&mut buf[0..4]); + (*self.y.borrow()).to_bytes(&mut buf[4..8]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + x: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), + y: Rc::new(RefCell::new(::from_bytes(&buf[4..8]))), + } + } +} +pub struct point { + __bytes: Value>, +} +impl point { + pub fn whole(&self) -> Ptr { + (self.__bytes.as_pointer() as Ptr).reinterpret_cast() + } + pub fn half(&self) -> Ptr { + (self.__bytes.as_pointer() as Ptr).reinterpret_cast() + } +} +impl Clone for point { + fn clone(&self) -> Self { + point { + __bytes: Rc::new(RefCell::new(self.__bytes.borrow().clone())), + } + } +} +impl Default for point { + fn default() -> Self { + point { + __bytes: Rc::new(RefCell::new(Box::from([0u8; 4]))), + } + } +} +impl ByteRepr for point {} +pub struct slot_union { + __bytes: Value>, +} +impl slot_union { + pub fn i(&self) -> Ptr { + (self.__bytes.as_pointer() as Ptr).reinterpret_cast() + } + pub fn u(&self) -> Ptr { + (self.__bytes.as_pointer() as Ptr).reinterpret_cast() + } +} +impl Clone for slot_union { + fn clone(&self) -> Self { + slot_union { + __bytes: Rc::new(RefCell::new(self.__bytes.borrow().clone())), + } + } +} +impl Default for slot_union { + fn default() -> Self { + slot_union { + __bytes: Rc::new(RefCell::new(Box::from([0u8; 4]))), + } + } +} +impl ByteRepr for slot_union {} +#[derive(Clone, Copy, PartialEq, Debug, Default)] +enum slot { + #[default] + SLOT_A = 0, + SLOT_B = 1, +} +impl From for slot { + fn from(n: i32) -> slot { + match n { + 0 => slot::SLOT_A, + 1 => slot::SLOT_B, + _ => panic!("invalid slot value: {}", n), + } + } +} +libcc2rs::impl_enum_inc_dec!(slot); +impl ByteRepr for slot { + fn to_bytes(&self, buf: &mut [u8]) { + (*self as i32).to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { + ::from(i32::from_bytes(buf)) + } +} +#[derive(Default)] +pub struct Inner { + pub tag_field: Value, +} +impl ByteRepr for Inner { + fn to_bytes(&self, buf: &mut [u8]) { + (*self.tag_field.borrow()).to_bytes(&mut buf[0..4]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + tag_field: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), + } + } +} +#[derive(Default)] +pub struct Outer { + pub field: Value, +} +impl ByteRepr for Outer {} +#[derive(Default)] +pub struct Inner_struct { + pub typedef_field: Value, +} +impl ByteRepr for Inner_struct { + fn to_bytes(&self, buf: &mut [u8]) { + (*self.typedef_field.borrow()).to_bytes(&mut buf[0..4]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + typedef_field: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), + } + } +} +pub fn is_active_0(w: Ptr) -> i32 { + let w: Value> = Rc::new(RefCell::new(w)); + return (({ + let _lhs = ((*(*(*w.borrow()).upgrade().deref()).mode.borrow()) as u32).clone(); + _lhs == ((widget_enum::MODE_ACTIVE as i32) as u32) + }) as i32); +} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let w: Value = >::default(); + (*(*w.borrow()).id.borrow_mut()) = 7; + (*(*w.borrow()).mode.borrow_mut()) = widget_enum::MODE_ACTIVE; + assert!((({ is_active_0((w.as_pointer()),) }) != 0)); + (*(*w.borrow()).mode.borrow_mut()) = widget_enum::MODE_DONE; + assert!( + (((((*(*w.borrow()).mode.borrow()) as u32) == ((widget_enum::MODE_DONE as i32) as u32)) + as i32) + != 0) + ); + let p: Value = >::default(); + (*(*p.borrow()).x.borrow_mut()) = 3; + (*(*p.borrow()).y.borrow_mut()) = 4; + assert!((((((*(*p.borrow()).x.borrow()) + (*(*p.borrow()).y.borrow())) == 7) as i32) != 0)); + let up: Value = >::default(); + (*up.borrow_mut()).whole().write(5); + assert!((((((*up.borrow()).whole().read()) == 5) as i32) != 0)); + let b: Value = >::default(); + (*b.borrow_mut()).i().write(9); + assert!((((((*b.borrow()).i().read()) == 9) as i32) != 0)); + let e: Value = Rc::new(RefCell::new(slot::SLOT_B)); + assert!((((((*e.borrow()) as u32) == ((slot::SLOT_B as i32) as u32)) as i32) != 0)); + let inner_tag: Value = >::default(); + (*(*inner_tag.borrow()).tag_field.borrow_mut()) = 11; + assert!(((((*(*inner_tag.borrow()).tag_field.borrow()) == 11) as i32) != 0)); + let inner_typedef: Value = >::default(); + (*(*inner_typedef.borrow()).typedef_field.borrow_mut()) = 22; + assert!(((((*(*inner_typedef.borrow()).typedef_field.borrow()) == 22) as i32) != 0)); + let o: Value = >::default(); + (*(*(*o.borrow()).field.borrow()).tag_field.borrow_mut()) = 33; + assert!(((((*(*(*o.borrow()).field.borrow()).tag_field.borrow()) == 33) as i32) != 0)); + return (*(*w.borrow()).id.borrow()); +} diff --git a/tests/unit/out/refcount/union_basic.rs b/tests/unit/out/refcount/union_basic.rs new file mode 100644 index 00000000..9988b7b7 --- /dev/null +++ b/tests/unit/out/refcount/union_basic.rs @@ -0,0 +1,45 @@ +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 basic { + __bytes: Value>, +} +impl basic { + pub fn i(&self) -> Ptr { + (self.__bytes.as_pointer() as Ptr).reinterpret_cast() + } + pub fn f(&self) -> Ptr { + (self.__bytes.as_pointer() as Ptr).reinterpret_cast() + } +} +impl Clone for basic { + fn clone(&self) -> Self { + basic { + __bytes: Rc::new(RefCell::new(self.__bytes.borrow().clone())), + } + } +} +impl Default for basic { + fn default() -> Self { + basic { + __bytes: Rc::new(RefCell::new(Box::from([0u8; 4]))), + } + } +} +impl ByteRepr for basic {} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let u: Value = >::default(); + (*u.borrow_mut()).i().write(42); + assert!((((((*u.borrow()).i().read()) == 42) as i32) != 0)); + (*u.borrow_mut()).f().write(3.140000105E+0); + assert!((((((*u.borrow()).f().read()) == 3.140000105E+0) as i32) != 0)); + return 0; +} diff --git a/tests/unit/out/refcount/union_pointer_pun_writethrough.rs b/tests/unit/out/refcount/union_pointer_pun_writethrough.rs new file mode 100644 index 00000000..12c36840 --- /dev/null +++ b/tests/unit/out/refcount/union_pointer_pun_writethrough.rs @@ -0,0 +1,45 @@ +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() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let x: Value = Rc::new(RefCell::new((-1_i32 as i64))); + pub struct anon_0 { + __bytes: Value>, + } + impl anon_0 { + pub fn as_unsigned(&self) -> Ptr> { + (self.__bytes.as_pointer() as Ptr).reinterpret_cast() + } + pub fn as_signed(&self) -> Ptr> { + (self.__bytes.as_pointer() as Ptr).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 {}; + let pp: Value = >::default(); + (*pp.borrow_mut()).as_signed().write((x.as_pointer())); + ((*pp.borrow()).as_unsigned().read()).write(42_u64); + assert!(((((*x.borrow()) == 42_i64) as i32) != 0)); + return 0; +} diff --git a/tests/unit/out/refcount/union_tagged_struct_arms.rs b/tests/unit/out/refcount/union_tagged_struct_arms.rs new file mode 100644 index 00000000..37417848 --- /dev/null +++ b/tests/unit/out/refcount/union_tagged_struct_arms.rs @@ -0,0 +1,265 @@ +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, Copy, PartialEq, Debug, Default)] +enum Choice_enum { + #[default] + C_LIST = 1, + C_LETTERS = 2, + C_INTEGERS = 3, +} +impl From for Choice_enum { + fn from(n: i32) -> Choice_enum { + match n { + 1 => Choice_enum::C_LIST, + 2 => Choice_enum::C_LETTERS, + 3 => Choice_enum::C_INTEGERS, + _ => panic!("invalid Choice_enum value: {}", n), + } + } +} +libcc2rs::impl_enum_inc_dec!(Choice_enum); +impl ByteRepr for Choice_enum { + fn to_bytes(&self, buf: &mut [u8]) { + (*self as i32).to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { + ::from(i32::from_bytes(buf)) + } +} +#[derive(Default)] +pub struct anon_1 { + pub items: Value>>, + pub count: Value, + pub cursor: Value, +} +impl ByteRepr for anon_1 {} +#[derive(Default)] +pub struct anon_2 { + pub lo: Value, + pub hi: Value, + pub curr: Value, + pub step: Value, +} +impl ByteRepr for anon_2 { + fn to_bytes(&self, buf: &mut [u8]) { + (*self.lo.borrow()).to_bytes(&mut buf[0..4]); + (*self.hi.borrow()).to_bytes(&mut buf[4..8]); + (*self.curr.borrow()).to_bytes(&mut buf[8..12]); + (*self.step.borrow()).to_bytes(&mut buf[12..13]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + lo: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), + hi: Rc::new(RefCell::new(::from_bytes(&buf[4..8]))), + curr: Rc::new(RefCell::new(::from_bytes(&buf[8..12]))), + step: Rc::new(RefCell::new(::from_bytes(&buf[12..13]))), + } + } +} +#[derive(Default)] +pub struct anon_3 { + pub lo: Value, + pub hi: Value, + pub curr: Value, + pub step: Value, + pub width: Value, +} +impl ByteRepr for anon_3 { + fn to_bytes(&self, buf: &mut [u8]) { + (*self.lo.borrow()).to_bytes(&mut buf[0..8]); + (*self.hi.borrow()).to_bytes(&mut buf[8..16]); + (*self.curr.borrow()).to_bytes(&mut buf[16..24]); + (*self.step.borrow()).to_bytes(&mut buf[24..32]); + (*self.width.borrow()).to_bytes(&mut buf[32..36]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + lo: Rc::new(RefCell::new(::from_bytes(&buf[0..8]))), + hi: Rc::new(RefCell::new(::from_bytes(&buf[8..16]))), + curr: Rc::new(RefCell::new(::from_bytes(&buf[16..24]))), + step: Rc::new(RefCell::new(::from_bytes(&buf[24..32]))), + width: Rc::new(RefCell::new(::from_bytes(&buf[32..36]))), + } + } +} +pub struct anon_0 { + __bytes: Value>, +} +impl anon_0 { + pub fn list(&self) -> Ptr { + (self.__bytes.as_pointer() as Ptr).reinterpret_cast() + } + pub fn letters(&self) -> Ptr { + (self.__bytes.as_pointer() as Ptr).reinterpret_cast() + } + pub fn integers(&self) -> Ptr { + (self.__bytes.as_pointer() as Ptr).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; 40]))), + } + } +} +impl ByteRepr for anon_0 {} +#[derive(Default)] +pub struct Branch { + pub choice: Value, + pub index: Value, + pub v: Value, +} +impl ByteRepr for Branch {} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + thread_local!( + static items_4: Value]>> = Rc::new(RefCell::new(Box::new([ + Ptr::from_string_literal(b"a"), + Ptr::from_string_literal(b"b"), + Ptr::from_string_literal(b"c"), + ]))); + ); + let p_list: Value = >::default(); + (*(*p_list.borrow()).choice.borrow_mut()) = Choice_enum::C_LIST; + (*(*p_list.borrow()).index.borrow_mut()) = 0; + (*(*(*(*p_list.borrow()).v.borrow()).list().upgrade().deref()) + .items + .borrow_mut()) = (items_4.with(Value::clone).as_pointer() as Ptr>); + (*(*(*(*p_list.borrow()).v.borrow()).list().upgrade().deref()) + .count + .borrow_mut()) = 3_i64; + (*(*(*(*p_list.borrow()).v.borrow()).list().upgrade().deref()) + .cursor + .borrow_mut()) = 1_i64; + assert!( + ((((*(*(*(*p_list.borrow()).v.borrow()).list().upgrade().deref()) + .count + .borrow()) + == 3_i64) as i32) + != 0) + ); + assert!( + (((((((*(*(*(*p_list.borrow()).v.borrow()).list().upgrade().deref()) + .items + .borrow()) + .offset((1) as isize) + .read()) + .offset((0) as isize) + .read()) as i32) + == ('b' as i32)) as i32) + != 0) + ); + let p_letters: Value = >::default(); + (*(*p_letters.borrow()).choice.borrow_mut()) = Choice_enum::C_LETTERS; + (*(*p_letters.borrow()).index.borrow_mut()) = 1; + (*(*(*(*p_letters.borrow()).v.borrow()) + .letters() + .upgrade() + .deref()) + .lo + .borrow_mut()) = ('a' as i32); + (*(*(*(*p_letters.borrow()).v.borrow()) + .letters() + .upgrade() + .deref()) + .hi + .borrow_mut()) = ('z' as i32); + (*(*(*(*p_letters.borrow()).v.borrow()) + .letters() + .upgrade() + .deref()) + .curr + .borrow_mut()) = ('m' as i32); + (*(*(*(*p_letters.borrow()).v.borrow()) + .letters() + .upgrade() + .deref()) + .step + .borrow_mut()) = 1_u8; + assert!( + (((((*(*(*(*p_letters.borrow()).v.borrow()) + .letters() + .upgrade() + .deref()) + .hi + .borrow()) + - (*(*(*(*p_letters.borrow()).v.borrow()) + .letters() + .upgrade() + .deref()) + .lo + .borrow())) + == 25) as i32) + != 0) + ); + let p_integers: Value = >::default(); + (*(*p_integers.borrow()).choice.borrow_mut()) = Choice_enum::C_INTEGERS; + (*(*p_integers.borrow()).index.borrow_mut()) = 2; + (*(*(*(*p_integers.borrow()).v.borrow()) + .integers() + .upgrade() + .deref()) + .lo + .borrow_mut()) = 1_i64; + (*(*(*(*p_integers.borrow()).v.borrow()) + .integers() + .upgrade() + .deref()) + .hi + .borrow_mut()) = 100_i64; + (*(*(*(*p_integers.borrow()).v.borrow()) + .integers() + .upgrade() + .deref()) + .curr + .borrow_mut()) = 1_i64; + (*(*(*(*p_integers.borrow()).v.borrow()) + .integers() + .upgrade() + .deref()) + .step + .borrow_mut()) = 1_i64; + (*(*(*(*p_integers.borrow()).v.borrow()) + .integers() + .upgrade() + .deref()) + .width + .borrow_mut()) = 3; + assert!( + ((((*(*(*(*p_integers.borrow()).v.borrow()) + .integers() + .upgrade() + .deref()) + .hi + .borrow()) + == 100_i64) as i32) + != 0) + ); + assert!( + ((((*(*(*(*p_integers.borrow()).v.borrow()) + .integers() + .upgrade() + .deref()) + .width + .borrow()) + == 3) as i32) + != 0) + ); + return 0; +} diff --git a/tests/unit/tag_vs_identifier_collision.c b/tests/unit/tag_vs_identifier_collision.c index 79212c64..a51731e9 100644 --- a/tests/unit/tag_vs_identifier_collision.c +++ b/tests/unit/tag_vs_identifier_collision.c @@ -1,4 +1,3 @@ -// no-compile: refcount #include typedef enum { MODE_IDLE, MODE_ACTIVE, MODE_DONE } widget; diff --git a/tests/unit/union_basic.c b/tests/unit/union_basic.c index 86731cc2..5d26a336 100644 --- a/tests/unit/union_basic.c +++ b/tests/unit/union_basic.c @@ -1,4 +1,3 @@ -// no-compile: refcount #include union basic { diff --git a/tests/unit/union_pointer_pun_writethrough.c b/tests/unit/union_pointer_pun_writethrough.c index d29cbc50..44bd842f 100644 --- a/tests/unit/union_pointer_pun_writethrough.c +++ b/tests/unit/union_pointer_pun_writethrough.c @@ -1,4 +1,4 @@ -// no-compile: refcount +// panic: refcount #include int main(void) { diff --git a/tests/unit/union_tagged_struct_arms.c b/tests/unit/union_tagged_struct_arms.c index f5b90e18..ca20e9a6 100644 --- a/tests/unit/union_tagged_struct_arms.c +++ b/tests/unit/union_tagged_struct_arms.c @@ -1,4 +1,4 @@ -// no-compile: refcount +// panic: refcount #include #include