diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 6d56236a..17c1075d 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -965,12 +965,8 @@ bool Converter::VisitReturnStmt(clang::ReturnStmt *stmt) { } void Converter::ConvertCondition(clang::Expr *cond) { - if (!cond->getType()->isBooleanType()) { - PushExprKind push(*this, ExprKind::RValue); - Convert(CreateConversionToBool(cond, ctx_)); - return; - } - Convert(cond); + PushExprKind push(*this, ExprKind::RValue); + Convert(NormalizeToBool(cond, ctx_)); } bool Converter::VisitIfStmt(clang::IfStmt *stmt) { @@ -1741,6 +1737,41 @@ void Converter::ConvertIntegerToEnumeralCast(clang::Expr *to, } } +void Converter::ConvertIntegralToBooleanCast(clang::ImplicitCastExpr *expr) { + auto sub_expr = expr->getSubExpr(); + auto *stripped = sub_expr->IgnoreParenImpCasts(); + + if (auto binop = clang::dyn_cast(stripped)) { + // Comparison already produces bool, no wrap needed. + if (binop->isComparisonOp()) { + Convert(sub_expr); + return; + } + // Distribute bool conversion to each argument of the logical op. + if (binop->isLogicalOp()) { + { + PushParen paren(*this); + ConvertCondition(binop->getLHS()); + } + StrCat(binop->getOpcodeStr()); + { + PushParen paren(*this); + ConvertCondition(binop->getRHS()); + } + return; + } + } + + PushParen paren(*this); + Convert(sub_expr); + StrCat(token::kDiff); + if (sub_expr->getType()->isEnumeralType()) { + StrCat(GetUnsafeTypeAsString(sub_expr->getType()), "::from(0)"); + } else /* sub_expr->getType()->isIntegerType() */ { + StrCat(token::kZero); + } +} + bool Converter::VisitImplicitCastExpr(clang::ImplicitCastExpr *expr) { auto *sub_expr = expr->getSubExpr(); auto type = expr->getType(); @@ -1816,20 +1847,7 @@ bool Converter::VisitImplicitCastExpr(clang::ImplicitCastExpr *expr) { Convert(sub_expr); break; case clang::CastKind::CK_IntegralToBoolean: - if (auto binop = clang::dyn_cast( - sub_expr->IgnoreParenImpCasts())) { - // This already produces bool, no need for != 0 - if (binop->isComparisonOp()) { - Convert(sub_expr); - break; - } - } - - { - PushParen paren(*this); - Convert(sub_expr); - StrCat(token::kDiff, token::kZero); - } + ConvertIntegralToBooleanCast(expr); break; case clang::CastKind::CK_PointerToBoolean: StrCat(token::kNot); @@ -2130,6 +2148,18 @@ bool Converter::VisitUnaryOperator(clang::UnaryOperator *expr) { Convert(sub_expr); computed_expr_type_ = ComputedExprType::FreshValue; break; + case clang::UO_LNot: { + bool needs_int_cast = + expr->getType()->isIntegerType() && !expr->getType()->isBooleanType(); + PushParen paren_cast(*this, needs_int_cast); + StrCat(token::kNot); + ConvertCondition(sub_expr); + if (needs_int_cast) { + ConvertCast(expr->getType()); + } + computed_expr_type_ = ComputedExprType::FreshValue; + break; + } case clang::UO_Minus: if (auto *literal = clang::dyn_cast(sub_expr)) { if (sub_expr->getType()->isUnsignedIntegerType()) { @@ -2173,7 +2203,7 @@ void Converter::EmitStmtExprTail(clang::Expr *tail) { Convert(tail); } bool Converter::VisitConditionalOperator(clang::ConditionalOperator *expr) { StrCat(keyword::kIf); - Convert(expr->getCond()); + ConvertCondition(expr->getCond()); { PushBrace then_brace(*this); if (expr->isLValue() && !isRValue() && !expr->getType()->isFunctionType()) { @@ -2290,21 +2320,11 @@ bool Converter::VisitParenExpr(clang::ParenExpr *expr) { } } - // Add cast to avoid ambigous integers. Don't add cast if sub expression is a - // pointer dereference because we might want to mutate the dereferenced value. - bool should_add_integral_cast = - expr->getType()->isIntegralOrEnumerationType() && !isAddrOf() && - !isVoid() && !clang::isa(expr->getSubExpr()); - PushParen outer(*this, should_add_integral_cast); - { PushParen inner(*this); Convert(expr->getSubExpr()); } - if (should_add_integral_cast) { - ConvertCast(expr->getType()); - } return false; } diff --git a/cpp2rust/converter/converter.h b/cpp2rust/converter/converter.h index 27a78041..9d7a7418 100644 --- a/cpp2rust/converter/converter.h +++ b/cpp2rust/converter/converter.h @@ -243,6 +243,8 @@ class Converter : public clang::RecursiveASTVisitor { void ConvertIntegerToEnumeralCast(clang::Expr *to, clang::Expr *from); + void ConvertIntegralToBooleanCast(clang::ImplicitCastExpr *expr); + virtual bool VisitImplicitCastExpr(clang::ImplicitCastExpr *expr); virtual bool VisitExplicitCastExpr(clang::ExplicitCastExpr *expr); diff --git a/cpp2rust/converter/converter_lib.cpp b/cpp2rust/converter/converter_lib.cpp index 027d3245..ed6ddc9f 100644 --- a/cpp2rust/converter/converter_lib.cpp +++ b/cpp2rust/converter/converter_lib.cpp @@ -683,9 +683,32 @@ bool ContainsVAArgExpr(const clang::Stmt *stmt) { return false; } -clang::Expr *CreateConversionToBool(clang::Expr *expr, clang::ASTContext &ctx) { +clang::Expr *NormalizeToBool(clang::Expr *expr, clang::ASTContext &ctx) { + if (expr->getType()->isBooleanType()) { + return expr; + } + + // If logical not returns integer, then craft a new logical not that returns + // bool. + if (auto bin = clang::dyn_cast(expr)) { + if (bin->getOpcode() == clang::UO_LNot) { + return clang::UnaryOperator::Create( + ctx, bin->getSubExpr(), clang::UO_LNot, ctx.BoolTy, clang::VK_PRValue, + clang::OK_Ordinary, clang::SourceLocation(), false, + clang::FPOptionsOverride()); + } + } + + // Either to pointer -> bool, or int -> bool. + clang::CastKind cast_kind; + if (expr->getType()->isPointerType()) { + cast_kind = clang::CK_PointerToBoolean; + } else /* expr->getType()->isIntegerType() */ { + cast_kind = clang::CK_IntegralToBoolean; + } + return clang::ImplicitCastExpr::Create( - ctx, ctx.BoolTy, clang::CK_IntegralToBoolean, expr, + ctx, ctx.BoolTy, cast_kind, expr, /*BasePath=*/nullptr, clang::VK_PRValue, clang::FPOptionsOverride()); } diff --git a/cpp2rust/converter/converter_lib.h b/cpp2rust/converter/converter_lib.h index 3a3cf25d..97fbde64 100644 --- a/cpp2rust/converter/converter_lib.h +++ b/cpp2rust/converter/converter_lib.h @@ -154,7 +154,7 @@ bool IsBuiltinVaCopy(const clang::CallExpr *expr); bool ContainsVAArgExpr(const clang::Stmt *stmt); -clang::Expr *CreateConversionToBool(clang::Expr *expr, clang::ASTContext &ctx); +clang::Expr *NormalizeToBool(clang::Expr *expr, clang::ASTContext &ctx); std::vector GetTopLevelSwitchCases(clang::SwitchStmt *stmt); diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index 645cf63b..9b3c310e 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -615,7 +615,8 @@ bool ConverterRefCount::ConvertIncAndDec(clang::UnaryOperator *expr) { bool ConverterRefCount::VisitConditionalOperator( clang::ConditionalOperator *expr) { - StrCat(keyword::kIf, ConvertRValue(expr->getCond())); + StrCat(keyword::kIf); + ConvertCondition(expr->getCond()); { PushBrace then_brace(*this); StrCat(ConvertFresh(expr->getTrueExpr())); @@ -1046,9 +1047,12 @@ bool ConverterRefCount::VisitImplicitCastExpr(clang::ImplicitCastExpr *expr) { } } - if (expr->getCastKind() == clang::CastKind::CK_NullToPointer && - expr->getType()->isFunctionPointerType()) { - StrCat("FnPtr::null()"); + if (expr->getCastKind() == clang::CastKind::CK_NullToPointer) { + if (expr->getType()->isFunctionPointerType()) { + StrCat("FnPtr::null()"); + } else { + StrCat("Default::default()"); + } computed_expr_type_ = ComputedExprType::FreshPointer; return false; } @@ -1137,6 +1141,11 @@ bool ConverterRefCount::VisitExplicitCastExpr(clang::ExplicitCastExpr *expr) { } return false; } + if (expr->getCastKind() == clang::CK_NullToPointer) { + StrCat("Default::default()"); + computed_expr_type_ = ComputedExprType::FreshPointer; + return false; + } switch (expr->getStmtClass()) { case clang::Stmt::CXXReinterpretCastExprClass: assert(expr->getType()->isPointerType() && diff --git a/tests/ub/out/refcount/ub4.rs b/tests/ub/out/refcount/ub4.rs index 8864310c..58bb8f61 100644 --- a/tests/ub/out/refcount/ub4.rs +++ b/tests/ub/out/refcount/ub4.rs @@ -7,11 +7,10 @@ use std::io::{Read, Seek, Write}; use std::os::fd::AsFd; use std::rc::{Rc, Weak}; pub fn smaller_0(x1: Ptr, x2: Ptr) -> Ptr { - return if (({ + return if ({ let _lhs = (x1.read()); _lhs < (x2.read()) - }) as bool) - { + }) { (x1).clone() } else { (x2).clone() diff --git a/tests/ub/out/unsafe/ub4.rs b/tests/ub/out/unsafe/ub4.rs index 9d642ab8..4e49a9ab 100644 --- a/tests/ub/out/unsafe/ub4.rs +++ b/tests/ub/out/unsafe/ub4.rs @@ -7,11 +7,7 @@ use std::io::{Read, Seek, Write}; use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; use std::rc::Rc; pub unsafe fn smaller_0(x1: *mut i32, x2: *mut i32) -> *mut i32 { - return if (((*x1) < (*x2)) as bool) { - (x1) - } else { - (x2) - }; + return if ((*x1) < (*x2)) { (x1) } else { (x2) }; } pub fn main() { unsafe { diff --git a/tests/unit/bool_condition_enum.cpp b/tests/unit/bool_condition_enum.cpp new file mode 100644 index 00000000..fb24e8e5 --- /dev/null +++ b/tests/unit/bool_condition_enum.cpp @@ -0,0 +1,29 @@ +#include + +enum Code { CODE_OK = 0, CODE_ERR = 1, CODE_FATAL = 2 }; + +int main() { + Code code = CODE_OK; + Code err = CODE_ERR; + + if (code) { + assert(false); + } + if (!code) { + assert(true); + } + if (err) { + assert(true); + } + if (!err) { + assert(false); + } + + int t9 = !code; + assert(t9 == 1); + + bool b4 = code; + assert(!b4); + + return 0; +} diff --git a/tests/unit/bool_condition_enum_c.c b/tests/unit/bool_condition_enum_c.c new file mode 100644 index 00000000..617bf9e6 --- /dev/null +++ b/tests/unit/bool_condition_enum_c.c @@ -0,0 +1,30 @@ +#include +#include + +enum Code { CODE_OK = 0, CODE_ERR = 1, CODE_FATAL = 2 }; + +int main() { + enum Code code = CODE_OK; + enum Code err = CODE_ERR; + + if (code) { + assert(false); + } + if (!code) { + assert(true); + } + if (err) { + assert(true); + } + if (!err) { + assert(false); + } + + int t9 = !code; + assert(t9 == 1); + + bool b4 = code; + assert(!b4); + + return 0; +} diff --git a/tests/unit/bool_condition_int.cpp b/tests/unit/bool_condition_int.cpp new file mode 100644 index 00000000..4a1b889c --- /dev/null +++ b/tests/unit/bool_condition_int.cpp @@ -0,0 +1,63 @@ +#include + +int main() { + int n = 3; + int zero = 0; + unsigned u = 4; + unsigned long ul = 5; + long long ll = 6; + char ch = 'a'; + + if (n) { + assert(true); + } + if (!n) { + assert(false); + } + if (zero) { + assert(false); + } + if (!zero) { + assert(true); + } + + if (u) { + assert(true); + } + if (ul) { + assert(true); + } + if (ll) { + assert(true); + } + if (ch) { + assert(true); + } + + int loop_count = 0; + int counter = 3; + while (counter) { + --counter; + ++loop_count; + } + assert(loop_count == 3); + + for (int i = 5; i; --i) { + ++loop_count; + } + assert(loop_count == 8); + + int t = n ? 100 : 200; + assert(t == 100); + int t2 = zero ? 100 : 200; + assert(t2 == 200); + int t7 = !n; + assert(t7 == 0); + int t8 = !zero; + assert(t8 == 1); + + bool b1 = n; + assert(b1); + + return 0; +} diff --git a/tests/unit/bool_condition_int_c.c b/tests/unit/bool_condition_int_c.c new file mode 100644 index 00000000..8d9d68db --- /dev/null +++ b/tests/unit/bool_condition_int_c.c @@ -0,0 +1,64 @@ +#include +#include + +int main() { + int n = 3; + int zero = 0; + unsigned u = 4; + unsigned long ul = 5; + long long ll = 6; + char ch = 'a'; + + if (n) { + assert(true); + } + if (!n) { + assert(false); + } + if (zero) { + assert(false); + } + if (!zero) { + assert(true); + } + + if (u) { + assert(true); + } + if (ul) { + assert(true); + } + if (ll) { + assert(true); + } + if (ch) { + assert(true); + } + + int loop_count = 0; + int counter = 3; + while (counter) { + --counter; + ++loop_count; + } + assert(loop_count == 3); + + for (int i = 5; i; --i) { + ++loop_count; + } + assert(loop_count == 8); + + int t = n ? 100 : 200; + assert(t == 100); + int t2 = zero ? 100 : 200; + assert(t2 == 200); + int t7 = !n; + assert(t7 == 0); + int t8 = !zero; + assert(t8 == 1); + + bool b1 = n; + assert(b1); + + return 0; +} diff --git a/tests/unit/bool_condition_logical.cpp b/tests/unit/bool_condition_logical.cpp new file mode 100644 index 00000000..eff2ae58 --- /dev/null +++ b/tests/unit/bool_condition_logical.cpp @@ -0,0 +1,81 @@ +#include +#include + +enum Code { CODE_OK = 0, CODE_ERR = 1, CODE_FATAL = 2 }; + +int side_effect = 0; +int observe(int v) { + ++side_effect; + return v; +} + +int main() { + int n = 3; + int zero = 0; + int storage = 7; + int *p = &storage; + int *np = nullptr; + unsigned u = 4; + Code code = CODE_OK; + + if (n && p) { + assert(true); + } + if (n && np) { + assert(false); + } + if (zero || p) { + assert(true); + } + if (zero || np) { + assert(false); + } + if (n && u && p && code == CODE_OK) { + assert(true); + } + + side_effect = 0; + if (zero && observe(1)) { + assert(false); + } + assert(side_effect == 0); + + if (n || observe(1)) { + assert(true); + } + assert(side_effect == 0); + + int x = 5; + int y = 3; + unsigned flags = 0x2u; + if ((x > y) || (flags & 0x1u)) { + assert(true); + } + if ((x < y) || (flags & 0x1u)) { + assert(false); + } + + unsigned a = 1u; + unsigned b = 2u; + unsigned c = 3u; + if (((a != c)) && ((b != c))) { + assert(true); + } + + int s = -1; + if ((p != nullptr) && (s < 0)) { + assert(true); + } + + unsigned k = 2u; + bool done = false; + if ((k > 1u) || !done) { + assert(true); + } + + if (((x > y)) || ((flags & 0x4u))) { + assert(true); + } + + return 0; +} diff --git a/tests/unit/bool_condition_logical_c.c b/tests/unit/bool_condition_logical_c.c new file mode 100644 index 00000000..c7870f3f --- /dev/null +++ b/tests/unit/bool_condition_logical_c.c @@ -0,0 +1,82 @@ +#include +#include +#include + +enum Code { CODE_OK = 0, CODE_ERR = 1, CODE_FATAL = 2 }; + +int side_effect = 0; +int observe(int v) { + ++side_effect; + return v; +} + +int main() { + int n = 3; + int zero = 0; + int storage = 7; + int *p = &storage; + int *np = NULL; + unsigned u = 4; + enum Code code = CODE_OK; + + if (n && p) { + assert(true); + } + if (n && np) { + assert(false); + } + if (zero || p) { + assert(true); + } + if (zero || np) { + assert(false); + } + if (n && u && p && code == CODE_OK) { + assert(true); + } + + side_effect = 0; + if (zero && observe(1)) { + assert(false); + } + assert(side_effect == 0); + + if (n || observe(1)) { + assert(true); + } + assert(side_effect == 0); + + int x = 5; + int y = 3; + unsigned flags = 0x2u; + if ((x > y) || (flags & 0x1u)) { + assert(true); + } + if ((x < y) || (flags & 0x1u)) { + assert(false); + } + + unsigned a = 1u; + unsigned b = 2u; + unsigned c = 3u; + if (((a != c)) && ((b != c))) { + assert(true); + } + + int s = -1; + if ((p != NULL) && (s < 0)) { + assert(true); + } + + unsigned k = 2u; + bool done = false; + if ((k > 1u) || !done) { + assert(true); + } + + if (((x > y)) || ((flags & 0x4u))) { + assert(true); + } + + return 0; +} diff --git a/tests/unit/bool_condition_ptr.cpp b/tests/unit/bool_condition_ptr.cpp new file mode 100644 index 00000000..ccf4714a --- /dev/null +++ b/tests/unit/bool_condition_ptr.cpp @@ -0,0 +1,45 @@ +#include +#include + +int main() { + int storage = 7; + int *p = &storage; + int *np = nullptr; + + if (p) { + assert(true); + } + if (!p) { + assert(false); + } + if (np) { + assert(false); + } + if (!np) { + assert(true); + } + + int *iter = p; + int iters = 0; + while (iter) { + ++iters; + iter = nullptr; + } + assert(iters == 1); + + int t3 = p ? 1 : 0; + assert(t3 == 1); + int t4 = np ? 1 : 0; + assert(t4 == 0); + int t5 = !p; + assert(t5 == 0); + int t6 = !np; + assert(t6 == 1); + + bool b2 = p; + bool b3 = np; + assert(b2); + assert(!b3); + + return 0; +} diff --git a/tests/unit/bool_condition_ptr_c.c b/tests/unit/bool_condition_ptr_c.c new file mode 100644 index 00000000..420e204c --- /dev/null +++ b/tests/unit/bool_condition_ptr_c.c @@ -0,0 +1,46 @@ +#include +#include +#include + +int main() { + int storage = 7; + int *p = &storage; + int *np = NULL; + + if (p) { + assert(true); + } + if (!p) { + assert(false); + } + if (np) { + assert(false); + } + if (!np) { + assert(true); + } + + int *iter = p; + int iters = 0; + while (iter) { + ++iters; + iter = NULL; + } + assert(iters == 1); + + int t3 = p ? 1 : 0; + assert(t3 == 1); + int t4 = np ? 1 : 0; + assert(t4 == 0); + int t5 = !p; + assert(t5 == 0); + int t6 = !np; + assert(t6 == 1); + + bool b2 = p; + bool b3 = np; + assert(b2); + assert(!b3); + + return 0; +} diff --git a/tests/unit/out/refcount/bool_condition_enum.rs b/tests/unit/out/refcount/bool_condition_enum.rs new file mode 100644 index 00000000..312017ae --- /dev/null +++ b/tests/unit/out/refcount/bool_condition_enum.rs @@ -0,0 +1,49 @@ +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 Code { + #[default] + CODE_OK = 0, + CODE_ERR = 1, + CODE_FATAL = 2, +} +impl From for Code { + fn from(n: i32) -> Code { + match n { + 0 => Code::CODE_OK, + 1 => Code::CODE_ERR, + 2 => Code::CODE_FATAL, + _ => panic!("invalid Code value: {}", n), + } + } +} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let code: Value = Rc::new(RefCell::new(Code::CODE_OK)); + let err: Value = Rc::new(RefCell::new(Code::CODE_ERR)); + if ((*code.borrow()) != Code::from(0)) { + assert!(false); + } + if !((*code.borrow()) != Code::from(0)) { + assert!(true); + } + if ((*err.borrow()) != Code::from(0)) { + assert!(true); + } + if !((*err.borrow()) != Code::from(0)) { + assert!(false); + } + let t9: Value = Rc::new(RefCell::new((!((*code.borrow()) != Code::from(0)) as i32))); + assert!(((*t9.borrow()) == 1)); + let b4: Value = Rc::new(RefCell::new(((*code.borrow()) != Code::from(0)).clone())); + assert!(!(*b4.borrow())); + return 0; +} diff --git a/tests/unit/out/refcount/bool_condition_enum_c.rs b/tests/unit/out/refcount/bool_condition_enum_c.rs new file mode 100644 index 00000000..150f2611 --- /dev/null +++ b/tests/unit/out/refcount/bool_condition_enum_c.rs @@ -0,0 +1,49 @@ +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 Code { + #[default] + CODE_OK = 0, + CODE_ERR = 1, + CODE_FATAL = 2, +} +impl From for Code { + fn from(n: i32) -> Code { + match n { + 0 => Code::CODE_OK, + 1 => Code::CODE_ERR, + 2 => Code::CODE_FATAL, + _ => panic!("invalid Code value: {}", n), + } + } +} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let code: Value = Rc::new(RefCell::new(Code::from((Code::CODE_OK as i32)))); + let err: Value = Rc::new(RefCell::new(Code::from((Code::CODE_ERR as i32)))); + if ((*code.borrow()) != Code::from(0)) { + assert!((0 != 0)); + } + if !((*code.borrow()) != Code::from(0)) { + assert!((1 != 0)); + } + if ((*err.borrow()) != Code::from(0)) { + assert!((1 != 0)); + } + if !((*err.borrow()) != Code::from(0)) { + assert!((0 != 0)); + } + let t9: Value = Rc::new(RefCell::new((!((*code.borrow()) != Code::from(0)) as i32))); + assert!(((*t9.borrow()) == 1)); + let b4: Value = Rc::new(RefCell::new(((*code.borrow()) != Code::from(0)).clone())); + assert!(((!(*b4.borrow()) as i32) != 0)); + return 0; +} diff --git a/tests/unit/out/refcount/bool_condition_int.rs b/tests/unit/out/refcount/bool_condition_int.rs new file mode 100644 index 00000000..ad21faed --- /dev/null +++ b/tests/unit/out/refcount/bool_condition_int.rs @@ -0,0 +1,71 @@ +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 n: Value = Rc::new(RefCell::new(3)); + let zero: Value = Rc::new(RefCell::new(0)); + let u: Value = Rc::new(RefCell::new(4_u32)); + let ul: Value = Rc::new(RefCell::new(5_u64)); + let ll: Value = Rc::new(RefCell::new(6_i64)); + let ch: Value = Rc::new(RefCell::new(('a' as u8))); + if ((*n.borrow()) != 0) { + assert!(true); + } + if !((*n.borrow()) != 0) { + assert!(false); + } + if ((*zero.borrow()) != 0) { + assert!(false); + } + if !((*zero.borrow()) != 0) { + assert!(true); + } + if ((*u.borrow()) != 0) { + assert!(true); + } + if ((*ul.borrow()) != 0) { + assert!(true); + } + if ((*ll.borrow()) != 0) { + assert!(true); + } + if ((*ch.borrow()) != 0) { + assert!(true); + } + let loop_count: Value = Rc::new(RefCell::new(0)); + let counter: Value = Rc::new(RefCell::new(3)); + 'loop_: while ((*counter.borrow()) != 0) { + (*counter.borrow_mut()).prefix_dec(); + (*loop_count.borrow_mut()).prefix_inc(); + } + assert!(((*loop_count.borrow()) == 3)); + let i: Value = Rc::new(RefCell::new(5)); + 'loop_: while ((*i.borrow()) != 0) { + (*loop_count.borrow_mut()).prefix_inc(); + (*i.borrow_mut()).prefix_dec(); + } + assert!(((*loop_count.borrow()) == 8)); + let t: Value = Rc::new(RefCell::new(if ((*n.borrow()) != 0) { 100 } else { 200 })); + assert!(((*t.borrow()) == 100)); + let t2: Value = Rc::new(RefCell::new(if ((*zero.borrow()) != 0) { + 100 + } else { + 200 + })); + assert!(((*t2.borrow()) == 200)); + let t7: Value = Rc::new(RefCell::new((!((*n.borrow()) != 0) as i32))); + assert!(((*t7.borrow()) == 0)); + let t8: Value = Rc::new(RefCell::new((!((*zero.borrow()) != 0) as i32))); + assert!(((*t8.borrow()) == 1)); + let b1: Value = Rc::new(RefCell::new(((*n.borrow()) != 0))); + assert!((*b1.borrow())); + return 0; +} diff --git a/tests/unit/out/refcount/bool_condition_int_c.rs b/tests/unit/out/refcount/bool_condition_int_c.rs new file mode 100644 index 00000000..7d685281 --- /dev/null +++ b/tests/unit/out/refcount/bool_condition_int_c.rs @@ -0,0 +1,71 @@ +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 n: Value = Rc::new(RefCell::new(3)); + let zero: Value = Rc::new(RefCell::new(0)); + let u: Value = Rc::new(RefCell::new(4_u32)); + let ul: Value = Rc::new(RefCell::new(5_u64)); + let ll: Value = Rc::new(RefCell::new(6_i64)); + let ch: Value = Rc::new(RefCell::new((('a' as i32) as u8))); + if ((*n.borrow()) != 0) { + assert!((1 != 0)); + } + if !((*n.borrow()) != 0) { + assert!((0 != 0)); + } + if ((*zero.borrow()) != 0) { + assert!((0 != 0)); + } + if !((*zero.borrow()) != 0) { + assert!((1 != 0)); + } + if ((*u.borrow()) != 0) { + assert!((1 != 0)); + } + if ((*ul.borrow()) != 0) { + assert!((1 != 0)); + } + if ((*ll.borrow()) != 0) { + assert!((1 != 0)); + } + if ((*ch.borrow()) != 0) { + assert!((1 != 0)); + } + let loop_count: Value = Rc::new(RefCell::new(0)); + let counter: Value = Rc::new(RefCell::new(3)); + 'loop_: while ((*counter.borrow()) != 0) { + (*counter.borrow_mut()).prefix_dec(); + (*loop_count.borrow_mut()).prefix_inc(); + } + assert!(((*loop_count.borrow()) == 3)); + let i: Value = Rc::new(RefCell::new(5)); + 'loop_: while ((*i.borrow()) != 0) { + (*loop_count.borrow_mut()).prefix_inc(); + (*i.borrow_mut()).prefix_dec(); + } + assert!(((*loop_count.borrow()) == 8)); + let t: Value = Rc::new(RefCell::new(if ((*n.borrow()) != 0) { 100 } else { 200 })); + assert!(((*t.borrow()) == 100)); + let t2: Value = Rc::new(RefCell::new(if ((*zero.borrow()) != 0) { + 100 + } else { + 200 + })); + assert!(((*t2.borrow()) == 200)); + let t7: Value = Rc::new(RefCell::new((!((*n.borrow()) != 0) as i32))); + assert!(((*t7.borrow()) == 0)); + let t8: Value = Rc::new(RefCell::new((!((*zero.borrow()) != 0) as i32))); + assert!(((*t8.borrow()) == 1)); + let b1: Value = Rc::new(RefCell::new(((*n.borrow()) != 0))); + assert!((*b1.borrow())); + return 0; +} diff --git a/tests/unit/out/refcount/bool_condition_logical.rs b/tests/unit/out/refcount/bool_condition_logical.rs new file mode 100644 index 00000000..a25a429d --- /dev/null +++ b/tests/unit/out/refcount/bool_condition_logical.rs @@ -0,0 +1,128 @@ +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 Code { + #[default] + CODE_OK = 0, + CODE_ERR = 1, + CODE_FATAL = 2, +} +impl From for Code { + fn from(n: i32) -> Code { + match n { + 0 => Code::CODE_OK, + 1 => Code::CODE_ERR, + 2 => Code::CODE_FATAL, + _ => panic!("invalid Code value: {}", n), + } + } +} +thread_local!( + pub static side_effect: Value = Rc::new(RefCell::new(0)); +); +pub fn observe_0(v: i32) -> i32 { + let v: Value = Rc::new(RefCell::new(v)); + (*side_effect.with(Value::clone).borrow_mut()).prefix_inc(); + return (*v.borrow()); +} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let n: Value = Rc::new(RefCell::new(3)); + let zero: Value = Rc::new(RefCell::new(0)); + let storage: Value = Rc::new(RefCell::new(7)); + let p: Value> = Rc::new(RefCell::new((storage.as_pointer()))); + let np: Value> = Rc::new(RefCell::new(Default::default())); + let u: Value = Rc::new(RefCell::new(4_u32)); + let code: Value = Rc::new(RefCell::new(Code::CODE_OK)); + if { + let _lhs = ((*n.borrow()) != 0); + _lhs && (!(*p.borrow()).is_null()).clone() + } { + assert!(true); + } + if { + let _lhs = ((*n.borrow()) != 0); + _lhs && (!(*np.borrow()).is_null()).clone() + } { + assert!(false); + } + if { + let _lhs = ((*zero.borrow()) != 0); + _lhs || (!(*p.borrow()).is_null()).clone() + } { + assert!(true); + } + if { + let _lhs = ((*zero.borrow()) != 0); + _lhs || (!(*np.borrow()).is_null()).clone() + } { + assert!(false); + } + if { + let _lhs = { + let _lhs = (((*n.borrow()) != 0) && ((*u.borrow()) != 0)); + _lhs && (!(*p.borrow()).is_null()).clone() + }; + _lhs && (((*code.borrow()) as i32) == (Code::CODE_OK as i32)).clone() + } { + assert!(true); + } + (*side_effect.with(Value::clone).borrow_mut()) = 0; + if (((*zero.borrow()) != 0) + && (({ + let _v: i32 = 1; + observe_0(_v) + }) != 0)) + { + assert!(false); + } + assert!(((*side_effect.with(Value::clone).borrow()) == 0)); + if (((*n.borrow()) != 0) + || (({ + let _v: i32 = 1; + observe_0(_v) + }) != 0)) + { + assert!(true); + } + assert!(((*side_effect.with(Value::clone).borrow()) == 0)); + let x: Value = Rc::new(RefCell::new(5)); + let y: Value = Rc::new(RefCell::new(3)); + let flags: Value = Rc::new(RefCell::new(2_u32)); + if (((*x.borrow()) > (*y.borrow())) || (((*flags.borrow()) & 1_u32) != 0)) { + assert!(true); + } + if (((*x.borrow()) < (*y.borrow())) || (((*flags.borrow()) & 1_u32) != 0)) { + assert!(false); + } + let a: Value = Rc::new(RefCell::new(1_u32)); + let b: Value = Rc::new(RefCell::new(2_u32)); + let c: Value = Rc::new(RefCell::new(3_u32)); + if (((*a.borrow()) != (*c.borrow())) && ((*b.borrow()) != (*c.borrow()))) { + assert!(true); + } + let s: Value = Rc::new(RefCell::new(-1_i32)); + if { + let _lhs = (!((*p.borrow()).is_null())).clone(); + _lhs && ((*s.borrow()) < 0) + } { + assert!(true); + } + let k: Value = Rc::new(RefCell::new(2_u32)); + let done: Value = Rc::new(RefCell::new(false)); + if (((*k.borrow()) > 1_u32) || !(*done.borrow())) { + assert!(true); + } + if (((*x.borrow()) > (*y.borrow())) || (((*flags.borrow()) & 4_u32) != 0)) { + assert!(true); + } + return 0; +} diff --git a/tests/unit/out/refcount/bool_condition_logical_c.rs b/tests/unit/out/refcount/bool_condition_logical_c.rs new file mode 100644 index 00000000..fcf9535b --- /dev/null +++ b/tests/unit/out/refcount/bool_condition_logical_c.rs @@ -0,0 +1,109 @@ +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 Code { + #[default] + CODE_OK = 0, + CODE_ERR = 1, + CODE_FATAL = 2, +} +impl From for Code { + fn from(n: i32) -> Code { + match n { + 0 => Code::CODE_OK, + 1 => Code::CODE_ERR, + 2 => Code::CODE_FATAL, + _ => panic!("invalid Code value: {}", n), + } + } +} +thread_local!( + pub static side_effect: Value = Rc::new(RefCell::new(0)); +); +pub fn observe_0(v: i32) -> i32 { + let v: Value = Rc::new(RefCell::new(v)); + (*side_effect.with(Value::clone).borrow_mut()).prefix_inc(); + return (*v.borrow()); +} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let n: Value = Rc::new(RefCell::new(3)); + let zero: Value = Rc::new(RefCell::new(0)); + let storage: Value = Rc::new(RefCell::new(7)); + let p: Value> = Rc::new(RefCell::new((storage.as_pointer()))); + let np: Value> = Rc::new(RefCell::new(Default::default())); + let u: Value = Rc::new(RefCell::new(4_u32)); + let code: Value = Rc::new(RefCell::new(Code::from((Code::CODE_OK as i32)))); + if ((*n.borrow()) != 0) && (!(*p.borrow()).is_null()) { + assert!((1 != 0)); + } + if ((*n.borrow()) != 0) && (!(*np.borrow()).is_null()) { + assert!((0 != 0)); + } + if ((*zero.borrow()) != 0) || (!(*p.borrow()).is_null()) { + assert!((1 != 0)); + } + if ((*zero.borrow()) != 0) || (!(*np.borrow()).is_null()) { + assert!((0 != 0)); + } + if ((((*n.borrow()) != 0) && ((*u.borrow()) != 0)) && (!(*p.borrow()).is_null())) + && (((*code.borrow()) as u32) == ((Code::CODE_OK as i32) as u32)) + { + assert!((1 != 0)); + } + (*side_effect.with(Value::clone).borrow_mut()) = 0; + if ((*zero.borrow()) != 0) + && (({ + let _v: i32 = 1; + observe_0(_v) + }) != 0) + { + assert!((0 != 0)); + } + assert!(((*side_effect.with(Value::clone).borrow()) == 0)); + if ((*n.borrow()) != 0) + || (({ + let _v: i32 = 1; + observe_0(_v) + }) != 0) + { + assert!((1 != 0)); + } + assert!(((*side_effect.with(Value::clone).borrow()) == 0)); + let x: Value = Rc::new(RefCell::new(5)); + let y: Value = Rc::new(RefCell::new(3)); + let flags: Value = Rc::new(RefCell::new(2_u32)); + if ((*x.borrow()) > (*y.borrow())) || (((*flags.borrow()) & 1_u32) != 0) { + assert!((1 != 0)); + } + if ((*x.borrow()) < (*y.borrow())) || (((*flags.borrow()) & 1_u32) != 0) { + assert!((0 != 0)); + } + let a: Value = Rc::new(RefCell::new(1_u32)); + let b: Value = Rc::new(RefCell::new(2_u32)); + let c: Value = Rc::new(RefCell::new(3_u32)); + if ((*a.borrow()) != (*c.borrow())) && ((*b.borrow()) != (*c.borrow())) { + assert!((1 != 0)); + } + let s: Value = Rc::new(RefCell::new(-1_i32)); + if ((*p.borrow()) != (Default::default())) && ((*s.borrow()) < 0) { + assert!((1 != 0)); + } + let k: Value = Rc::new(RefCell::new(2_u32)); + let done: Value = Rc::new(RefCell::new((0 != 0))); + if ((*k.borrow()) > 1_u32) || (!(*done.borrow())) { + assert!((1 != 0)); + } + if ((*x.borrow()) > (*y.borrow())) || (((*flags.borrow()) & 4_u32) != 0) { + assert!((1 != 0)); + } + return 0; +} diff --git a/tests/unit/out/refcount/bool_condition_ptr.rs b/tests/unit/out/refcount/bool_condition_ptr.rs new file mode 100644 index 00000000..87545fdb --- /dev/null +++ b/tests/unit/out/refcount/bool_condition_ptr.rs @@ -0,0 +1,48 @@ +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 storage: Value = Rc::new(RefCell::new(7)); + let p: Value> = Rc::new(RefCell::new((storage.as_pointer()))); + let np: Value> = Rc::new(RefCell::new(Default::default())); + if !(*p.borrow()).is_null() { + assert!(true); + } + if !!(*p.borrow()).is_null() { + assert!(false); + } + if !(*np.borrow()).is_null() { + assert!(false); + } + if !!(*np.borrow()).is_null() { + assert!(true); + } + let iter: Value> = Rc::new(RefCell::new((*p.borrow()).clone())); + let iters: Value = Rc::new(RefCell::new(0)); + 'loop_: while !(*iter.borrow()).is_null() { + (*iters.borrow_mut()).prefix_inc(); + (*iter.borrow_mut()) = Default::default(); + } + assert!(((*iters.borrow()) == 1)); + let t3: Value = Rc::new(RefCell::new(if !(*p.borrow()).is_null() { 1 } else { 0 })); + assert!(((*t3.borrow()) == 1)); + let t4: Value = Rc::new(RefCell::new(if !(*np.borrow()).is_null() { 1 } else { 0 })); + assert!(((*t4.borrow()) == 0)); + let t5: Value = Rc::new(RefCell::new((!!(*p.borrow()).is_null() as i32))); + assert!(((*t5.borrow()) == 0)); + let t6: Value = Rc::new(RefCell::new((!!(*np.borrow()).is_null() as i32))); + assert!(((*t6.borrow()) == 1)); + let b2: Value = Rc::new(RefCell::new((!(*p.borrow()).is_null()).clone())); + let b3: Value = Rc::new(RefCell::new((!(*np.borrow()).is_null()).clone())); + assert!((*b2.borrow())); + assert!(!(*b3.borrow())); + return 0; +} diff --git a/tests/unit/out/refcount/bool_condition_ptr_c.rs b/tests/unit/out/refcount/bool_condition_ptr_c.rs new file mode 100644 index 00000000..68f93d26 --- /dev/null +++ b/tests/unit/out/refcount/bool_condition_ptr_c.rs @@ -0,0 +1,48 @@ +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 storage: Value = Rc::new(RefCell::new(7)); + let p: Value> = Rc::new(RefCell::new((storage.as_pointer()))); + let np: Value> = Rc::new(RefCell::new(Default::default())); + if !(*p.borrow()).is_null() { + assert!((1 != 0)); + } + if !!(*p.borrow()).is_null() { + assert!((0 != 0)); + } + if !(*np.borrow()).is_null() { + assert!((0 != 0)); + } + if !!(*np.borrow()).is_null() { + assert!((1 != 0)); + } + let iter: Value> = Rc::new(RefCell::new((*p.borrow()).clone())); + let iters: Value = Rc::new(RefCell::new(0)); + 'loop_: while !(*iter.borrow()).is_null() { + (*iters.borrow_mut()).prefix_inc(); + (*iter.borrow_mut()) = Default::default(); + } + assert!(((*iters.borrow()) == 1)); + let t3: Value = Rc::new(RefCell::new(if !(*p.borrow()).is_null() { 1 } else { 0 })); + assert!(((*t3.borrow()) == 1)); + let t4: Value = Rc::new(RefCell::new(if !(*np.borrow()).is_null() { 1 } else { 0 })); + assert!(((*t4.borrow()) == 0)); + let t5: Value = Rc::new(RefCell::new((!!(*p.borrow()).is_null() as i32))); + assert!(((*t5.borrow()) == 0)); + let t6: Value = Rc::new(RefCell::new((!!(*np.borrow()).is_null() as i32))); + assert!(((*t6.borrow()) == 1)); + let b2: Value = Rc::new(RefCell::new((!(*p.borrow()).is_null()).clone())); + let b3: Value = Rc::new(RefCell::new((!(*np.borrow()).is_null()).clone())); + assert!((*b2.borrow())); + assert!(((!(*b3.borrow()) as i32) != 0)); + return 0; +} diff --git a/tests/unit/out/refcount/enum_int_interop.rs b/tests/unit/out/refcount/enum_int_interop.rs index 64e02edf..6ba4c69f 100644 --- a/tests/unit/out/refcount/enum_int_interop.rs +++ b/tests/unit/out/refcount/enum_int_interop.rs @@ -131,9 +131,7 @@ fn main_0() -> i32 { 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), - ))); + let cmp: Value = Rc::new(RefCell::new(Color::from((((*c.borrow()) as i32) + 1)))); assert!((((*cmp.borrow()) as i32) == (Color::BLUE as i32))); let o: Value