diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 1318c6f1..d3b04bd3 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -1731,6 +1731,16 @@ bool Converter::VisitCXXBoolLiteralExpr(clang::CXXBoolLiteralExpr *expr) { return false; } +void Converter::ConvertIntegerToEnumeralCast(clang::Expr *to, + clang::Expr *from) { + StrCat(GetUnsafeTypeAsString(to->getType()), "::from"); + PushParen paren(*this); + Convert(from); + if (!from->getType()->isSpecificBuiltinType(clang::BuiltinType::Int)) { + StrCat(keyword::kAs, "i32"); + } +} + bool Converter::VisitImplicitCastExpr(clang::ImplicitCastExpr *expr) { auto *sub_expr = expr->getSubExpr(); auto type = expr->getType(); @@ -1846,6 +1856,10 @@ bool Converter::VisitImplicitCastExpr(clang::ImplicitCastExpr *expr) { Convert(sub_expr); break; } + if (type->isEnumeralType() && !sub_expr->getType()->isEnumeralType()) { + ConvertIntegerToEnumeralCast(expr, sub_expr); + break; + } { PushParen outer(*this); if (clang::isa(sub_expr)) { @@ -1890,6 +1904,10 @@ bool Converter::VisitExplicitCastExpr(clang::ExplicitCastExpr *expr) { StrCat(')'); return false; } + if (type->isEnumeralType() && !sub_expr->getType()->isEnumeralType()) { + ConvertIntegerToEnumeralCast(expr, sub_expr); + return false; + } { PushParen paren(*this); Convert(sub_expr); @@ -2200,10 +2218,14 @@ std::string Converter::ConvertDeclRefExpr(clang::DeclRefExpr *expr) { } if (auto enum_constant = clang::dyn_cast(decl)) { - return std::format("{}::{}", - GetRecordName(clang::dyn_cast( - enum_constant->getDeclContext())), - std::string_view(enum_constant->getName())); + auto qualified = std::format("{}::{}", + GetRecordName(clang::dyn_cast( + enum_constant->getDeclContext())), + std::string_view(enum_constant->getName())); + if (!expr->getType()->isEnumeralType()) { + return std::format("({} as i32)", qualified); + } + return qualified; } if (IsGlobalVar(expr)) { @@ -2704,9 +2726,29 @@ bool Converter::VisitEnumDecl(clang::EnumDecl *decl) { std::string_view(init.data(), init.size()))); } StrCat("}"); + + AddFromImpl(decl); return false; } +void Converter::AddFromImpl(clang::EnumDecl *decl) { + auto name = GetRecordName(decl); + StrCat(std::format("impl From for {}", name)); + PushBrace impl(*this); + StrCat(std::format("fn from(n: i32) -> {}", name)); + PushBrace fn(*this); + StrCat("match n"); + PushBrace match(*this); + for (auto e : decl->enumerators()) { + llvm::SmallVector init; + e->getInitVal().toString(init, 10); + StrCat(std::format("{} => {}::{},", + std::string_view(init.data(), init.size()), name, + std::string_view(e->getName()))); + } + StrCat(std::format("_ => panic!(\"invalid {} value: {{}}\", n),", name)); +} + bool Converter::VisitCXXDefaultArgExpr(clang::CXXDefaultArgExpr *expr) { if (expr->getType()->isPointerType()) { StrCat(keyword_default_); diff --git a/cpp2rust/converter/converter.h b/cpp2rust/converter/converter.h index 139b025a..27a78041 100644 --- a/cpp2rust/converter/converter.h +++ b/cpp2rust/converter/converter.h @@ -241,6 +241,8 @@ class Converter : public clang::RecursiveASTVisitor { virtual bool VisitCXXBoolLiteralExpr(clang::CXXBoolLiteralExpr *expr); + void ConvertIntegerToEnumeralCast(clang::Expr *to, clang::Expr *from); + virtual bool VisitImplicitCastExpr(clang::ImplicitCastExpr *expr); virtual bool VisitExplicitCastExpr(clang::ExplicitCastExpr *expr); @@ -293,6 +295,8 @@ class Converter : public clang::RecursiveASTVisitor { virtual bool VisitEnumDecl(clang::EnumDecl *decl); + virtual void AddFromImpl(clang::EnumDecl *decl); + virtual bool VisitCXXDefaultArgExpr(clang::CXXDefaultArgExpr *expr); virtual bool VisitLambdaExpr(clang::LambdaExpr *expr); diff --git a/tests/ub/enum_out_of_range_cast.cpp b/tests/ub/enum_out_of_range_cast.cpp new file mode 100644 index 00000000..1549920c --- /dev/null +++ b/tests/ub/enum_out_of_range_cast.cpp @@ -0,0 +1,9 @@ +// panic + +enum Color { RED, GREEN, BLUE }; + +int main() { + int n = 3; + Color c = (Color)n; + return c == BLUE ? 0 : 1; +} diff --git a/tests/ub/out/refcount/enum_out_of_range_cast.rs b/tests/ub/out/refcount/enum_out_of_range_cast.rs new file mode 100644 index 00000000..2ee58dc0 --- /dev/null +++ b/tests/ub/out/refcount/enum_out_of_range_cast.rs @@ -0,0 +1,37 @@ +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 Color { + #[default] + RED = 0, + GREEN = 1, + BLUE = 2, +} +impl From for Color { + fn from(n: i32) -> Color { + match n { + 0 => Color::RED, + 1 => Color::GREEN, + 2 => Color::BLUE, + _ => panic!("invalid Color value: {}", n), + } + } +} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let n: Value = Rc::new(RefCell::new(3)); + let c: Value = Rc::new(RefCell::new(Color::from((*n.borrow())))); + return if (((*c.borrow()) as i32) == (Color::BLUE as i32)) { + 0 + } else { + 1 + }; +} diff --git a/tests/ub/out/unsafe/enum_out_of_range_cast.rs b/tests/ub/out/unsafe/enum_out_of_range_cast.rs new file mode 100644 index 00000000..8f0a5ac5 --- /dev/null +++ b/tests/ub/out/unsafe/enum_out_of_range_cast.rs @@ -0,0 +1,39 @@ +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; +#[derive(Clone, Copy, PartialEq, Debug, Default)] +enum Color { + #[default] + RED = 0, + GREEN = 1, + BLUE = 2, +} +impl From for Color { + fn from(n: i32) -> Color { + match n { + 0 => Color::RED, + 1 => Color::GREEN, + 2 => Color::BLUE, + _ => panic!("invalid Color value: {}", n), + } + } +} +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut n: i32 = 3; + let mut c: Color = Color::from(n); + return if ((c as i32) == (Color::BLUE as i32)) { + 0 + } else { + 1 + }; +} diff --git a/tests/unit/enum_int_interop.cpp b/tests/unit/enum_int_interop.cpp new file mode 100644 index 00000000..02aeee10 --- /dev/null +++ b/tests/unit/enum_int_interop.cpp @@ -0,0 +1,117 @@ +#include + +enum Color { RED, GREEN, BLUE }; + +enum Option { + OPT_NONE = 0, + OPT_A = 10, + OPT_B = 20, + OPT_C = 30, +}; + +typedef enum { + TAG_ZERO = 0, + TAG_ONE = 1, + TAG_TWO = 2, +} Tag; + +int as_int(Color c) { return c; } + +int classify_option(int option) { + switch (option) { + case OPT_NONE: + return -1; + case OPT_A: + return 1; + case OPT_B: + return 2; + case OPT_C: + return 3; + default: + return 0; + } +} + +Color make_color(int n) { return (Color)n; } + +int main() { + Color c = RED; + + assert(c == RED); + assert(c == 0); + assert(c != 1); + + if (c == GREEN) { + return 1; + } + + switch (c) { + case 0: + break; + case 1: + return 1; + case 2: + return 2; + default: + return 99; + } + + int x = c; + assert(x == 0); + + int y = c + 1; + assert(y == 1); + + c = (Color)2; + assert(c == BLUE); + assert(c == 2); + + c = make_color(1); + assert(c == GREEN); + + Color cmp = (Color)(c + 1); + assert(cmp == BLUE); + + Option o = OPT_A; + assert(o == OPT_A); + assert(o == 10); + + int oi = o; + assert(oi == 10); + + o = (Option)20; + assert(o == OPT_B); + + int rc = classify_option(o); + assert(rc == 2); + + rc = classify_option(20); + assert(rc == 2); + + rc = classify_option(OPT_C); + assert(rc == 3); + + Tag t = TAG_ONE; + assert(t == 1); + assert(t == TAG_ONE); + + int ti = t; + assert(ti == 1); + + t = (Tag)2; + assert(t == TAG_TWO); + + switch (t) { + case TAG_ZERO: + return 90; + case 1: + return 91; + case 2: + break; + } + + int extra = (int)RED + (int)GREEN + (int)BLUE; + assert(extra == 0 + 1 + 2); + + return 0; +} diff --git a/tests/unit/enum_int_interop_c.c b/tests/unit/enum_int_interop_c.c new file mode 100644 index 00000000..ed22035a --- /dev/null +++ b/tests/unit/enum_int_interop_c.c @@ -0,0 +1,117 @@ +#include + +enum Color { RED, GREEN, BLUE }; + +enum Option { + OPT_NONE = 0, + OPT_A = 10, + OPT_B = 20, + OPT_C = 30, +}; + +typedef enum { + TAG_ZERO = 0, + TAG_ONE = 1, + TAG_TWO = 2, +} Tag; + +int as_int(enum Color c) { return c; } + +int classify_option(int option) { + switch (option) { + case OPT_NONE: + return -1; + case OPT_A: + return 1; + case OPT_B: + return 2; + case OPT_C: + return 3; + default: + return 0; + } +} + +enum Color make_color(int n) { return (enum Color)n; } + +int main() { + enum Color c = RED; + + assert(c == RED); + assert(c == 0); + assert(c != 1); + + if (c == GREEN) { + return 1; + } + + switch (c) { + case 0: + break; + case 1: + return 1; + case 2: + return 2; + default: + return 99; + } + + int x = c; + assert(x == 0); + + int y = c + 1; + assert(y == 1); + + c = (enum Color)2; + assert(c == BLUE); + assert(c == 2); + + c = make_color(1); + assert(c == GREEN); + + enum Color cmp = (enum Color)(c + 1); + assert(cmp == BLUE); + + enum Option o = OPT_A; + assert(o == OPT_A); + assert(o == 10); + + int oi = o; + assert(oi == 10); + + o = (enum Option)20; + assert(o == OPT_B); + + int rc = classify_option(o); + assert(rc == 2); + + rc = classify_option(20); + assert(rc == 2); + + rc = classify_option(OPT_C); + assert(rc == 3); + + Tag t = TAG_ONE; + assert(t == 1); + assert(t == TAG_ONE); + + int ti = t; + assert(ti == 1); + + t = (Tag)2; + assert(t == TAG_TWO); + + switch (t) { + case TAG_ZERO: + return 90; + case 1: + return 91; + case 2: + break; + } + + int extra = (int)RED + (int)GREEN + (int)BLUE; + assert(extra == 0 + 1 + 2); + + return 0; +} diff --git a/tests/unit/out/refcount/anonymous_enum.rs b/tests/unit/out/refcount/anonymous_enum.rs index 47dcf325..fd913572 100644 --- a/tests/unit/out/refcount/anonymous_enum.rs +++ b/tests/unit/out/refcount/anonymous_enum.rs @@ -12,12 +12,30 @@ enum anon_enum_3 { FIRST_A = 0, FIRST_B = 1, } +impl From for anon_enum_3 { + fn from(n: i32) -> anon_enum_3 { + match n { + 0 => anon_enum_3::FIRST_A, + 1 => anon_enum_3::FIRST_B, + _ => panic!("invalid anon_enum_3 value: {}", n), + } + } +} #[derive(Clone, Copy, PartialEq, Debug, Default)] enum anon_enum_11 { #[default] SECOND_A = 0, SECOND_B = 1, } +impl From for anon_enum_11 { + fn from(n: i32) -> anon_enum_11 { + match n { + 0 => anon_enum_11::SECOND_A, + 1 => anon_enum_11::SECOND_B, + _ => panic!("invalid anon_enum_11 value: {}", n), + } + } +} #[derive(Default)] pub struct S { pub a: Value, @@ -37,12 +55,30 @@ enum TdEnum { TD_A = 0, TD_B = 1, } +impl From for TdEnum { + fn from(n: i32) -> TdEnum { + match n { + 0 => TdEnum::TD_A, + 1 => TdEnum::TD_B, + _ => panic!("invalid TdEnum value: {}", n), + } + } +} #[derive(Clone, Copy, PartialEq, Debug, Default)] enum anon_enum_24 { #[default] FIELD_A = 0, FIELD_B = 1, } +impl From for anon_enum_24 { + fn from(n: i32) -> anon_enum_24 { + match n { + 0 => anon_enum_24::FIELD_A, + 1 => anon_enum_24::FIELD_B, + _ => panic!("invalid anon_enum_24 value: {}", n), + } + } +} #[derive(Default)] pub struct WithAnonField { pub a: Value, @@ -67,6 +103,15 @@ fn main_0() -> i32 { #[default] THIRD_A = 0, THIRD_B = 1, + } + impl From for anon_enum_31 { + fn from(n: i32) -> anon_enum_31 { + match n { + 0 => anon_enum_31::THIRD_A, + 1 => anon_enum_31::THIRD_B, + _ => panic!("invalid anon_enum_31 value: {}", n), + } + } }; assert!(((anon_enum_3::FIRST_A as i32) != (anon_enum_3::FIRST_B as i32))); assert!(((anon_enum_11::SECOND_A as i32) != (anon_enum_11::SECOND_B as i32))); diff --git a/tests/unit/out/refcount/anonymous_enum_c.rs b/tests/unit/out/refcount/anonymous_enum_c.rs index 0b0c762c..41278782 100644 --- a/tests/unit/out/refcount/anonymous_enum_c.rs +++ b/tests/unit/out/refcount/anonymous_enum_c.rs @@ -12,12 +12,30 @@ enum anon_enum_3 { FIRST_A = 0, FIRST_B = 1, } +impl From for anon_enum_3 { + fn from(n: i32) -> anon_enum_3 { + match n { + 0 => anon_enum_3::FIRST_A, + 1 => anon_enum_3::FIRST_B, + _ => panic!("invalid anon_enum_3 value: {}", n), + } + } +} #[derive(Clone, Copy, PartialEq, Debug, Default)] enum anon_enum_11 { #[default] SECOND_A = 0, SECOND_B = 1, } +impl From for anon_enum_11 { + fn from(n: i32) -> anon_enum_11 { + match n { + 0 => anon_enum_11::SECOND_A, + 1 => anon_enum_11::SECOND_B, + _ => panic!("invalid anon_enum_11 value: {}", n), + } + } +} #[derive(Default)] pub struct S { pub a: Value, @@ -29,12 +47,30 @@ enum TdEnum { TD_A = 0, TD_B = 1, } +impl From for TdEnum { + fn from(n: i32) -> TdEnum { + match n { + 0 => TdEnum::TD_A, + 1 => TdEnum::TD_B, + _ => panic!("invalid TdEnum value: {}", n), + } + } +} #[derive(Clone, Copy, PartialEq, Debug, Default)] enum anon_enum_24 { #[default] FIELD_A = 0, FIELD_B = 1, } +impl From for anon_enum_24 { + fn from(n: i32) -> anon_enum_24 { + match n { + 0 => anon_enum_24::FIELD_A, + 1 => anon_enum_24::FIELD_B, + _ => panic!("invalid anon_enum_24 value: {}", n), + } + } +} #[derive(Default)] pub struct WithAnonField { pub a: Value, @@ -50,18 +86,27 @@ fn main_0() -> i32 { #[default] THIRD_A = 0, THIRD_B = 1, + } + impl From for anon_enum_31 { + fn from(n: i32) -> anon_enum_31 { + match n { + 0 => anon_enum_31::THIRD_A, + 1 => anon_enum_31::THIRD_B, + _ => panic!("invalid anon_enum_31 value: {}", n), + } + } }; - assert!((anon_enum_3::FIRST_A != anon_enum_3::FIRST_B)); - assert!((anon_enum_11::SECOND_A != anon_enum_11::SECOND_B)); - assert!((anon_enum_31::THIRD_A != anon_enum_31::THIRD_B)); - let td: Value = Rc::new(RefCell::new((TdEnum::TD_A as TdEnum))); - assert!((((*td.borrow()) as u32) == (TdEnum::TD_A as u32))); - (*td.borrow_mut()) = (TdEnum::TD_B as TdEnum); - assert!((((*td.borrow()) as u32) == (TdEnum::TD_B as u32))); + assert!(((anon_enum_3::FIRST_A as i32) != (anon_enum_3::FIRST_B as i32))); + assert!(((anon_enum_11::SECOND_A as i32) != (anon_enum_11::SECOND_B as i32))); + assert!(((anon_enum_31::THIRD_A as i32) != (anon_enum_31::THIRD_B as i32))); + let td: Value = Rc::new(RefCell::new(TdEnum::from((TdEnum::TD_A as i32)))); + assert!((((*td.borrow()) as u32) == ((TdEnum::TD_A as i32) as u32))); + (*td.borrow_mut()) = TdEnum::from((TdEnum::TD_B as i32)); + assert!((((*td.borrow()) as u32) == ((TdEnum::TD_B as i32) as u32))); let w: Value = >::default(); - (*(*w.borrow()).field.borrow_mut()) = (anon_enum_24::FIELD_A as anon_enum_24); - assert!((((*(*w.borrow()).field.borrow()) as u32) == (anon_enum_24::FIELD_A as u32))); - (*(*w.borrow()).field.borrow_mut()) = (anon_enum_24::FIELD_B as anon_enum_24); - assert!((((*(*w.borrow()).field.borrow()) as u32) == (anon_enum_24::FIELD_B as u32))); + (*(*w.borrow()).field.borrow_mut()) = anon_enum_24::from((anon_enum_24::FIELD_A as i32)); + assert!((((*(*w.borrow()).field.borrow()) as u32) == ((anon_enum_24::FIELD_A as i32) as u32))); + (*(*w.borrow()).field.borrow_mut()) = anon_enum_24::from((anon_enum_24::FIELD_B as i32)); + assert!((((*(*w.borrow()).field.borrow()) as u32) == ((anon_enum_24::FIELD_B as i32) as u32))); return 0; } diff --git a/tests/unit/out/refcount/c_struct.rs b/tests/unit/out/refcount/c_struct.rs index 2343bb35..2e2499a2 100644 --- a/tests/unit/out/refcount/c_struct.rs +++ b/tests/unit/out/refcount/c_struct.rs @@ -31,6 +31,16 @@ enum Color { GREEN = 1, BLUE = 2, } +impl From for Color { + fn from(n: i32) -> Color { + match n { + 0 => Color::RED, + 1 => Color::GREEN, + 2 => Color::BLUE, + _ => panic!("invalid Color value: {}", n), + } + } +} #[derive(Default)] pub struct Inner { pub a: Value, @@ -85,15 +95,15 @@ fn main_0() -> i32 { a: Rc::new(RefCell::new(5)), b: Rc::new(RefCell::new(6)), })), - color: Rc::new(RefCell::new((Color::GREEN as Color))), + color: Rc::new(RefCell::new(Color::from((Color::GREEN as i32)))), count: Rc::new(RefCell::new(42)), })); assert!(((*(*(*c.borrow()).inner.borrow()).a.borrow()) == 5)); assert!(((*(*(*c.borrow()).inner.borrow()).b.borrow()) == 6)); - assert!((((*(*c.borrow()).color.borrow()) as u32) == (Color::GREEN as u32))); + assert!((((*(*c.borrow()).color.borrow()) as u32) == ((Color::GREEN as i32) as u32))); assert!(((*(*c.borrow()).count.borrow()) == 42)); let c2: Value = >::default(); - (*(*c2.borrow()).color.borrow_mut()) = (Color::BLUE as Color); + (*(*c2.borrow()).color.borrow_mut()) = Color::from((Color::BLUE as i32)); assert!((((*(*c2.borrow()).color.borrow()) as u32) == 2_u32)); return 0; } diff --git a/tests/unit/out/refcount/enum_int_interop.rs b/tests/unit/out/refcount/enum_int_interop.rs new file mode 100644 index 00000000..64e02edf --- /dev/null +++ b/tests/unit/out/refcount/enum_int_interop.rs @@ -0,0 +1,189 @@ +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 Color { + #[default] + RED = 0, + GREEN = 1, + BLUE = 2, +} +impl From for Color { + fn from(n: i32) -> Color { + match n { + 0 => Color::RED, + 1 => Color::GREEN, + 2 => Color::BLUE, + _ => panic!("invalid Color value: {}", n), + } + } +} +#[derive(Clone, Copy, PartialEq, Debug, Default)] +enum Option { + #[default] + OPT_NONE = 0, + OPT_A = 10, + OPT_B = 20, + OPT_C = 30, +} +impl From for Option { + fn from(n: i32) -> Option { + match n { + 0 => Option::OPT_NONE, + 10 => Option::OPT_A, + 20 => Option::OPT_B, + 30 => Option::OPT_C, + _ => panic!("invalid Option value: {}", n), + } + } +} +#[derive(Clone, Copy, PartialEq, Debug, Default)] +enum Tag { + #[default] + TAG_ZERO = 0, + TAG_ONE = 1, + TAG_TWO = 2, +} +impl From for Tag { + fn from(n: i32) -> Tag { + match n { + 0 => Tag::TAG_ZERO, + 1 => Tag::TAG_ONE, + 2 => Tag::TAG_TWO, + _ => panic!("invalid Tag value: {}", n), + } + } +} +pub fn as_int_0(c: Color) -> i32 { + let c: Value = Rc::new(RefCell::new(c)); + return ((*c.borrow()) as i32).clone(); +} +pub fn classify_option_1(option: i32) -> i32 { + let option: Value = Rc::new(RefCell::new(option)); + 'switch: { + let __match_cond = (*option.borrow()); + match __match_cond { + v if v == (Option::OPT_NONE as i32) => { + return -1_i32; + } + v if v == (Option::OPT_A as i32) => { + return 1; + } + v if v == (Option::OPT_B as i32) => { + return 2; + } + v if v == (Option::OPT_C as i32) => { + return 3; + } + _ => { + return 0; + } + } + }; + panic!("ub: non-void function does not return a value") +} +pub fn make_color_2(n: i32) -> Color { + let n: Value = Rc::new(RefCell::new(n)); + return Color::from((*n.borrow())); +} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let c: Value = Rc::new(RefCell::new(Color::RED)); + assert!((((*c.borrow()) as i32) == (Color::RED as i32))); + assert!((((*c.borrow()) as i32) == 0)); + assert!((((*c.borrow()) as i32) != 1)); + if (((*c.borrow()) as i32) == (Color::GREEN as i32)) { + return 1; + } + 'switch: { + let __match_cond = ((*c.borrow()) as i32); + match __match_cond { + v if v == 0 => { + break 'switch; + } + v if v == 1 => { + return 1; + } + v if v == 2 => { + return 2; + } + _ => { + return 99; + } + } + }; + let x: Value = Rc::new(RefCell::new(((*c.borrow()) as i32).clone())); + assert!(((*x.borrow()) == 0)); + let y: Value = Rc::new(RefCell::new((((*c.borrow()) as i32) + 1))); + assert!(((*y.borrow()) == 1)); + (*c.borrow_mut()) = Color::from(2); + assert!((((*c.borrow()) as i32) == (Color::BLUE as i32))); + assert!((((*c.borrow()) as i32) == 2)); + (*c.borrow_mut()) = ({ + let _n: i32 = 1; + make_color_2(_n) + }); + assert!((((*c.borrow()) as i32) == (Color::GREEN as i32))); + let cmp: Value = Rc::new(RefCell::new(Color::from( + ((((*c.borrow()) as i32) + 1) as i32), + ))); + assert!((((*cmp.borrow()) as i32) == (Color::BLUE as i32))); + let o: Value