diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 5fe0269a..ec547615 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -130,17 +130,15 @@ bool Converter::VisitRecordType(clang::RecordType *type) { auto *decl = type->getDecl(); if (auto lambda = clang::dyn_cast(decl)) { if (lambda->isLambda()) { - auto call_op = lambda->getLambdaCallOperator(); - StrCat("Rcparameters()) { - StrCat(std::format("{},", ToStringBase(p->getType()))); - } - StrCat(")"); - if (!call_op->getReturnType()->isVoidType()) { - StrCat("->"); - StrCat(ToStringBase(call_op->getReturnType())); + if (in_function_formals_) { + StrCat( + ConvertFunctionPointerType(lambda->getLambdaCallOperator() + ->getType() + ->getAs(), + FnProtoType::LambdaCallOperator)); + } else { + StrCat("_"); } - StrCat(">"); return false; } } @@ -222,24 +220,25 @@ bool Converter::VisitLValueReferenceType(clang::LValueReferenceType *type) { return Convert(pointee_type); } -void Converter::ConvertFunctionPointerType(clang::PointerType *type) { - auto proto = type->getPointeeType()->getAs(); - assert(proto && "Type should be a function prototype"); - - StrCat("Rcparam_types()) { - StrCat(std::format("{},", ToString(p_ty))); + result += ToString(p_ty) + ","; } - StrCat(")"); + result += ")"; if (!proto->getReturnType()->isVoidType()) { - StrCat(std::format("-> {}", ToString(proto->getReturnType()))); + result += std::format(" -> {}", ToString(proto->getReturnType())); } - StrCat(">"); + return result; } bool Converter::VisitPointerType(clang::PointerType *type) { - if (type->getPointeeType()->getAs()) { - ConvertFunctionPointerType(type); + if (auto proto = type->getPointeeType()->getAs()) { + StrCat(std::format("Option<{} {}>", keyword_unsafe_, + ConvertFunctionPointerType(proto))); return false; } @@ -423,6 +422,9 @@ bool Converter::ConvertVarDeclSkipInit(clang::VarDecl *decl) { } bool Converter::ConvertLambdaVarDecl(clang::VarDecl *decl) { + if (decl->getType()->isFunctionPointerType()) { + return false; + } if (decl->hasInit()) { if (clang::isa( decl->getInit()->IgnoreUnlessSpelledInSource())) { @@ -1377,6 +1379,17 @@ bool Converter::VisitCallExpr(clang::CallExpr *expr) { return false; } +void Converter::EmitFnPtrCall(clang::Expr *callee) { + StrCat(token::kOpenParen); + Convert(callee); + StrCat(").unwrap()"); +} + +void Converter::ConvertFunctionToFunctionPointer( + const clang::FunctionDecl *fn_decl) { + StrCat(std::format("Some({})", GetNamedDeclAsString(fn_decl))); +} + void Converter::ConvertGenericCallExpr(clang::CallExpr *expr) { clang::Expr *callee = expr->getCallee(); auto convert_param_ty = [&](clang::QualType param_type, clang::Expr *expr) { @@ -1399,7 +1412,8 @@ void Converter::ConvertGenericCallExpr(clang::CallExpr *expr) { StrCat(token::kOpenParen); StrCat(keyword_unsafe_); StrCat(token::kOpenCurlyBracket); - const auto *function = expr->getCalleeDecl()->getAsFunction(); + const auto *function = + expr->getCalleeDecl() ? expr->getCalleeDecl()->getAsFunction() : nullptr; const clang::FunctionProtoType *proto = nullptr; if (!function) { @@ -1447,7 +1461,12 @@ void Converter::ConvertGenericCallExpr(clang::CallExpr *expr) { } } - Convert(callee); + if (proto && !function) { + EmitFnPtrCall(callee); + } else { + PushExprKind push(*this, ExprKind::Callee); + Convert(callee); + } StrCat(token::kOpenParen); for (unsigned i = 0; i < num_named_params && i < num_args; ++i) { auto *arg = expr->getArg(i + arg_begin); @@ -1668,7 +1687,15 @@ bool Converter::VisitImplicitCastExpr(clang::ImplicitCastExpr *expr) { break; } case clang::CastKind::CK_FunctionToPointerDecay: - case clang::CastKind::CK_BuiltinFnToFnPtr: + case clang::CastKind::CK_BuiltinFnToFnPtr: { + if (isCallee()) { + Convert(sub_expr); + } else { + PushExprKind push(*this, ExprKind::AddrOf); + Convert(sub_expr); + } + break; + } case clang::CastKind::CK_ConstructorConversion: case clang::CastKind::CK_DerivedToBase: Convert(sub_expr); @@ -1692,7 +1719,11 @@ bool Converter::VisitImplicitCastExpr(clang::ImplicitCastExpr *expr) { ConvertEqualsNullPtr(sub_expr); break; case clang::CastKind::CK_NullToPointer: - StrCat(keyword_default_); + if (type->isFunctionPointerType()) { + StrCat("None"); + } else { + StrCat(keyword_default_); + } computed_expr_type_ = ComputedExprType::FreshPointer; break; default: @@ -1737,6 +1768,17 @@ bool Converter::VisitExplicitCastExpr(clang::ExplicitCastExpr *expr) { if (expr->getType() == sub_expr->getType()) { return Convert(sub_expr); } + if (type->isFunctionPointerType() || + sub_expr->getType()->isFunctionPointerType()) { + StrCat("std::mem::transmute::<"); + Convert(sub_expr->getType()); + StrCat(","); + Convert(type); + StrCat(">("); + Convert(sub_expr); + StrCat(")"); + return false; + } StrCat(token::kOpenParen); Convert(sub_expr); if (auto *unary_oper = clang::dyn_cast(sub_expr); @@ -1963,12 +2005,12 @@ bool Converter::VisitConditionalOperator(clang::ConditionalOperator *expr) { StrCat(keyword::kIf); Convert(expr->getCond()); StrCat(token::kOpenCurlyBracket); - if (expr->isLValue() && !isRValue()) { + if (expr->isLValue() && !isRValue() && !expr->getType()->isFunctionType()) { StrCat(token::kRef, keyword_mut_); } Convert(expr->getTrueExpr()); StrCat(token::kCloseCurlyBracket, keyword::kElse, token::kOpenCurlyBracket); - if (expr->isLValue() && !isRValue()) { + if (expr->isLValue() && !isRValue() && !expr->getType()->isFunctionType()) { StrCat(token::kRef, keyword_mut_); } Convert(expr->getFalseExpr()); @@ -2022,35 +2064,23 @@ bool Converter::VisitDeclRefExpr(clang::DeclRefExpr *expr) { return false; } - if (auto function = clang::dyn_cast(decl)) { + if (auto *fn_decl = clang::dyn_cast(decl)) { if (isAddrOf()) { - // Wrap unsafe function in safe closure because the Fn trait only accepts - // safe functions - std::string arguments; - for (unsigned i = 0; i < function->getNumParams(); ++i) { - arguments += (i ? ", a" : "a") + std::to_string(i); - } - StrCat("Rc::new", token::kOpenParen); - StrCat(std::format("|{}|", arguments)); - StrCat(keyword_unsafe_, token::kOpenCurlyBracket); - StrCat(str); - StrCat(token::kOpenParen); - StrCat(arguments); - StrCat(token::kCloseParen); - StrCat(token::kCloseCurlyBracket); - StrCat(token::kCloseParen); + ConvertFunctionToFunctionPointer(fn_decl); return false; } } if (auto var_decl = clang::dyn_cast(decl)) { - if (auto init = var_decl->getInit()) { - if (auto lambda = clang::dyn_cast( - init->IgnoreUnlessSpelledInSource())) { - StrCat(token::kOpenParen); - VisitLambdaExpr(lambda); - StrCat(token::kCloseParen); - return false; + if (!var_decl->getType()->isFunctionPointerType()) { + if (auto init = var_decl->getInit()) { + if (auto lambda = clang::dyn_cast( + init->IgnoreUnlessSpelledInSource())) { + StrCat(token::kOpenParen); + VisitLambdaExpr(lambda); + StrCat(token::kCloseParen); + return false; + } } } } @@ -2509,6 +2539,9 @@ bool Converter::VisitCXXDefaultArgExpr(clang::CXXDefaultArgExpr *expr) { } bool Converter::VisitLambdaExpr(clang::LambdaExpr *expr) { + if (isAddrOf() && expr->capture_size() == 0) { + StrCat("Some"); + } StrCat(token::kOpenParen); StrCat("|"); for (auto p : expr->getLambdaClass()->getLambdaCallOperator()->parameters()) { @@ -2636,23 +2669,10 @@ bool Converter::VisitCXXStdInitializerListExpr( return false; } -std::string -Converter::GetFunctionPointerDefaultAsString(clang::QualType qual_type) { - std::string ret; - auto proto = qual_type->getPointeeType()->getAs(); - assert(proto); - ret = "Rc::new(|"; - for (unsigned i = 0; i < proto->getNumParams(); ++i) { - ret += "_,"; - } - ret += R"(| { panic!("ub: uninit function pointer") }))"; - return ret; -} - std::string Converter::GetDefaultAsString(clang::QualType qual_type) { if (qual_type->isPointerType()) { if (qual_type->getPointeeType()->isFunctionType()) { - return GetFunctionPointerDefaultAsString(qual_type); + return "None"; } else { computed_expr_type_ = ComputedExprType::FreshPointer; return keyword_default_; @@ -2800,6 +2820,16 @@ void Converter::ConvertVarInit(clang::QualType qual_type, clang::Expr *expr) { StrCat(keyword_mut_); } } + if (qual_type->isFunctionPointerType()) { + if (auto *lambda = clang::dyn_cast( + expr->IgnoreUnlessSpelledInSource())) { + PushExprKind push(*this, ExprKind::AddrOf); + curr_init_type_.push(qual_type); + VisitLambdaExpr(lambda); + curr_init_type_.pop(); + return; + } + } auto *ignore_casts = expr->IgnoreCasts(); // FIXME: this looks very complicated if (auto *ctor = clang::dyn_cast(ignore_casts); @@ -2845,7 +2875,8 @@ void Converter::ConvertUnsignedArithOperand(clang::Expr *expr, void Converter::ConvertEqualsNullPtr(clang::Expr *expr) { StrCat("("); Convert(expr); - if (IsUniquePtr(expr->getType())) { + if (IsUniquePtr(expr->getType()) || + expr->getType()->isFunctionPointerType()) { StrCat(").is_none()"); } else { StrCat(").is_null()"); @@ -3229,6 +3260,13 @@ void Converter::PlaceholderCtx::dump() const { std::string Converter::ConvertPlaceholder(clang::Expr *expr, clang::Expr *arg, const PlaceholderCtx &ph_ctx) { + if (arg->getType()->isFunctionPointerType()) { + PushExprKind push(*this, ExprKind::Callee); + Buffer buf(*this); + Convert(arg); + return std::move(buf).str(); + } + if (ph_ctx.needs_materialization()) { auto materialized = ph_ctx.materialize_ctx->GetOrMaterialize( static_cast(ph_ctx.materialize_idx), @@ -3376,6 +3414,10 @@ bool Converter::isVoid() const { return curr_expr_kind_.empty() || curr_expr_kind_.back() == ExprKind::Void; } +bool Converter::isCallee() const { + return !curr_expr_kind_.empty() && curr_expr_kind_.back() == ExprKind::Callee; +} + void Converter::SetFresh() { switch (computed_expr_type_) { case ComputedExprType::Value: diff --git a/cpp2rust/converter/converter.h b/cpp2rust/converter/converter.h index b2908fd0..6f2c3719 100644 --- a/cpp2rust/converter/converter.h +++ b/cpp2rust/converter/converter.h @@ -61,7 +61,11 @@ class Converter : public clang::RecursiveASTVisitor { virtual bool VisitPointerType(clang::PointerType *type); - void ConvertFunctionPointerType(clang::PointerType *type); + enum class FnProtoType { LambdaCallOperator, FnPtr }; + + virtual std::string + ConvertFunctionPointerType(const clang::FunctionProtoType *proto, + FnProtoType kind = FnProtoType::FnPtr); virtual bool VisitDecayedType(clang::DecayedType *type); @@ -201,6 +205,11 @@ class Converter : public clang::RecursiveASTVisitor { void ConvertGenericCallExpr(clang::CallExpr *expr); + virtual void EmitFnPtrCall(clang::Expr *callee); + + virtual void + ConvertFunctionToFunctionPointer(const clang::FunctionDecl *fn_decl); + virtual void ConvertPrintf(clang::CallExpr *expr); void ConvertVAArgCall(clang::CallExpr *expr); @@ -334,8 +343,6 @@ class Converter : public clang::RecursiveASTVisitor { virtual bool Convert(clang::Stmt *stmt); virtual bool Convert(clang::Expr *expr); - std::string GetFunctionPointerDefaultAsString(clang::QualType qual_type); - virtual std::string GetDefaultAsString(clang::QualType qual_type); virtual std::string GetDefaultAsStringFallback(clang::QualType qual_type); @@ -472,6 +479,7 @@ class Converter : public clang::RecursiveASTVisitor { static std::unordered_set abstract_structs_; enum class ExprKind : uint8_t { + Callee, LValue, RValue, XValue, @@ -482,6 +490,8 @@ class Converter : public clang::RecursiveASTVisitor { static const char *expr_kind_to_string(ExprKind kind) { switch (kind) { + case ExprKind::Callee: + return "Callee"; case ExprKind::LValue: return "LValue"; case ExprKind::RValue: @@ -505,6 +515,7 @@ class Converter : public clang::RecursiveASTVisitor { bool isAddrOf() const; bool isObject() const; bool isVoid() const; + bool isCallee() const; void dump_expr_kinds(); diff --git a/cpp2rust/converter/converter_lib.cpp b/cpp2rust/converter/converter_lib.cpp index 3f515788..4afa3140 100644 --- a/cpp2rust/converter/converter_lib.cpp +++ b/cpp2rust/converter/converter_lib.cpp @@ -362,18 +362,18 @@ const char *AccessSpecifierAsString(clang::AccessSpecifier spec) { } clang::QualType GetReturnTypeOfFunction(const clang::CallExpr *expr) { - auto decl = expr->getCalleeDecl(); - if (decl->getAsFunction()) { - return decl->getAsFunction()->getReturnType().getCanonicalType(); - } - - auto callee_ty = - expr->getCallee()->getType().getDesugaredType(decl->getASTContext()); - if (auto ptr_ty = callee_ty->getAs()) { - return ptr_ty->getPointeeType() - ->getAs() - ->getReturnType() - .getCanonicalType(); + if (auto *decl = expr->getCalleeDecl()) { + if (auto *fn = decl->getAsFunction()) { + return fn->getReturnType().getCanonicalType(); + } + } + + auto callee_ty = expr->getCallee()->getType(); + if (auto *ptr_ty = callee_ty->getAs()) { + if (auto *fn_ty = + ptr_ty->getPointeeType()->getAs()) { + return fn_ty->getReturnType().getCanonicalType(); + } } assert(0 && "Unhandled function prototype"); diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index e9f397ca..1a31c84e 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -165,10 +165,70 @@ bool ConverterRefCount::VisitLValueReferenceType( return false; } +std::string ConverterRefCount::BuildFnAdapter( + const clang::FunctionDecl *src_fn, + const clang::FunctionProtoType *src_proto, + const clang::FunctionProtoType *target_proto) { + + // UB: Incompatible arity + if (src_proto->getNumParams() != target_proto->getNumParams()) { + return "None"; + } + + PushConversionKind push(*this, ConversionKind::Unboxed); + + // Build adapter signature: |a0: T0, a1: T1, ...| -> Tr + std::string closure = "(|"; + for (unsigned i = 0; i < target_proto->getNumParams(); ++i) { + closure += + std::format("a{}: {},", i, ToString(target_proto->getParamType(i))); + } + closure += "|"; + if (!target_proto->getReturnType()->isVoidType()) { + closure += std::format(" -> {} ", ToString(target_proto->getReturnType())); + } + closure += "{ "; + + // Build adapter body: src_fn(convert(a0), convert(a1), ...) + closure += GetNamedDeclAsString(src_fn) + "("; + for (unsigned i = 0; i < src_proto->getNumParams(); ++i) { + auto src_pty = src_proto->getParamType(i); + auto tgt_pty = target_proto->getParamType(i); + if (ToString(src_pty) == ToString(tgt_pty)) { + closure += std::format("a{}", i); + } else if (src_pty->isPointerType() && tgt_pty->isPointerType()) { + if (tgt_pty->isVoidPointerType()) { + closure += std::format("a{}.cast::<{}>().unwrap()", i, + ToString(src_pty->getPointeeType())); + } else if (src_pty->isVoidPointerType()) { + closure += std::format("a{}.to_any()", i); + } else if (tgt_pty->getPointeeType()->isCharType()) { + closure += std::format("a{}.reinterpret_cast::<{}>()", i, + ToString(src_pty->getPointeeType())); + } else if (src_pty->getPointeeType()->isCharType()) { + closure += std::format("a{}.reinterpret_cast::()", i); + } + } else { + // UB: Incompatible types + return "None"; + } + closure += ", "; + } + closure += ") })"; + + return std::format("Some({} as {})", closure, + ConvertFunctionPointerType(target_proto)); +} + +std::string ConverterRefCount::ConvertFunctionPointerType( + const clang::FunctionProtoType *proto, FnProtoType kind) { + PushConversionKind push(*this, ConversionKind::Unboxed); + return Converter::ConvertFunctionPointerType(proto, kind); +} + bool ConverterRefCount::VisitPointerType(clang::PointerType *type) { - if (type->getPointeeType()->getAs()) { - PushConversionKind push(*this, ConversionKind::Unboxed); - ConvertFunctionPointerType(type); + if (auto proto = type->getPointeeType()->getAs()) { + StrCat(std::format("FnPtr<{}>", ConvertFunctionPointerType(proto))); return false; } @@ -568,9 +628,9 @@ bool ConverterRefCount::VisitDeclRefExpr(clang::DeclRefExpr *expr) { auto str = ConvertDeclRefExpr(expr); auto decl = expr->getDecl(); - if (clang::isa(decl)) { + if (auto fn_decl = clang::dyn_cast(decl)) { if (isAddrOf()) { - StrCat(std::format("Rc::new({})", str)); + ConvertFunctionToFunctionPointer(fn_decl); } else { StrCat(str); } @@ -951,9 +1011,83 @@ bool ConverterRefCount::VisitImplicitCastExpr(clang::ImplicitCastExpr *expr) { } } + if (expr->getCastKind() == clang::CastKind::CK_NullToPointer && + expr->getType()->isFunctionPointerType()) { + StrCat("FnPtr::null()"); + computed_expr_type_ = ComputedExprType::FreshPointer; + return false; + } + return Converter::VisitImplicitCastExpr(expr); } +void ConverterRefCount::EmitFnPtrCall(clang::Expr *callee) { + StrCat("(*"); + Convert(callee); + StrCat(")"); +} + +void ConverterRefCount::ConvertFunctionToFunctionPointer( + const clang::FunctionDecl *fn_decl) { + StrCat(std::format("FnPtr::<{}>::new({})", + ConvertFunctionPointerType( + fn_decl->getType()->getAs()), + GetNamedDeclAsString(fn_decl))); +} + +void ConverterRefCount::ConvertEqualsNullPtr(clang::Expr *expr) { + StrCat("("); + Convert(expr); + StrCat(").is_null()"); +} + +bool ConverterRefCount::VisitFunctionPointerCast( + clang::ExplicitCastExpr *expr) { + if (expr->getType()->isFunctionPointerType() || + expr->getSubExpr()->getType()->isFunctionPointerType()) { + if (expr->getSubExpr()->getType()->isFunctionPointerType() && + expr->getType()->isFunctionPointerType()) { + auto target_proto = + expr->getType()->getPointeeType()->getAs(); + auto src_proto = expr->getSubExpr() + ->getType() + ->getPointeeType() + ->getAs(); + auto fn_type = ConvertFunctionPointerType(target_proto); + + std::string adapter = "None"; + // Only accept direct references to the casted function. Otherwise the + // closure would be capturing and would not coerce into a fn pointer. + if (auto *decl_ref = clang::dyn_cast( + expr->getSubExpr()->IgnoreImplicit())) { + if (auto *fn_decl = + clang::dyn_cast(decl_ref->getDecl())) { + adapter = BuildFnAdapter(fn_decl, src_proto, target_proto); + } + } + + StrCat(std::format("{}.cast::<{}>({})", ToString(expr->getSubExpr()), + fn_type, adapter)); + } else if (expr->getSubExpr()->getType()->isFunctionPointerType() || + expr->getType()->isVoidPointerType()) { + Convert(expr->getSubExpr()); + StrCat(".to_any()"); + } else if (expr->getSubExpr()->getType()->isVoidPointerType() || + expr->getType()->isFunctionPointerType()) { + auto target_proto = + expr->getType()->getPointeeType()->getAs(); + auto fn_type = ConvertFunctionPointerType(target_proto); + StrCat(std::format("{}.cast_fn::<{}>().expect(\"ub:wrong fn type\")", + ToString(expr->getSubExpr()), fn_type)); + } else { + assert(0 && "Unhandled function pointer cast"); + } + return false; + } + + return true; +} + bool ConverterRefCount::VisitExplicitCastExpr(clang::ExplicitCastExpr *expr) { if (expr->getTypeAsWritten()->isVoidType()) { return false; @@ -968,7 +1102,9 @@ bool ConverterRefCount::VisitExplicitCastExpr(clang::ExplicitCastExpr *expr) { return false; case clang::Stmt::CStyleCastExprClass: case clang::Stmt::CXXStaticCastExprClass: - if (expr->getSubExpr()->getType()->isVoidPointerType()) { + if (!VisitFunctionPointerCast(expr)) { + return false; + } else if (expr->getSubExpr()->getType()->isVoidPointerType()) { Convert(expr->getSubExpr()); PushConversionKind push(*this, ConversionKind::Unboxed); StrCat(std::format(".cast::<{}>().expect(\"ub:wrong type\")", @@ -1412,7 +1548,7 @@ std::string ConverterRefCount::GetDefaultAsString(clang::QualType qual_type) { if (qual_type->isPointerType()) { auto pointee_type = qual_type->getPointeeType(); if (pointee_type->isFunctionType()) { - ret = GetFunctionPointerDefaultAsString(qual_type); + ret = "FnPtr::null()"; } else { if (pointee_type->isVoidType()) { ret = "AnyPtr::default()"; @@ -1477,9 +1613,13 @@ void ConverterRefCount::ConvertVarInit(clang::QualType qual_type, { Buffer buf(*this); PushConversionKind push(*this, ConversionKind::Unboxed); - StrCat("Rc::new("); - VisitLambdaExpr(lambda); - StrCat(")"); + if (qual_type->isFunctionPointerType() && lambda->capture_size() == 0) { + StrCat("FnPtr::new("); + VisitLambdaExpr(lambda); + StrCat(")"); + } else { + VisitLambdaExpr(lambda); + } str = std::move(buf).str(); } StrCat(BoxValue(std::move(str))); diff --git a/cpp2rust/converter/models/converter_refcount.h b/cpp2rust/converter/models/converter_refcount.h index 81025901..e986a266 100644 --- a/cpp2rust/converter/models/converter_refcount.h +++ b/cpp2rust/converter/models/converter_refcount.h @@ -22,6 +22,10 @@ class ConverterRefCount final : public Converter { bool VisitPointerType(clang::PointerType *type) override; + std::string + ConvertFunctionPointerType(const clang::FunctionProtoType *proto, + FnProtoType kind = FnProtoType::FnPtr) override; + bool VisitCXXRecordDecl(clang::CXXRecordDecl *decl) override; void ConvertOrdAndPartialOrdTraits(const clang::CXXRecordDecl *decl, @@ -59,12 +63,19 @@ class ConverterRefCount final : public Converter { void ConvertPrintf(clang::CallExpr *expr) override; + void EmitFnPtrCall(clang::Expr *callee) override; + + void + ConvertFunctionToFunctionPointer(const clang::FunctionDecl *fn_decl) override; + bool VisitCallExpr(clang::CallExpr *expr) override; bool VisitStringLiteral(clang::StringLiteral *expr) override; bool VisitImplicitCastExpr(clang::ImplicitCastExpr *expr) override; + bool VisitFunctionPointerCast(clang::ExplicitCastExpr *expr); + bool VisitExplicitCastExpr(clang::ExplicitCastExpr *expr) override; bool VisitBinaryOperator(clang::BinaryOperator *expr) override; @@ -103,6 +114,8 @@ class ConverterRefCount final : public Converter { std::string GetDefaultAsString(clang::QualType qual_type) override; + void ConvertEqualsNullPtr(clang::Expr *expr) override; + std::string GetDefaultAsStringFallback(clang::QualType qual_type) override; std::string ConvertVarDefaultInit(clang::QualType qual_type) override; @@ -171,6 +184,10 @@ class ConverterRefCount final : public Converter { const char *GetPointerDerefSuffix(clang::QualType pointee_type); const char *GetPointerDerefPrefix(clang::QualType pointee_type) override; + std::string BuildFnAdapter(const clang::FunctionDecl *src_fn, + const clang::FunctionProtoType *src_proto, + const clang::FunctionProtoType *target_proto); + void EmitSetOrAssign(clang::Expr *lhs, std::string_view rhs); // Wraps a pointer expression with deref prefix/suffix: e.g. diff --git a/libcc2rs/src/fn_ptr.rs b/libcc2rs/src/fn_ptr.rs new file mode 100644 index 00000000..2ccc150e --- /dev/null +++ b/libcc2rs/src/fn_ptr.rs @@ -0,0 +1,181 @@ +// Copyright (c) 2022-present INESC-ID. +// Distributed under the MIT license that can be found in the LICENSE file. + +use std::any::{Any, TypeId}; +use std::marker::PhantomData; +use std::ops::Deref; +use std::rc::Rc; + +use crate::rc::{AnyPtr, ErasedPtr}; +use crate::reinterpret::ByteRepr; + +pub trait FnAddr { + fn fn_addr(&self) -> usize; +} + +macro_rules! impl_fn_addr { + () => { + impl_fn_addr!(@gen A B C D E F G H I J); + }; + (@gen $($a:ident)*) => { + impl FnAddr for fn($($a,)*) -> R { + #[inline] + fn fn_addr(&self) -> usize { *self as *const () as usize } + } + impl_fn_addr!(@peel $($a)*); + }; + (@peel) => {}; + (@peel $head:ident $($tail:ident)*) => { + impl_fn_addr!(@gen $($tail)*); + }; +} +impl_fn_addr!(); + +trait ErasedFn: Any { + fn addr(&self) -> usize; +} + +impl ErasedFn for T { + fn addr(&self) -> usize { + self.fn_addr() + } +} + +pub struct FnPtr { + original: Option>, + current_cast: Option>, + // FnPtr does not use T, hence wrap in PhantomData + _marker: PhantomData, +} + +impl FnPtr { + #[inline] + pub fn null() -> Self { + FnPtr { + original: None, + current_cast: None, + _marker: PhantomData, + } + } + + #[inline] + pub fn is_null(&self) -> bool { + self.original.is_none() + } +} + +impl FnPtr { + pub fn new(f: T) -> Self { + let rc: Rc = Rc::new(f); + FnPtr { + original: Some(rc.clone()), + current_cast: Some(rc), + _marker: PhantomData, + } + } +} + +impl FnPtr { + pub fn cast(&self, adapter: Option) -> FnPtr { + let original = self.original.as_ref().expect("ub: null fn pointer cast"); + + let current_cast = if self + .current_cast + .as_ref() + .is_some_and(|rc| Any::type_id(&**rc) == TypeId::of::()) + { + self.current_cast.clone() + } else if Any::type_id(&**original) == TypeId::of::() { + Some(original.clone()) + } else { + adapter.map(|a| Rc::new(a) as Rc) + }; + + FnPtr { + original: Some(original.clone()), + current_cast, + _marker: PhantomData, + } + } +} + +impl Deref for FnPtr { + type Target = T; + fn deref(&self) -> &T { + if self.original.is_none() { + panic!("ub: null fn pointer call"); + } + let rc = self + .current_cast + .as_ref() + .expect("ub: calling through incompatible fn pointer type"); + let any: &dyn Any = &**rc; + any.downcast_ref::() + .expect("ub: fn pointer type mismatch") + } +} + +impl Clone for FnPtr { + fn clone(&self) -> Self { + FnPtr { + original: self.original.clone(), + current_cast: self.current_cast.clone(), + _marker: PhantomData, + } + } +} + +impl Default for FnPtr { + fn default() -> Self { + Self::null() + } +} + +impl PartialEq for FnPtr { + fn eq(&self, other: &Self) -> bool { + match (&self.original, &other.original) { + (None, None) => true, + (Some(a), Some(b)) => a.addr() == b.addr(), + _ => false, + } + } +} + +impl Eq for FnPtr {} + +impl ByteRepr for FnPtr {} + +impl ErasedPtr for FnPtr { + fn pointee_type_id(&self) -> TypeId { + TypeId::of::() + } + fn memcpy(&self, _src: &dyn ErasedPtr, _len: usize) { + panic!("memcpy not supported on fn pointer"); + } + fn as_any(&self) -> &dyn Any { + self + } + fn equals(&self, other: &dyn ErasedPtr) -> Option { + if self.pointee_type_id() != other.pointee_type_id() { + return None; + } + other.as_any().downcast_ref::>().map(|o| self == o) + } + fn is_null(&self) -> bool { + FnPtr::is_null(self) + } +} + +impl FnPtr { + pub fn to_any(&self) -> AnyPtr { + AnyPtr { + ptr: Rc::new(self.clone()), + } + } +} + +impl AnyPtr { + pub fn cast_fn(&self) -> Option> { + self.ptr.as_any().downcast_ref::>().cloned() + } +} diff --git a/libcc2rs/src/lib.rs b/libcc2rs/src/lib.rs index 42eb4117..1271b941 100644 --- a/libcc2rs/src/lib.rs +++ b/libcc2rs/src/lib.rs @@ -7,6 +7,9 @@ pub use reinterpret::ByteRepr; mod rc; pub use rc::*; +mod fn_ptr; +pub use fn_ptr::FnPtr; + mod inc; pub use inc::*; diff --git a/libcc2rs/src/rc.rs b/libcc2rs/src/rc.rs index e02e9626..a6242080 100644 --- a/libcc2rs/src/rc.rs +++ b/libcc2rs/src/rc.rs @@ -1004,7 +1004,7 @@ impl Ptr { } } -trait ErasedPtr: std::any::Any { +pub(crate) trait ErasedPtr: std::any::Any { fn pointee_type_id(&self) -> std::any::TypeId; fn memcpy(&self, src: &dyn ErasedPtr, len: usize); fn as_any(&self) -> &dyn std::any::Any; @@ -1057,7 +1057,7 @@ where #[derive(Clone)] pub struct AnyPtr { - ptr: Rc, + pub(crate) ptr: Rc, } impl Ptr { diff --git a/tests/ub/out/refcount/dangling-prvalue-as-lvalue.rs b/tests/ub/out/refcount/dangling-prvalue-as-lvalue.rs index c5ffd859..fd03296b 100644 --- a/tests/ub/out/refcount/dangling-prvalue-as-lvalue.rs +++ b/tests/ub/out/refcount/dangling-prvalue-as-lvalue.rs @@ -17,7 +17,7 @@ fn main_0() -> i32 { let v: Value> = Rc::new(RefCell::new(vec![1, 2])); let b: Ptr = ({ let _a: Ptr = (v.as_pointer() as Ptr); - Rc::new(foo_0)(_a) + foo_0(_a) }); (*v.borrow_mut()).clear(); return (b.read()); diff --git a/tests/ub/out/refcount/ub1.rs b/tests/ub/out/refcount/ub1.rs index 0b4feefa..e525fce8 100644 --- a/tests/ub/out/refcount/ub1.rs +++ b/tests/ub/out/refcount/ub1.rs @@ -16,6 +16,6 @@ pub fn main() { std::process::exit(main_0()); } fn main_0() -> i32 { - let x: Ptr = ({ Rc::new(dangling_0)() }); + let x: Ptr = ({ dangling_0() }); return (x.read()); } diff --git a/tests/ub/out/unsafe/dangling-prvalue-as-lvalue.rs b/tests/ub/out/unsafe/dangling-prvalue-as-lvalue.rs index 11ddb63f..eeaa1d9b 100644 --- a/tests/ub/out/unsafe/dangling-prvalue-as-lvalue.rs +++ b/tests/ub/out/unsafe/dangling-prvalue-as-lvalue.rs @@ -19,7 +19,7 @@ unsafe fn main_0() -> i32 { let mut v: Vec = vec![1, 2]; let b: *const i32 = (unsafe { let _a: *const i32 = &(*v.as_mut_ptr()) as *const i32; - Rc::new(|a0| unsafe { foo_0(a0) })(_a) + foo_0(_a) }); v.clear(); return (*b); diff --git a/tests/ub/out/unsafe/ub1.rs b/tests/ub/out/unsafe/ub1.rs index bc49a90c..002d9c72 100644 --- a/tests/ub/out/unsafe/ub1.rs +++ b/tests/ub/out/unsafe/ub1.rs @@ -18,6 +18,6 @@ pub fn main() { } } unsafe fn main_0() -> i32 { - let x: *mut i32 = (unsafe { Rc::new(|| unsafe { dangling_0() })() }); + let x: *mut i32 = (unsafe { dangling_0() }); return (*x); } diff --git a/tests/unit/fn_ptr.cpp b/tests/unit/fn_ptr.cpp new file mode 100644 index 00000000..0706e7d8 --- /dev/null +++ b/tests/unit/fn_ptr.cpp @@ -0,0 +1,24 @@ +// Copyright (c) 2022-present INESC-ID. +// Distributed under the MIT license that can be found in the LICENSE file. + +#include + +typedef int (*foo_t)(void *); + +int my_foo(void *p) { return *static_cast(p); } + +int foo(foo_t fn, int *pi) { return fn(pi); } + +int main() { + foo_t fn = nullptr; + assert(fn == nullptr); + assert(fn != my_foo); + + fn = my_foo; + assert(fn != nullptr); + assert(fn == my_foo); + + int a = 10; + assert(foo(fn, &a) == a); + return 0; +} diff --git a/tests/unit/fn_ptr_array.cpp b/tests/unit/fn_ptr_array.cpp new file mode 100644 index 00000000..ef6f335d --- /dev/null +++ b/tests/unit/fn_ptr_array.cpp @@ -0,0 +1,24 @@ +// Copyright (c) 2022-present INESC-ID. +// Distributed under the MIT license that can be found in the LICENSE file. + +#include + +typedef int (*op_t)(int, int); + +int add(int a, int b) { return a + b; } +int sub(int a, int b) { return a - b; } +int mul(int a, int b) { return a * b; } + +int main() { + op_t ops[3] = {add, sub, mul}; + + assert(ops[0](2, 3) == 5); + assert(ops[1](7, 4) == 3); + assert(ops[2](6, 5) == 30); + + assert(ops[0] != nullptr); + assert(ops[0] == add); + assert(ops[0] != sub); + + return 0; +} diff --git a/tests/unit/fn_ptr_as_condition.cpp b/tests/unit/fn_ptr_as_condition.cpp new file mode 100644 index 00000000..be74365d --- /dev/null +++ b/tests/unit/fn_ptr_as_condition.cpp @@ -0,0 +1,36 @@ +// Copyright (c) 2022-present INESC-ID. +// Distributed under the MIT license that can be found in the LICENSE file. + +#include + +typedef void (*callback_t)(int *); + +void double_it(int *x) { *x *= 2; } + +void maybe_call(callback_t cb, int *x) { + if (cb) { + cb(x); + } +} + +int main() { + int a = 5; + maybe_call(double_it, &a); + assert(a == 10); + + int b = 5; + maybe_call(nullptr, &b); + assert(b == 5); + + callback_t fn = nullptr; + if (!fn) { + fn = double_it; + } + int c = 3; + if (fn) { + fn(&c); + } + assert(c == 6); + + return 0; +} diff --git a/tests/unit/fn_ptr_cast.cpp b/tests/unit/fn_ptr_cast.cpp new file mode 100644 index 00000000..eb5c5abf --- /dev/null +++ b/tests/unit/fn_ptr_cast.cpp @@ -0,0 +1,59 @@ +// Copyright (c) 2022-present INESC-ID. +// Distributed under the MIT license that can be found in the LICENSE file. + +#include + +typedef void (*generic_fn)(void); +typedef int (*int_fn)(int); + +int double_it(int x) { return x * 2; } + +void test_roundtrip() { + int_fn fn = double_it; + assert(fn(5) == 10); + + generic_fn gfn = (generic_fn)fn; + assert(gfn != nullptr); + + int_fn fn2 = (int_fn)gfn; + assert(fn2(5) == 10); + assert(fn2 == fn); +} + +void test_double_cast() { + int_fn fn = double_it; + int_fn fn2 = (int_fn)(generic_fn)fn; + assert(fn2(5) == 10); + assert(fn2 == fn); +} + +struct Command { + void *data; +}; + +void test_void_ptr_to_fn() { + Command cmd; + cmd.data = (void *)double_it; + + int_fn fn = (int_fn)cmd.data; + assert(fn(5) == 10); +} + +typedef int (*generic_int_fn)(void *, int); + +int add_offset(int *base, int offset) { return *base + offset; } + +void test_call_through_cast() { + generic_int_fn gfn = (generic_int_fn)add_offset; + int val = 100; + int result = gfn(&val, 42); + assert(result == 142); +} + +int main() { + test_roundtrip(); + test_double_cast(); + test_void_ptr_to_fn(); + test_call_through_cast(); + return 0; +} diff --git a/tests/unit/fn_ptr_conditional.cpp b/tests/unit/fn_ptr_conditional.cpp new file mode 100644 index 00000000..343eaeda --- /dev/null +++ b/tests/unit/fn_ptr_conditional.cpp @@ -0,0 +1,28 @@ +// Copyright (c) 2022-present INESC-ID. +// Distributed under the MIT license that can be found in the LICENSE file. + +#include + +typedef int (*op_t)(int); + +int inc(int x) { return x + 1; } +int dec(int x) { return x - 1; } +int identity(int x) { return x; } + +op_t pick(int mode) { return mode > 0 ? inc : mode < 0 ? dec : identity; } + +int apply(op_t fn, int x) { + op_t actual = fn ? fn : identity; + return actual(x); +} + +int main() { + assert(pick(1)(10) == 11); + assert(pick(-1)(10) == 9); + assert(pick(0)(10) == 10); + + assert(apply(inc, 5) == 6); + assert(apply(nullptr, 5) == 5); + + return 0; +} diff --git a/tests/unit/fn_ptr_default_arg.cpp b/tests/unit/fn_ptr_default_arg.cpp new file mode 100644 index 00000000..c5d659eb --- /dev/null +++ b/tests/unit/fn_ptr_default_arg.cpp @@ -0,0 +1,26 @@ +// Copyright (c) 2022-present INESC-ID. +// Distributed under the MIT license that can be found in the LICENSE file. + +#include + +typedef int (*transform_t)(int); + +int identity(int x) { return x; } + +int apply(int x, transform_t fn = nullptr) { + if (fn) { + return fn(x); + } + return x; +} + +int main() { + assert(apply(5) == 5); + assert(apply(5, nullptr) == 5); + assert(apply(5, identity) == 5); + + transform_t negate = [](int x) { return -x; }; + assert(apply(5, negate) == -5); + + return 0; +} diff --git a/tests/unit/fn_ptr_global.cpp b/tests/unit/fn_ptr_global.cpp new file mode 100644 index 00000000..034e2c2b --- /dev/null +++ b/tests/unit/fn_ptr_global.cpp @@ -0,0 +1,39 @@ +// Copyright (c) 2022-present INESC-ID. +// Distributed under the MIT license that can be found in the LICENSE file. + +#include + +typedef int (*op_t)(int); + +int double_it(int x) { return x * 2; } +int triple_it(int x) { return x * 3; } + +static op_t g_op = nullptr; + +void set_op(op_t fn) { g_op = fn; } + +int call_op(int x) { + if (g_op) { + return g_op(x); + } + return x; +} + +int main() { + assert(call_op(5) == 5); + + set_op(double_it); + assert(g_op != nullptr); + assert(g_op == double_it); + assert(call_op(5) == 10); + + set_op(triple_it); + assert(g_op == triple_it); + assert(call_op(5) == 15); + + set_op(nullptr); + assert(g_op == nullptr); + assert(call_op(5) == 5); + + return 0; +} diff --git a/tests/unit/fn_ptr_reassign.cpp b/tests/unit/fn_ptr_reassign.cpp new file mode 100644 index 00000000..ecb1af3e --- /dev/null +++ b/tests/unit/fn_ptr_reassign.cpp @@ -0,0 +1,30 @@ +// Copyright (c) 2022-present INESC-ID. +// Distributed under the MIT license that can be found in the LICENSE file. + +#include + +typedef int (*op_t)(int, int); + +int add(int a, int b) { return a + b; } +int sub(int a, int b) { return a - b; } +int mul(int a, int b) { return a * b; } + +int main() { + op_t fn = add; + assert(fn(3, 4) == 7); + + fn = sub; + assert(fn(10, 3) == 7); + + fn = mul; + assert(fn(6, 7) == 42); + + fn = nullptr; + assert(fn == nullptr); + + fn = add; + assert(fn != nullptr); + assert(fn(1, 1) == 2); + + return 0; +} diff --git a/tests/unit/fn_ptr_return.cpp b/tests/unit/fn_ptr_return.cpp new file mode 100644 index 00000000..4112b6b0 --- /dev/null +++ b/tests/unit/fn_ptr_return.cpp @@ -0,0 +1,30 @@ +// Copyright (c) 2022-present INESC-ID. +// Distributed under the MIT license that can be found in the LICENSE file. + +#include + +typedef int (*op_t)(int); + +int inc(int x) { return x + 1; } +int dec(int x) { return x - 1; } + +op_t pick(int choose_inc) { + if (choose_inc) { + return inc; + } + return dec; +} + +int main() { + op_t f = pick(1); + assert(f != nullptr); + assert(f == inc); + assert(f(10) == 11); + + op_t g = pick(0); + assert(g == dec); + assert(g(10) == 9); + + assert(f != g); + return 0; +} diff --git a/tests/unit/fn_ptr_stable_sort.cpp b/tests/unit/fn_ptr_stable_sort.cpp new file mode 100644 index 00000000..16b0f31f --- /dev/null +++ b/tests/unit/fn_ptr_stable_sort.cpp @@ -0,0 +1,28 @@ +// Copyright (c) 2022-present INESC-ID. +// Distributed under the MIT license that can be found in the LICENSE file. + +#include +#include +#include + +struct Item { + int key; + int value; +}; + +static bool Compare(const Item &a, const Item &b) { return a.key < b.key; } + +int main() { + std::vector v; + v.push_back({3, 30}); + v.push_back({1, 10}); + v.push_back({2, 20}); + + std::stable_sort(v.begin(), v.end(), Compare); + + assert(v[0].key == 1); + assert(v[1].key == 2); + assert(v[2].key == 3); + + return 0; +} diff --git a/tests/unit/fn_ptr_struct.cpp b/tests/unit/fn_ptr_struct.cpp new file mode 100644 index 00000000..ccfa106d --- /dev/null +++ b/tests/unit/fn_ptr_struct.cpp @@ -0,0 +1,29 @@ +// Copyright (c) 2022-present INESC-ID. +// Distributed under the MIT license that can be found in the LICENSE file. + +#include + +typedef int (*handler_t)(int); + +struct Handler { + int tag; + handler_t cb; +}; + +int double_it(int x) { return x * 2; } +int negate(int x) { return -x; } + +int main() { + Handler h1 = {1, double_it}; + Handler h2 = {2, negate}; + + assert(h1.cb != nullptr); + assert(h1.cb(5) == 10); + assert(h2.cb(7) == -7); + + h1.cb = negate; + assert(h1.cb(3) == -3); + assert(h1.cb == h2.cb); + + return 0; +} diff --git a/tests/unit/fn_ptr_void_return.cpp b/tests/unit/fn_ptr_void_return.cpp new file mode 100644 index 00000000..bcd3fed4 --- /dev/null +++ b/tests/unit/fn_ptr_void_return.cpp @@ -0,0 +1,28 @@ +// Copyright (c) 2022-present INESC-ID. +// Distributed under the MIT license that can be found in the LICENSE file. + +#include + +typedef void (*action_t)(int *); + +void negate(int *x) { *x = -*x; } +void zero_out(int *x) { *x = 0; } + +void run(action_t fn, int *x) { fn(x); } + +int main() { + int a = 42; + run(negate, &a); + assert(a == -42); + + run(zero_out, &a); + assert(a == 0); + + action_t fn = negate; + assert(fn != nullptr); + int b = 10; + fn(&b); + assert(b == -10); + + return 0; +} diff --git a/tests/unit/fn_ptr_vtable.cpp b/tests/unit/fn_ptr_vtable.cpp new file mode 100644 index 00000000..6a75da96 --- /dev/null +++ b/tests/unit/fn_ptr_vtable.cpp @@ -0,0 +1,44 @@ +// Copyright (c) 2022-present INESC-ID. +// Distributed under the MIT license that can be found in the LICENSE file. + +#include + +typedef void *(*create_fn)(int); +typedef int (*get_fn)(void *); +typedef void (*destroy_fn)(void *); + +struct Vtable { + create_fn create; + get_fn get; + destroy_fn destroy; +}; + +static int storage; + +void *int_create(int val) { + storage = val; + return &storage; +} + +int int_get(void *p) { return *(int *)p; } + +void int_destroy(void *p) { *(int *)p = 0; } + +int main() { + Vtable vt = {int_create, int_get, int_destroy}; + + assert(vt.create != nullptr); + assert(vt.get != nullptr); + assert(vt.destroy != nullptr); + + void *obj = vt.create(42); + assert(vt.get(obj) == 42); + + vt.destroy(obj); + assert(storage == 0); + + vt.get = nullptr; + assert(vt.get == nullptr); + + return 0; +} diff --git a/tests/unit/lambda_capture_pass.cpp b/tests/unit/lambda_capture_pass.cpp new file mode 100644 index 00000000..d9b2a05e --- /dev/null +++ b/tests/unit/lambda_capture_pass.cpp @@ -0,0 +1,22 @@ +// Copyright (c) 2022-present INESC-ID. +// Distributed under the MIT license that can be found in the LICENSE file. + +#include + +template int apply(F fn, int x) { return fn(x); } + +int main() { + int base = 10; + + auto add_base = [&base](int x) { return x + base; }; + assert(apply(add_base, 5) == 15); + + base = 100; + assert(apply(add_base, 5) == 105); + + int factor = 3; + auto scale = [factor](int x) { return x * factor; }; + assert(apply(scale, 4) == 12); + + return 0; +} diff --git a/tests/unit/lambda_nested.cpp b/tests/unit/lambda_nested.cpp new file mode 100644 index 00000000..14b0287b --- /dev/null +++ b/tests/unit/lambda_nested.cpp @@ -0,0 +1,20 @@ +// Copyright (c) 2022-present INESC-ID. +// Distributed under the MIT license that can be found in the LICENSE file. + +#include + +int main() { + int x = 10; + + auto outer = [&x](int y) { + auto inner = [&x, y](int z) { return x + y + z; }; + return inner(1); + }; + + assert(outer(20) == 31); + + x = 100; + assert(outer(20) == 121); + + return 0; +} diff --git a/tests/unit/out/refcount/complex_function.rs b/tests/unit/out/refcount/complex_function.rs index 7a7c2038..2d778ae7 100644 --- a/tests/unit/out/refcount/complex_function.rs +++ b/tests/unit/out/refcount/complex_function.rs @@ -133,11 +133,11 @@ fn main_0() -> i32 { let r1: Ptr = x1.as_pointer(); let r2: Ptr = ({ let _x: Ptr = x1.as_pointer(); - Rc::new(bar_2)(_x) + bar_2(_x) }); let r3: Ptr = ({ let _x: Ptr = (r1).clone(); - Rc::new(bar_2)(_x) + bar_2(_x) }); let __rhs = (*x1.borrow()); { @@ -403,7 +403,7 @@ fn main_0() -> i32 { .deref()) .v .as_pointer()); - Rc::new(ptr_1)(_x) + ptr_1(_x) }) .clone(); let __tmp = __ptr.read() + 1; @@ -436,7 +436,7 @@ fn main_0() -> i32 { .deref()) .v .as_pointer()); - Rc::new(ptr_1)(_x) + ptr_1(_x) }); let ptr3: Value> = Rc::new(RefCell::new( ({ @@ -450,7 +450,7 @@ fn main_0() -> i32 { .deref()) .v .as_pointer()); - Rc::new(ptr_1)(_x) + ptr_1(_x) }), )); let vptr: Value = Rc::new(RefCell::new( @@ -481,7 +481,7 @@ fn main_0() -> i32 { .deref()) .v .as_pointer(); - Rc::new(bar_2)(_x) + bar_2(_x) }), )); ({ @@ -495,7 +495,7 @@ fn main_0() -> i32 { .deref()) .v .as_pointer(); - Rc::new(bar_2)(_x) + bar_2(_x) }) .with_mut(|__v| __v.postfix_inc()); return (((({ diff --git a/tests/unit/out/refcount/fn_ptr.rs b/tests/unit/out/refcount/fn_ptr.rs new file mode 100644 index 00000000..ee8e5002 --- /dev/null +++ b/tests/unit/out/refcount/fn_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::Seek; +use std::io::{Read, Write}; +use std::os::fd::AsFd; +use std::rc::{Rc, Weak}; +pub fn my_foo_0(p: AnyPtr) -> i32 { + let p: Value = Rc::new(RefCell::new(p)); + return ((*p.borrow()).cast::().expect("ub:wrong type").read()); +} +pub fn foo_1(fn_: FnPtr i32>, pi: Ptr) -> i32 { + let fn_: Value i32>> = Rc::new(RefCell::new(fn_)); + let pi: Value> = Rc::new(RefCell::new(pi)); + return ({ + let _arg0: AnyPtr = ((*pi.borrow()).clone() as Ptr).to_any(); + (*(*fn_.borrow()))(_arg0) + }); +} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let fn_: Value i32>> = Rc::new(RefCell::new(FnPtr::null())); + assert!((*fn_.borrow()).is_null()); + assert!({ + let _lhs = (*fn_.borrow()).clone(); + _lhs != FnPtr:: i32>::new(my_foo_0) + }); + (*fn_.borrow_mut()) = FnPtr:: i32>::new(my_foo_0); + assert!(!((*fn_.borrow()).is_null())); + assert!({ + let _lhs = (*fn_.borrow()).clone(); + _lhs == FnPtr:: i32>::new(my_foo_0) + }); + let a: Value = Rc::new(RefCell::new(10)); + assert!({ + let _lhs = ({ + let _fn: FnPtr i32> = (*fn_.borrow()).clone(); + let _pi: Ptr = (a.as_pointer()); + foo_1(_fn, _pi) + }); + _lhs == (*a.borrow()) + }); + return 0; +} diff --git a/tests/unit/out/refcount/fn_ptr_array.rs b/tests/unit/out/refcount/fn_ptr_array.rs new file mode 100644 index 00000000..2c3817c3 --- /dev/null +++ b/tests/unit/out/refcount/fn_ptr_array.rs @@ -0,0 +1,59 @@ +extern crate libcc2rs; +use libcc2rs::*; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::io::prelude::*; +use std::io::Seek; +use std::io::{Read, Write}; +use std::os::fd::AsFd; +use std::rc::{Rc, Weak}; +pub fn add_0(a: i32, b: i32) -> i32 { + let a: Value = Rc::new(RefCell::new(a)); + let b: Value = Rc::new(RefCell::new(b)); + return ((*a.borrow()) + (*b.borrow())); +} +pub fn sub_1(a: i32, b: i32) -> i32 { + let a: Value = Rc::new(RefCell::new(a)); + let b: Value = Rc::new(RefCell::new(b)); + return ((*a.borrow()) - (*b.borrow())); +} +pub fn mul_2(a: i32, b: i32) -> i32 { + let a: Value = Rc::new(RefCell::new(a)); + let b: Value = Rc::new(RefCell::new(b)); + return ((*a.borrow()) * (*b.borrow())); +} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let ops: Value i32>]>> = Rc::new(RefCell::new(Box::new([ + FnPtr:: i32>::new(add_0), + FnPtr:: i32>::new(sub_1), + FnPtr:: i32>::new(mul_2), + ]))); + assert!( + (({ + let _arg0: i32 = 2; + let _arg1: i32 = 3; + (*(*ops.borrow())[(0) as usize])(_arg0, _arg1) + }) == 5) + ); + assert!( + (({ + let _arg0: i32 = 7; + let _arg1: i32 = 4; + (*(*ops.borrow())[(1) as usize])(_arg0, _arg1) + }) == 3) + ); + assert!( + (({ + let _arg0: i32 = 6; + let _arg1: i32 = 5; + (*(*ops.borrow())[(2) as usize])(_arg0, _arg1) + }) == 30) + ); + assert!(!(((*ops.borrow())[(0) as usize]).is_null())); + assert!(((*ops.borrow())[(0) as usize] == FnPtr:: i32>::new(add_0))); + assert!(((*ops.borrow())[(0) as usize] != FnPtr:: i32>::new(sub_1))); + return 0; +} diff --git a/tests/unit/out/refcount/fn_ptr_as_condition.rs b/tests/unit/out/refcount/fn_ptr_as_condition.rs new file mode 100644 index 00000000..880d2671 --- /dev/null +++ b/tests/unit/out/refcount/fn_ptr_as_condition.rs @@ -0,0 +1,59 @@ +extern crate libcc2rs; +use libcc2rs::*; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::io::prelude::*; +use std::io::Seek; +use std::io::{Read, Write}; +use std::os::fd::AsFd; +use std::rc::{Rc, Weak}; +pub fn double_it_0(x: Ptr) { + let x: Value> = Rc::new(RefCell::new(x)); + { + let __ptr = (*x.borrow()).clone(); + let __tmp = __ptr.read() * 2; + __ptr.write(__tmp) + }; +} +pub fn maybe_call_1(cb: FnPtr)>, x: Ptr) { + let cb: Value)>> = Rc::new(RefCell::new(cb)); + let x: Value> = Rc::new(RefCell::new(x)); + if !(*cb.borrow()).is_null() { + ({ + let _arg0: Ptr = (*x.borrow()).clone(); + (*(*cb.borrow()))(_arg0) + }); + } +} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let a: Value = Rc::new(RefCell::new(5)); + ({ + let _cb: FnPtr)> = FnPtr::)>::new(double_it_0); + let _x: Ptr = (a.as_pointer()); + maybe_call_1(_cb, _x) + }); + assert!(((*a.borrow()) == 10)); + let b: Value = Rc::new(RefCell::new(5)); + ({ + let _cb: FnPtr)> = FnPtr::null(); + let _x: Ptr = (b.as_pointer()); + maybe_call_1(_cb, _x) + }); + assert!(((*b.borrow()) == 5)); + let fn_: Value)>> = Rc::new(RefCell::new(FnPtr::null())); + if !!(*fn_.borrow()).is_null() { + (*fn_.borrow_mut()) = (FnPtr::)>::new(double_it_0)).clone(); + } + let c: Value = Rc::new(RefCell::new(3)); + if !(*fn_.borrow()).is_null() { + ({ + let _arg0: Ptr = (c.as_pointer()); + (*(*fn_.borrow()))(_arg0) + }); + } + assert!(((*c.borrow()) == 6)); + return 0; +} diff --git a/tests/unit/out/refcount/fn_ptr_cast.rs b/tests/unit/out/refcount/fn_ptr_cast.rs new file mode 100644 index 00000000..0d0d8204 --- /dev/null +++ b/tests/unit/out/refcount/fn_ptr_cast.rs @@ -0,0 +1,123 @@ +extern crate libcc2rs; +use libcc2rs::*; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::io::prelude::*; +use std::io::Seek; +use std::io::{Read, Write}; +use std::os::fd::AsFd; +use std::rc::{Rc, Weak}; +pub fn double_it_0(x: i32) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + return ((*x.borrow()) * 2); +} +pub fn test_roundtrip_1() { + let fn_: Value i32>> = + Rc::new(RefCell::new(FnPtr:: i32>::new(double_it_0))); + assert!( + (({ + let _arg0: i32 = 5; + (*(*fn_.borrow()))(_arg0) + }) == 10) + ); + let gfn: Value> = + Rc::new(RefCell::new(((*fn_.borrow()).cast::(None)).clone())); + assert!(!((*gfn.borrow()).is_null())); + let fn2: Value i32>> = Rc::new(RefCell::new( + ((*gfn.borrow()).cast:: i32>(None)).clone(), + )); + assert!( + (({ + let _arg0: i32 = 5; + (*(*fn2.borrow()))(_arg0) + }) == 10) + ); + assert!({ + let _lhs = (*fn2.borrow()).clone(); + _lhs == (*fn_.borrow()).clone() + }); +} +pub fn test_double_cast_2() { + let fn_: Value i32>> = + Rc::new(RefCell::new(FnPtr:: i32>::new(double_it_0))); + let fn2: Value i32>> = Rc::new(RefCell::new( + ((*fn_.borrow()) + .cast::(None) + .cast:: i32>(None)) + .clone(), + )); + assert!( + (({ + let _arg0: i32 = 5; + (*(*fn2.borrow()))(_arg0) + }) == 10) + ); + assert!({ + let _lhs = (*fn2.borrow()).clone(); + _lhs == (*fn_.borrow()).clone() + }); +} +#[derive(Default)] +pub struct Command { + pub data: Value, +} +impl Clone for Command { + fn clone(&self) -> Self { + let mut this = Self { + data: Rc::new(RefCell::new((*self.data.borrow()).clone())), + }; + this + } +} +impl ByteRepr for Command {} +pub fn test_void_ptr_to_fn_3() { + let cmd: Value = Rc::new(RefCell::new(::default())); + (*(*cmd.borrow()).data.borrow_mut()) = FnPtr:: i32>::new(double_it_0).to_any(); + let fn_: Value i32>> = Rc::new(RefCell::new( + ((*(*cmd.borrow()).data.borrow()) + .cast_fn:: i32>() + .expect("ub:wrong fn type")) + .clone(), + )); + assert!( + (({ + let _arg0: i32 = 5; + (*(*fn_.borrow()))(_arg0) + }) == 10) + ); +} +pub fn add_offset_4(base: Ptr, offset: i32) -> i32 { + let base: Value> = Rc::new(RefCell::new(base)); + let offset: Value = Rc::new(RefCell::new(offset)); + return { + let _lhs = ((*base.borrow()).read()); + _lhs + (*offset.borrow()) + }; +} +pub fn test_call_through_cast_5() { + let gfn: Value i32>> = Rc::new(RefCell::new( + FnPtr::, i32) -> i32>::new(add_offset_4).cast:: i32>(Some( + (|a0: AnyPtr, a1: i32| -> i32 { add_offset_4(a0.cast::().unwrap(), a1) }) + as fn(AnyPtr, i32) -> i32, + )), + )); + let val: Value = Rc::new(RefCell::new(100)); + let result: Value = Rc::new(RefCell::new( + ({ + let _arg0: AnyPtr = ((val.as_pointer()) as Ptr).to_any(); + let _arg1: i32 = 42; + (*(*gfn.borrow()))(_arg0, _arg1) + }), + )); + assert!(((*result.borrow()) == 142)); +} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + ({ test_roundtrip_1() }); + ({ test_double_cast_2() }); + ({ test_void_ptr_to_fn_3() }); + ({ test_call_through_cast_5() }); + return 0; +} diff --git a/tests/unit/out/refcount/fn_ptr_conditional.rs b/tests/unit/out/refcount/fn_ptr_conditional.rs new file mode 100644 index 00000000..4d277c65 --- /dev/null +++ b/tests/unit/out/refcount/fn_ptr_conditional.rs @@ -0,0 +1,94 @@ +extern crate libcc2rs; +use libcc2rs::*; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::io::prelude::*; +use std::io::Seek; +use std::io::{Read, Write}; +use std::os::fd::AsFd; +use std::rc::{Rc, Weak}; +pub fn inc_0(x: i32) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + return ((*x.borrow()) + 1); +} +pub fn dec_1(x: i32) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + return ((*x.borrow()) - 1); +} +pub fn identity_2(x: i32) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + return (*x.borrow()); +} +pub fn pick_3(mode: i32) -> FnPtr i32> { + let mode: Value = Rc::new(RefCell::new(mode)); + return if ((*mode.borrow()) > 0) { + FnPtr:: i32>::new(inc_0) + } else { + if ((*mode.borrow()) < 0) { + FnPtr:: i32>::new(dec_1) + } else { + FnPtr:: i32>::new(identity_2) + } + }; +} +pub fn apply_4(fn_: FnPtr i32>, x: i32) -> i32 { + let fn_: Value i32>> = Rc::new(RefCell::new(fn_)); + let x: Value = Rc::new(RefCell::new(x)); + let actual: Value i32>> = + Rc::new(RefCell::new(if !(*fn_.borrow()).is_null() { + (*fn_.borrow()).clone() + } else { + FnPtr:: i32>::new(identity_2) + })); + return ({ + let _arg0: i32 = (*x.borrow()); + (*(*actual.borrow()))(_arg0) + }); +} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + assert!( + (({ + let _arg0: i32 = 10; + (*({ + let _mode: i32 = 1; + pick_3(_mode) + }))(_arg0) + }) == 11) + ); + assert!( + (({ + let _arg0: i32 = 10; + (*({ + let _mode: i32 = -1_i32; + pick_3(_mode) + }))(_arg0) + }) == 9) + ); + assert!( + (({ + let _arg0: i32 = 10; + (*({ + let _mode: i32 = 0; + pick_3(_mode) + }))(_arg0) + }) == 10) + ); + assert!( + (({ + let _fn: FnPtr i32> = FnPtr:: i32>::new(inc_0); + let _x: i32 = 5; + apply_4(_fn, _x) + }) == 6) + ); + assert!( + (({ + let _fn: FnPtr i32> = FnPtr::null(); + let _x: i32 = 5; + apply_4(_fn, _x) + }) == 5) + ); + return 0; +} diff --git a/tests/unit/out/refcount/fn_ptr_default_arg.rs b/tests/unit/out/refcount/fn_ptr_default_arg.rs new file mode 100644 index 00000000..35f843d6 --- /dev/null +++ b/tests/unit/out/refcount/fn_ptr_default_arg.rs @@ -0,0 +1,64 @@ +extern crate libcc2rs; +use libcc2rs::*; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::io::prelude::*; +use std::io::Seek; +use std::io::{Read, Write}; +use std::os::fd::AsFd; +use std::rc::{Rc, Weak}; +pub fn identity_0(x: i32) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + return (*x.borrow()); +} +pub fn apply_1(x: i32, fn_: Option i32>>) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + let fn_: Value i32>> = Rc::new(RefCell::new(fn_.unwrap_or(FnPtr::null()))); + if !(*fn_.borrow()).is_null() { + return ({ + let _arg0: i32 = (*x.borrow()); + (*(*fn_.borrow()))(_arg0) + }); + } + return (*x.borrow()); +} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + assert!( + (({ + let _x: i32 = 5; + let _fn: FnPtr i32> = Default::default(); + apply_1(_x, Some(_fn)) + }) == 5) + ); + assert!( + (({ + let _x: i32 = 5; + let _fn: FnPtr i32> = FnPtr::null(); + apply_1(_x, Some(_fn)) + }) == 5) + ); + assert!( + (({ + let _x: i32 = 5; + let _fn: FnPtr i32> = FnPtr:: i32>::new(identity_0); + apply_1(_x, Some(_fn)) + }) == 5) + ); + let negate: Value i32>> = Rc::new(RefCell::new(FnPtr::new( + (|x: i32| { + let x: Value = Rc::new(RefCell::new(x)); + return -(*x.borrow()); + }), + ))); + assert!( + (({ + let _x: i32 = 5; + let _fn: FnPtr i32> = (*negate.borrow()).clone(); + apply_1(_x, Some(_fn)) + }) == -5_i32) + ); + return 0; +} diff --git a/tests/unit/out/refcount/fn_ptr_global.rs b/tests/unit/out/refcount/fn_ptr_global.rs new file mode 100644 index 00000000..3218860a --- /dev/null +++ b/tests/unit/out/refcount/fn_ptr_global.rs @@ -0,0 +1,86 @@ +extern crate libcc2rs; +use libcc2rs::*; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::io::prelude::*; +use std::io::Seek; +use std::io::{Read, Write}; +use std::os::fd::AsFd; +use std::rc::{Rc, Weak}; +pub fn double_it_0(x: i32) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + return ((*x.borrow()) * 2); +} +pub fn triple_it_1(x: i32) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + return ((*x.borrow()) * 3); +} +thread_local!( + pub static g_op: Value i32>> = Rc::new(RefCell::new(FnPtr::null())); +); +pub fn set_op_2(fn_: FnPtr i32>) { + let fn_: Value i32>> = Rc::new(RefCell::new(fn_)); + (*g_op.with(Value::clone).borrow_mut()) = (*fn_.borrow()).clone(); +} +pub fn call_op_3(x: i32) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + if !(*g_op.with(Value::clone).borrow()).is_null() { + return ({ + let _arg0: i32 = (*x.borrow()); + (*(*g_op.with(Value::clone).borrow()))(_arg0) + }); + } + return (*x.borrow()); +} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + assert!( + (({ + let _x: i32 = 5; + call_op_3(_x) + }) == 5) + ); + ({ + let _fn: FnPtr i32> = FnPtr:: i32>::new(double_it_0); + set_op_2(_fn) + }); + assert!(!((*g_op.with(Value::clone).borrow()).is_null())); + assert!({ + let _lhs = (*g_op.with(Value::clone).borrow()).clone(); + _lhs == FnPtr:: i32>::new(double_it_0) + }); + assert!( + (({ + let _x: i32 = 5; + call_op_3(_x) + }) == 10) + ); + ({ + let _fn: FnPtr i32> = FnPtr:: i32>::new(triple_it_1); + set_op_2(_fn) + }); + assert!({ + let _lhs = (*g_op.with(Value::clone).borrow()).clone(); + _lhs == FnPtr:: i32>::new(triple_it_1) + }); + assert!( + (({ + let _x: i32 = 5; + call_op_3(_x) + }) == 15) + ); + ({ + let _fn: FnPtr i32> = FnPtr::null(); + set_op_2(_fn) + }); + assert!((*g_op.with(Value::clone).borrow()).is_null()); + assert!( + (({ + let _x: i32 = 5; + call_op_3(_x) + }) == 5) + ); + return 0; +} diff --git a/tests/unit/out/refcount/fn_ptr_reassign.rs b/tests/unit/out/refcount/fn_ptr_reassign.rs new file mode 100644 index 00000000..da316260 --- /dev/null +++ b/tests/unit/out/refcount/fn_ptr_reassign.rs @@ -0,0 +1,66 @@ +extern crate libcc2rs; +use libcc2rs::*; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::io::prelude::*; +use std::io::Seek; +use std::io::{Read, Write}; +use std::os::fd::AsFd; +use std::rc::{Rc, Weak}; +pub fn add_0(a: i32, b: i32) -> i32 { + let a: Value = Rc::new(RefCell::new(a)); + let b: Value = Rc::new(RefCell::new(b)); + return ((*a.borrow()) + (*b.borrow())); +} +pub fn sub_1(a: i32, b: i32) -> i32 { + let a: Value = Rc::new(RefCell::new(a)); + let b: Value = Rc::new(RefCell::new(b)); + return ((*a.borrow()) - (*b.borrow())); +} +pub fn mul_2(a: i32, b: i32) -> i32 { + let a: Value = Rc::new(RefCell::new(a)); + let b: Value = Rc::new(RefCell::new(b)); + return ((*a.borrow()) * (*b.borrow())); +} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let fn_: Value i32>> = + Rc::new(RefCell::new(FnPtr:: i32>::new(add_0))); + assert!( + (({ + let _arg0: i32 = 3; + let _arg1: i32 = 4; + (*(*fn_.borrow()))(_arg0, _arg1) + }) == 7) + ); + (*fn_.borrow_mut()) = FnPtr:: i32>::new(sub_1); + assert!( + (({ + let _arg0: i32 = 10; + let _arg1: i32 = 3; + (*(*fn_.borrow()))(_arg0, _arg1) + }) == 7) + ); + (*fn_.borrow_mut()) = FnPtr:: i32>::new(mul_2); + assert!( + (({ + let _arg0: i32 = 6; + let _arg1: i32 = 7; + (*(*fn_.borrow()))(_arg0, _arg1) + }) == 42) + ); + (*fn_.borrow_mut()) = FnPtr::null(); + assert!((*fn_.borrow()).is_null()); + (*fn_.borrow_mut()) = FnPtr:: i32>::new(add_0); + assert!(!((*fn_.borrow()).is_null())); + assert!( + (({ + let _arg0: i32 = 1; + let _arg1: i32 = 1; + (*(*fn_.borrow()))(_arg0, _arg1) + }) == 2) + ); + return 0; +} diff --git a/tests/unit/out/refcount/fn_ptr_return.rs b/tests/unit/out/refcount/fn_ptr_return.rs new file mode 100644 index 00000000..3a6ab413 --- /dev/null +++ b/tests/unit/out/refcount/fn_ptr_return.rs @@ -0,0 +1,67 @@ +extern crate libcc2rs; +use libcc2rs::*; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::io::prelude::*; +use std::io::Seek; +use std::io::{Read, Write}; +use std::os::fd::AsFd; +use std::rc::{Rc, Weak}; +pub fn inc_0(x: i32) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + return ((*x.borrow()) + 1); +} +pub fn dec_1(x: i32) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + return ((*x.borrow()) - 1); +} +pub fn pick_2(choose_inc: i32) -> FnPtr i32> { + let choose_inc: Value = Rc::new(RefCell::new(choose_inc)); + if ((*choose_inc.borrow()) != 0) { + return FnPtr:: i32>::new(inc_0); + } + return FnPtr:: i32>::new(dec_1); +} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let f: Value i32>> = Rc::new(RefCell::new( + ({ + let _choose_inc: i32 = 1; + pick_2(_choose_inc) + }), + )); + assert!(!((*f.borrow()).is_null())); + assert!({ + let _lhs = (*f.borrow()).clone(); + _lhs == FnPtr:: i32>::new(inc_0) + }); + assert!( + (({ + let _arg0: i32 = 10; + (*(*f.borrow()))(_arg0) + }) == 11) + ); + let g: Value i32>> = Rc::new(RefCell::new( + ({ + let _choose_inc: i32 = 0; + pick_2(_choose_inc) + }), + )); + assert!({ + let _lhs = (*g.borrow()).clone(); + _lhs == FnPtr:: i32>::new(dec_1) + }); + assert!( + (({ + let _arg0: i32 = 10; + (*(*g.borrow()))(_arg0) + }) == 9) + ); + assert!({ + let _lhs = (*f.borrow()).clone(); + _lhs != (*g.borrow()).clone() + }); + return 0; +} diff --git a/tests/unit/out/refcount/fn_ptr_stable_sort.rs b/tests/unit/out/refcount/fn_ptr_stable_sort.rs new file mode 100644 index 00000000..2770c956 --- /dev/null +++ b/tests/unit/out/refcount/fn_ptr_stable_sort.rs @@ -0,0 +1,80 @@ +extern crate libcc2rs; +use libcc2rs::*; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::io::prelude::*; +use std::io::Seek; +use std::io::{Read, Write}; +use std::os::fd::AsFd; +use std::rc::{Rc, Weak}; +#[derive(Default)] +pub struct Item { + pub key: Value, + pub value: Value, +} +impl Clone for Item { + fn clone(&self) -> Self { + let mut this = Self { + key: Rc::new(RefCell::new((*self.key.borrow()))), + value: Rc::new(RefCell::new((*self.value.borrow()))), + }; + this + } +} +impl ByteRepr for Item {} +pub fn Compare_0(a: Ptr, b: Ptr) -> bool { + return { + let _lhs = (*(*a.upgrade().deref()).key.borrow()); + _lhs < (*(*b.upgrade().deref()).key.borrow()) + }; +} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let v: Value> = Rc::new(RefCell::new(Vec::new())); + (*v.borrow_mut()).push(Item { + key: Rc::new(RefCell::new(3)), + value: Rc::new(RefCell::new(30)), + }); + (*v.borrow_mut()).push(Item { + key: Rc::new(RefCell::new(1)), + value: Rc::new(RefCell::new(10)), + }); + (*v.borrow_mut()).push(Item { + key: Rc::new(RefCell::new(2)), + value: Rc::new(RefCell::new(20)), + }); + (v.as_pointer() as Ptr).sort_with_cmp( + (v.as_pointer() as Ptr).to_end().get_offset(), + Compare_0, + ); + assert!( + ((*(*(v.as_pointer() as Ptr) + .offset(0_u64 as isize) + .upgrade() + .deref()) + .key + .borrow()) + == 1) + ); + assert!( + ((*(*(v.as_pointer() as Ptr) + .offset(1_u64 as isize) + .upgrade() + .deref()) + .key + .borrow()) + == 2) + ); + assert!( + ((*(*(v.as_pointer() as Ptr) + .offset(2_u64 as isize) + .upgrade() + .deref()) + .key + .borrow()) + == 3) + ); + return 0; +} diff --git a/tests/unit/out/refcount/fn_ptr_struct.rs b/tests/unit/out/refcount/fn_ptr_struct.rs new file mode 100644 index 00000000..506edd3f --- /dev/null +++ b/tests/unit/out/refcount/fn_ptr_struct.rs @@ -0,0 +1,78 @@ +extern crate libcc2rs; +use libcc2rs::*; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::io::prelude::*; +use std::io::Seek; +use std::io::{Read, Write}; +use std::os::fd::AsFd; +use std::rc::{Rc, Weak}; +#[derive()] +pub struct Handler { + pub tag: Value, + pub cb: Value i32>>, +} +impl Clone for Handler { + fn clone(&self) -> Self { + let mut this = Self { + tag: Rc::new(RefCell::new((*self.tag.borrow()))), + cb: Rc::new(RefCell::new((*self.cb.borrow()).clone())), + }; + this + } +} +impl Default for Handler { + fn default() -> Self { + Handler { + tag: >::default(), + cb: Rc::new(RefCell::new(FnPtr::null())), + } + } +} +impl ByteRepr for Handler {} +pub fn double_it_0(x: i32) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + return ((*x.borrow()) * 2); +} +pub fn negate_1(x: i32) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + return -(*x.borrow()); +} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let h1: Value = Rc::new(RefCell::new(Handler { + tag: Rc::new(RefCell::new(1)), + cb: Rc::new(RefCell::new(FnPtr:: i32>::new(double_it_0))), + })); + let h2: Value = Rc::new(RefCell::new(Handler { + tag: Rc::new(RefCell::new(2)), + cb: Rc::new(RefCell::new(FnPtr:: i32>::new(negate_1))), + })); + assert!(!((*(*h1.borrow()).cb.borrow()).is_null())); + assert!( + (({ + let _arg0: i32 = 5; + (*(*(*h1.borrow()).cb.borrow()))(_arg0) + }) == 10) + ); + assert!( + (({ + let _arg0: i32 = 7; + (*(*(*h2.borrow()).cb.borrow()))(_arg0) + }) == -7_i32) + ); + (*(*h1.borrow()).cb.borrow_mut()) = FnPtr:: i32>::new(negate_1); + assert!( + (({ + let _arg0: i32 = 3; + (*(*(*h1.borrow()).cb.borrow()))(_arg0) + }) == -3_i32) + ); + assert!({ + let _lhs = (*(*h1.borrow()).cb.borrow()).clone(); + _lhs == (*(*h2.borrow()).cb.borrow()).clone() + }); + return 0; +} diff --git a/tests/unit/out/refcount/fn_ptr_void_return.rs b/tests/unit/out/refcount/fn_ptr_void_return.rs new file mode 100644 index 00000000..d095d4e0 --- /dev/null +++ b/tests/unit/out/refcount/fn_ptr_void_return.rs @@ -0,0 +1,54 @@ +extern crate libcc2rs; +use libcc2rs::*; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::io::prelude::*; +use std::io::Seek; +use std::io::{Read, Write}; +use std::os::fd::AsFd; +use std::rc::{Rc, Weak}; +pub fn negate_0(x: Ptr) { + let x: Value> = Rc::new(RefCell::new(x)); + let __rhs = -((*x.borrow()).read()); + (*x.borrow()).write(__rhs); +} +pub fn zero_out_1(x: Ptr) { + let x: Value> = Rc::new(RefCell::new(x)); + (*x.borrow()).write(0); +} +pub fn run_2(fn_: FnPtr)>, x: Ptr) { + let fn_: Value)>> = Rc::new(RefCell::new(fn_)); + let x: Value> = Rc::new(RefCell::new(x)); + ({ + let _arg0: Ptr = (*x.borrow()).clone(); + (*(*fn_.borrow()))(_arg0) + }); +} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let a: Value = Rc::new(RefCell::new(42)); + ({ + let _fn: FnPtr)> = FnPtr::)>::new(negate_0); + let _x: Ptr = (a.as_pointer()); + run_2(_fn, _x) + }); + assert!(((*a.borrow()) == -42_i32)); + ({ + let _fn: FnPtr)> = FnPtr::)>::new(zero_out_1); + let _x: Ptr = (a.as_pointer()); + run_2(_fn, _x) + }); + assert!(((*a.borrow()) == 0)); + let fn_: Value)>> = + Rc::new(RefCell::new(FnPtr::)>::new(negate_0))); + assert!(!((*fn_.borrow()).is_null())); + let b: Value = Rc::new(RefCell::new(10)); + ({ + let _arg0: Ptr = (b.as_pointer()); + (*(*fn_.borrow()))(_arg0) + }); + assert!(((*b.borrow()) == -10_i32)); + return 0; +} diff --git a/tests/unit/out/refcount/fn_ptr_vtable.rs b/tests/unit/out/refcount/fn_ptr_vtable.rs new file mode 100644 index 00000000..cb12c7e5 --- /dev/null +++ b/tests/unit/out/refcount/fn_ptr_vtable.rs @@ -0,0 +1,86 @@ +extern crate libcc2rs; +use libcc2rs::*; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::io::prelude::*; +use std::io::Seek; +use std::io::{Read, Write}; +use std::os::fd::AsFd; +use std::rc::{Rc, Weak}; +#[derive()] +pub struct Vtable { + pub create: Value AnyPtr>>, + pub get: Value i32>>, + pub destroy: Value>, +} +impl Clone for Vtable { + fn clone(&self) -> Self { + let mut this = Self { + create: Rc::new(RefCell::new((*self.create.borrow()).clone())), + get: Rc::new(RefCell::new((*self.get.borrow()).clone())), + destroy: Rc::new(RefCell::new((*self.destroy.borrow()).clone())), + }; + this + } +} +impl Default for Vtable { + fn default() -> Self { + Vtable { + create: Rc::new(RefCell::new(FnPtr::null())), + get: Rc::new(RefCell::new(FnPtr::null())), + destroy: Rc::new(RefCell::new(FnPtr::null())), + } + } +} +impl ByteRepr for Vtable {} +thread_local!( + pub static storage: Value = >::default(); +); +pub fn int_create_0(val: i32) -> AnyPtr { + let val: Value = Rc::new(RefCell::new(val)); + (*storage.with(Value::clone).borrow_mut()) = (*val.borrow()); + return ((storage.with(Value::clone).as_pointer()) as Ptr).to_any(); +} +pub fn int_get_1(p: AnyPtr) -> i32 { + let p: Value = Rc::new(RefCell::new(p)); + return ((*p.borrow()).cast::().expect("ub:wrong type").read()); +} +pub fn int_destroy_2(p: AnyPtr) { + let p: Value = Rc::new(RefCell::new(p)); + (*p.borrow()).cast::().expect("ub:wrong type").write(0); +} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let vt: Value = Rc::new(RefCell::new(Vtable { + create: Rc::new(RefCell::new( + (FnPtr:: AnyPtr>::new(int_create_0)).clone(), + )), + get: Rc::new(RefCell::new(FnPtr:: i32>::new(int_get_1))), + destroy: Rc::new(RefCell::new(FnPtr::::new(int_destroy_2))), + })); + assert!(!((*(*vt.borrow()).create.borrow()).is_null())); + assert!(!((*(*vt.borrow()).get.borrow()).is_null())); + assert!(!((*(*vt.borrow()).destroy.borrow()).is_null())); + let obj: Value = Rc::new(RefCell::new( + ({ + let _arg0: i32 = 42; + (*(*(*vt.borrow()).create.borrow()))(_arg0) + }), + )); + assert!( + (({ + let _arg0: AnyPtr = (*obj.borrow()).clone(); + (*(*(*vt.borrow()).get.borrow()))(_arg0) + }) == 42) + ); + ({ + let _arg0: AnyPtr = (*obj.borrow()).clone(); + (*(*(*vt.borrow()).destroy.borrow()))(_arg0) + }); + assert!(((*storage.with(Value::clone).borrow()) == 0)); + (*(*vt.borrow()).get.borrow_mut()) = FnPtr::null(); + assert!((*(*vt.borrow()).get.borrow()).is_null()); + return 0; +} diff --git a/tests/unit/out/refcount/lambda_capture_pass.rs b/tests/unit/out/refcount/lambda_capture_pass.rs new file mode 100644 index 00000000..757476fa --- /dev/null +++ b/tests/unit/out/refcount/lambda_capture_pass.rs @@ -0,0 +1,69 @@ +extern crate libcc2rs; +use libcc2rs::*; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::io::prelude::*; +use std::io::Seek; +use std::io::{Read, Write}; +use std::os::fd::AsFd; +use std::rc::{Rc, Weak}; +pub fn apply_0(fn_: impl Fn(i32) -> i32, x: i32) -> i32 { + let fn_: Value<_> = Rc::new(RefCell::new(fn_)); + let x: Value = Rc::new(RefCell::new(x)); + return ({ + let _x: i32 = (*x.borrow()); + (*fn_.borrow_mut())(_x) + }) + .clone(); +} +pub fn apply_1(fn_: impl Fn(i32) -> i32, x: i32) -> i32 { + let fn_: Value<_> = Rc::new(RefCell::new(fn_)); + let x: Value = Rc::new(RefCell::new(x)); + return ({ + let _x: i32 = (*x.borrow()); + (*fn_.borrow_mut())(_x) + }) + .clone(); +} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let base: Value = Rc::new(RefCell::new(10)); + let add_base: Value<_> = Rc::new(RefCell::new( + (|x: i32| { + let x: Value = Rc::new(RefCell::new(x)); + return ((*x.borrow()) + (*base.borrow())); + }), + )); + assert!( + (({ + let _fn: _ = (*add_base.borrow()).clone(); + let _x: i32 = 5; + apply_0(_fn, _x) + }) == 15) + ); + (*base.borrow_mut()) = 100; + assert!( + (({ + let _fn: _ = (*add_base.borrow()).clone(); + let _x: i32 = 5; + apply_0(_fn, _x) + }) == 105) + ); + let factor: Value = Rc::new(RefCell::new(3)); + let scale: Value<_> = Rc::new(RefCell::new( + (|x: i32| { + let x: Value = Rc::new(RefCell::new(x)); + return ((*x.borrow()) * (*factor.borrow())); + }), + )); + assert!( + (({ + let _fn: _ = (*scale.borrow()).clone(); + let _x: i32 = 4; + apply_1(_fn, _x) + }) == 12) + ); + return 0; +} diff --git a/tests/unit/out/refcount/lambda_nested.rs b/tests/unit/out/refcount/lambda_nested.rs new file mode 100644 index 00000000..9b26d593 --- /dev/null +++ b/tests/unit/out/refcount/lambda_nested.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::Seek; +use std::io::{Read, 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(10)); + let outer: Value<_> = Rc::new(RefCell::new( + (|y: i32| { + let y: Value = Rc::new(RefCell::new(y)); + let inner: Value<_> = Rc::new(RefCell::new( + (|z: i32| { + let z: Value = Rc::new(RefCell::new(z)); + return (((*x.borrow()) + (*y.borrow())) + (*z.borrow())); + }), + )); + return ({ + let _z: i32 = 1; + (*inner.borrow_mut())(_z) + }) + .clone(); + }), + )); + assert!( + (({ + let _y: i32 = 20; + (*outer.borrow_mut())(_y) + }) == 31) + ); + (*x.borrow_mut()) = 100; + assert!( + (({ + let _y: i32 = 20; + (*outer.borrow_mut())(_y) + }) == 121) + ); + return 0; +} diff --git a/tests/unit/out/refcount/no_direct_callee.rs b/tests/unit/out/refcount/no_direct_callee.rs index a01b00dc..4cd3f05c 100644 --- a/tests/unit/out/refcount/no_direct_callee.rs +++ b/tests/unit/out/refcount/no_direct_callee.rs @@ -10,9 +10,9 @@ use std::rc::{Rc, Weak}; pub fn test1_0() -> bool { return false; } -pub fn test_1(fn_: Rc bool>) -> i32 { - let fn_: Value bool>> = Rc::new(RefCell::new(fn_)); - if !({ (*fn_.borrow())() }) { +pub fn test_1(fn_: FnPtr bool>) -> i32 { + let fn_: Value bool>> = Rc::new(RefCell::new(fn_)); + if !({ (*(*fn_.borrow()))() }) { return 1; } return 0; @@ -22,7 +22,7 @@ pub fn main() { } fn main_0() -> i32 { return ({ - let _fn: Rc bool> = Rc::new(test1_0); + let _fn: FnPtr bool> = FnPtr:: bool>::new(test1_0); test_1(_fn) }); } diff --git a/tests/unit/out/refcount/printfs.rs b/tests/unit/out/refcount/printfs.rs index df5ffa6c..a661f372 100644 --- a/tests/unit/out/refcount/printfs.rs +++ b/tests/unit/out/refcount/printfs.rs @@ -44,7 +44,7 @@ fn main_0() -> i32 { .to_c_string_iterator() .chain(std::iter::once(0)) .collect::>(); - Rc::new(fn_0)(_v) + fn_0(_v) }) )) .as_pointer() as Ptr) @@ -53,7 +53,7 @@ fn main_0() -> i32 { "{}", (({ let _v: Ptr> = s.as_pointer(); - Rc::new(fn2_1)(_v) + fn2_1(_v) }) .to_strong() .as_pointer() as Ptr) diff --git a/tests/unit/out/refcount/prvalue-as-lvalue.rs b/tests/unit/out/refcount/prvalue-as-lvalue.rs index a8926cca..610c6ba5 100644 --- a/tests/unit/out/refcount/prvalue-as-lvalue.rs +++ b/tests/unit/out/refcount/prvalue-as-lvalue.rs @@ -18,7 +18,7 @@ fn main_0() -> i32 { let pa: Value> = Rc::new(RefCell::new((a.as_pointer()))); let b: Ptr = ({ let _a: Ptr = (*pa.borrow()).clone(); - Rc::new(foo_0)(_a) + foo_0(_a) }); return (b.read()); } diff --git a/tests/unit/out/refcount/ref_calls.rs b/tests/unit/out/refcount/ref_calls.rs index 41dbbfdb..f9e604f8 100644 --- a/tests/unit/out/refcount/ref_calls.rs +++ b/tests/unit/out/refcount/ref_calls.rs @@ -27,7 +27,7 @@ fn main_0() -> i32 { )); let z: Ptr = ({ let _x: Ptr = x.as_pointer(); - Rc::new(foo_1)(_x) + foo_1(_x) }); return { let _lhs = { diff --git a/tests/unit/out/unsafe/complex_function.rs b/tests/unit/out/unsafe/complex_function.rs index 5d741ea3..5707ff99 100644 --- a/tests/unit/out/unsafe/complex_function.rs +++ b/tests/unit/out/unsafe/complex_function.rs @@ -90,11 +90,11 @@ unsafe fn main_0() -> i32 { let r1: *mut i32 = &mut x1 as *mut i32; let r2: *mut i32 = (unsafe { let _x: *mut i32 = &mut x1 as *mut i32; - Rc::new(|a0| unsafe { bar_2(a0) })(_x) + bar_2(_x) }); let r3: *mut i32 = (unsafe { let _x: *mut i32 = r1; - Rc::new(|a0| unsafe { bar_2(a0) })(_x) + bar_2(_x) }); (*r2) += x1; (*r3) += (*r1); @@ -230,12 +230,12 @@ unsafe fn main_0() -> i32 { let mut pref: *mut i32 = (unsafe { let _x: *mut i32 = &mut (*(unsafe { (*(unsafe { (*(unsafe { d.get() })).get() })).get() })).v as *mut i32; - Rc::new(|a0| unsafe { bar_2(a0) })(_x) + bar_2(_x) }); (*(unsafe { let _x: *mut i32 = &mut (*(unsafe { (*(unsafe { (*(unsafe { d.get() })).get() })).get() })).v as *mut i32; - Rc::new(|a0| unsafe { bar_2(a0) })(_x) + bar_2(_x) })) .postfix_inc(); return (((*(unsafe { diff --git a/tests/unit/out/unsafe/fn_ptr.rs b/tests/unit/out/unsafe/fn_ptr.rs new file mode 100644 index 00000000..60ce3036 --- /dev/null +++ b/tests/unit/out/unsafe/fn_ptr.rs @@ -0,0 +1,43 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::Seek; +use std::io::{Read, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +pub unsafe fn my_foo_0(mut p: *mut ::libc::c_void) -> i32 { + return (*(p as *mut i32)); +} +pub unsafe fn foo_1( + mut fn_: Option i32>, + mut pi: *mut i32, +) -> i32 { + return (unsafe { + let _arg0: *mut ::libc::c_void = (pi as *mut i32 as *mut ::libc::c_void); + (fn_).unwrap()(_arg0) + }); +} +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut fn_: Option i32> = None; + assert!((fn_).is_none()); + assert!(((fn_) != (Some(my_foo_0)))); + fn_ = Some(my_foo_0); + assert!(!((fn_).is_none())); + assert!(((fn_) == (Some(my_foo_0)))); + let mut a: i32 = 10; + assert!( + ((unsafe { + let _fn: Option i32> = fn_; + let _pi: *mut i32 = (&mut a as *mut i32); + foo_1(_fn, _pi) + }) == (a)) + ); + return 0; +} diff --git a/tests/unit/out/unsafe/fn_ptr_array.rs b/tests/unit/out/unsafe/fn_ptr_array.rs new file mode 100644 index 00000000..1e224706 --- /dev/null +++ b/tests/unit/out/unsafe/fn_ptr_array.rs @@ -0,0 +1,51 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::Seek; +use std::io::{Read, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +pub unsafe fn add_0(mut a: i32, mut b: i32) -> i32 { + return ((a) + (b)); +} +pub unsafe fn sub_1(mut a: i32, mut b: i32) -> i32 { + return ((a) - (b)); +} +pub unsafe fn mul_2(mut a: i32, mut b: i32) -> i32 { + return ((a) * (b)); +} +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut ops: [Option i32>; 3] = [Some(add_0), Some(sub_1), Some(mul_2)]; + assert!( + ((unsafe { + let _arg0: i32 = 2; + let _arg1: i32 = 3; + (ops[(0) as usize]).unwrap()(_arg0, _arg1) + }) == (5)) + ); + assert!( + ((unsafe { + let _arg0: i32 = 7; + let _arg1: i32 = 4; + (ops[(1) as usize]).unwrap()(_arg0, _arg1) + }) == (3)) + ); + assert!( + ((unsafe { + let _arg0: i32 = 6; + let _arg1: i32 = 5; + (ops[(2) as usize]).unwrap()(_arg0, _arg1) + }) == (30)) + ); + assert!(!((ops[(0) as usize]).is_none())); + assert!(((ops[(0) as usize]) == (Some(add_0)))); + assert!(((ops[(0) as usize]) != (Some(sub_1)))); + return 0; +} diff --git a/tests/unit/out/unsafe/fn_ptr_as_condition.rs b/tests/unit/out/unsafe/fn_ptr_as_condition.rs new file mode 100644 index 00000000..7669fb31 --- /dev/null +++ b/tests/unit/out/unsafe/fn_ptr_as_condition.rs @@ -0,0 +1,54 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::Seek; +use std::io::{Read, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +pub unsafe fn double_it_0(mut x: *mut i32) { + (*x) *= 2; +} +pub unsafe fn maybe_call_1(mut cb: Option, mut x: *mut i32) { + if !(cb).is_none() { + (unsafe { + let _arg0: *mut i32 = x; + (cb).unwrap()(_arg0) + }); + } +} +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut a: i32 = 5; + (unsafe { + let _cb: Option = Some(double_it_0); + let _x: *mut i32 = (&mut a as *mut i32); + maybe_call_1(_cb, _x) + }); + assert!(((a) == (10))); + let mut b: i32 = 5; + (unsafe { + let _cb: Option = None; + let _x: *mut i32 = (&mut b as *mut i32); + maybe_call_1(_cb, _x) + }); + assert!(((b) == (5))); + let mut fn_: Option = None; + if !!(fn_).is_none() { + fn_ = Some(double_it_0); + } + let mut c: i32 = 3; + if !(fn_).is_none() { + (unsafe { + let _arg0: *mut i32 = (&mut c as *mut i32); + (fn_).unwrap()(_arg0) + }); + } + assert!(((c) == (6))); + return 0; +} diff --git a/tests/unit/out/unsafe/fn_ptr_cast.rs b/tests/unit/out/unsafe/fn_ptr_cast.rs new file mode 100644 index 00000000..9fce4e7c --- /dev/null +++ b/tests/unit/out/unsafe/fn_ptr_cast.rs @@ -0,0 +1,94 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::Seek; +use std::io::{Read, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +pub unsafe fn double_it_0(mut x: i32) -> i32 { + return ((x) * (2)); +} +pub unsafe fn test_roundtrip_1() { + let mut fn_: Option i32> = Some(double_it_0); + assert!( + ((unsafe { + let _arg0: i32 = 5; + (fn_).unwrap()(_arg0) + }) == (10)) + ); + let mut gfn: Option = + std::mem::transmute:: i32>, Option>(fn_); + assert!(!((gfn).is_none())); + let mut fn2: Option i32> = + std::mem::transmute::, Option i32>>(gfn); + assert!( + ((unsafe { + let _arg0: i32 = 5; + (fn2).unwrap()(_arg0) + }) == (10)) + ); + assert!(((fn2) == (fn_))); +} +pub unsafe fn test_double_cast_2() { + let mut fn_: Option i32> = Some(double_it_0); + let mut fn2: Option i32> = + std::mem::transmute::, Option i32>>( + std::mem::transmute:: i32>, Option>(fn_), + ); + assert!( + ((unsafe { + let _arg0: i32 = 5; + (fn2).unwrap()(_arg0) + }) == (10)) + ); + assert!(((fn2) == (fn_))); +} +#[derive(Copy, Clone, Default)] +pub struct Command { + pub data: *mut ::libc::c_void, +} +pub unsafe fn test_void_ptr_to_fn_3() { + let mut cmd: Command = ::default(); + cmd.data = std::mem::transmute:: i32>, *mut ::libc::c_void>(Some( + double_it_0, + )); + let mut fn_: Option i32> = + std::mem::transmute::<*mut ::libc::c_void, Option i32>>(cmd.data); + assert!( + ((unsafe { + let _arg0: i32 = 5; + (fn_).unwrap()(_arg0) + }) == (10)) + ); +} +pub unsafe fn add_offset_4(mut base: *mut i32, mut offset: i32) -> i32 { + return ((*base) + (offset)); +} +pub unsafe fn test_call_through_cast_5() { + let mut gfn: Option i32> = std::mem::transmute::< + Option i32>, + Option i32>, + >(Some(add_offset_4)); + let mut val: i32 = 100; + let mut result: i32 = (unsafe { + let _arg0: *mut ::libc::c_void = + ((&mut val as *mut i32) as *mut i32 as *mut ::libc::c_void); + let _arg1: i32 = 42; + (gfn).unwrap()(_arg0, _arg1) + }); + assert!(((result) == (142))); +} +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + (unsafe { test_roundtrip_1() }); + (unsafe { test_double_cast_2() }); + (unsafe { test_void_ptr_to_fn_3() }); + (unsafe { test_call_through_cast_5() }); + return 0; +} diff --git a/tests/unit/out/unsafe/fn_ptr_conditional.rs b/tests/unit/out/unsafe/fn_ptr_conditional.rs new file mode 100644 index 00000000..0694a0b1 --- /dev/null +++ b/tests/unit/out/unsafe/fn_ptr_conditional.rs @@ -0,0 +1,92 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::Seek; +use std::io::{Read, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +pub unsafe fn inc_0(mut x: i32) -> i32 { + return ((x) + (1)); +} +pub unsafe fn dec_1(mut x: i32) -> i32 { + return ((x) - (1)); +} +pub unsafe fn identity_2(mut x: i32) -> i32 { + return x; +} +pub unsafe fn pick_3(mut mode: i32) -> Option i32> { + return if ((mode) > (0)) { + Some(inc_0) + } else { + if ((mode) < (0)) { + Some(dec_1) + } else { + Some(identity_2) + } + }; +} +pub unsafe fn apply_4(mut fn_: Option i32>, mut x: i32) -> i32 { + let mut actual: Option i32> = if !(fn_).is_none() { + fn_ + } else { + Some(identity_2) + }; + return (unsafe { + let _arg0: i32 = x; + (actual).unwrap()(_arg0) + }); +} +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + assert!( + ((unsafe { + let _arg0: i32 = 10; + (unsafe { + let _mode: i32 = 1; + pick_3(_mode) + }) + .unwrap()(_arg0) + }) == (11)) + ); + assert!( + ((unsafe { + let _arg0: i32 = 10; + (unsafe { + let _mode: i32 = -1_i32; + pick_3(_mode) + }) + .unwrap()(_arg0) + }) == (9)) + ); + assert!( + ((unsafe { + let _arg0: i32 = 10; + (unsafe { + let _mode: i32 = 0; + pick_3(_mode) + }) + .unwrap()(_arg0) + }) == (10)) + ); + assert!( + ((unsafe { + let _fn: Option i32> = Some(inc_0); + let _x: i32 = 5; + apply_4(_fn, _x) + }) == (6)) + ); + assert!( + ((unsafe { + let _fn: Option i32> = None; + let _x: i32 = 5; + apply_4(_fn, _x) + }) == (5)) + ); + return 0; +} diff --git a/tests/unit/out/unsafe/fn_ptr_default_arg.rs b/tests/unit/out/unsafe/fn_ptr_default_arg.rs new file mode 100644 index 00000000..86287ca6 --- /dev/null +++ b/tests/unit/out/unsafe/fn_ptr_default_arg.rs @@ -0,0 +1,61 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::Seek; +use std::io::{Read, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +pub unsafe fn identity_0(mut x: i32) -> i32 { + return x; +} +pub unsafe fn apply_1(mut x: i32, mut fn_: Option i32>>) -> i32 { + let mut fn_: Option i32> = fn_.unwrap_or(None); + if !(fn_).is_none() { + return (unsafe { + let _arg0: i32 = x; + (fn_).unwrap()(_arg0) + }); + } + return x; +} +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + assert!( + ((unsafe { + let _x: i32 = 5; + let _fn: Option i32> = Default::default(); + apply_1(_x, Some(_fn)) + }) == (5)) + ); + assert!( + ((unsafe { + let _x: i32 = 5; + let _fn: Option i32> = None; + apply_1(_x, Some(_fn)) + }) == (5)) + ); + assert!( + ((unsafe { + let _x: i32 = 5; + let _fn: Option i32> = Some(identity_0); + apply_1(_x, Some(_fn)) + }) == (5)) + ); + let mut negate: Option i32> = Some(|x: i32| { + return -x; + }); + assert!( + ((unsafe { + let _x: i32 = 5; + let _fn: Option i32> = negate; + apply_1(_x, Some(_fn)) + }) == (-5_i32)) + ); + return 0; +} diff --git a/tests/unit/out/unsafe/fn_ptr_global.rs b/tests/unit/out/unsafe/fn_ptr_global.rs new file mode 100644 index 00000000..21dc35b7 --- /dev/null +++ b/tests/unit/out/unsafe/fn_ptr_global.rs @@ -0,0 +1,76 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::Seek; +use std::io::{Read, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +pub unsafe fn double_it_0(mut x: i32) -> i32 { + return ((x) * (2)); +} +pub unsafe fn triple_it_1(mut x: i32) -> i32 { + return ((x) * (3)); +} +pub static mut g_op: Option i32> = None; +pub unsafe fn set_op_2(mut fn_: Option i32>) { + g_op = fn_; +} +pub unsafe fn call_op_3(mut x: i32) -> i32 { + if !(g_op).is_none() { + return (unsafe { + let _arg0: i32 = x; + (g_op).unwrap()(_arg0) + }); + } + return x; +} +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + assert!( + ((unsafe { + let _x: i32 = 5; + call_op_3(_x) + }) == (5)) + ); + (unsafe { + let _fn: Option i32> = Some(double_it_0); + set_op_2(_fn) + }); + assert!(!((g_op).is_none())); + assert!(((g_op) == (Some(double_it_0)))); + assert!( + ((unsafe { + let _x: i32 = 5; + call_op_3(_x) + }) == (10)) + ); + (unsafe { + let _fn: Option i32> = Some(triple_it_1); + set_op_2(_fn) + }); + assert!(((g_op) == (Some(triple_it_1)))); + assert!( + ((unsafe { + let _x: i32 = 5; + call_op_3(_x) + }) == (15)) + ); + (unsafe { + let _fn: Option i32> = None; + set_op_2(_fn) + }); + assert!((g_op).is_none()); + assert!( + ((unsafe { + let _x: i32 = 5; + call_op_3(_x) + }) == (5)) + ); + return 0; +} diff --git a/tests/unit/out/unsafe/fn_ptr_reassign.rs b/tests/unit/out/unsafe/fn_ptr_reassign.rs new file mode 100644 index 00000000..08eed4bb --- /dev/null +++ b/tests/unit/out/unsafe/fn_ptr_reassign.rs @@ -0,0 +1,61 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::Seek; +use std::io::{Read, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +pub unsafe fn add_0(mut a: i32, mut b: i32) -> i32 { + return ((a) + (b)); +} +pub unsafe fn sub_1(mut a: i32, mut b: i32) -> i32 { + return ((a) - (b)); +} +pub unsafe fn mul_2(mut a: i32, mut b: i32) -> i32 { + return ((a) * (b)); +} +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut fn_: Option i32> = Some(add_0); + assert!( + ((unsafe { + let _arg0: i32 = 3; + let _arg1: i32 = 4; + (fn_).unwrap()(_arg0, _arg1) + }) == (7)) + ); + fn_ = Some(sub_1); + assert!( + ((unsafe { + let _arg0: i32 = 10; + let _arg1: i32 = 3; + (fn_).unwrap()(_arg0, _arg1) + }) == (7)) + ); + fn_ = Some(mul_2); + assert!( + ((unsafe { + let _arg0: i32 = 6; + let _arg1: i32 = 7; + (fn_).unwrap()(_arg0, _arg1) + }) == (42)) + ); + fn_ = None; + assert!((fn_).is_none()); + fn_ = Some(add_0); + assert!(!((fn_).is_none())); + assert!( + ((unsafe { + let _arg0: i32 = 1; + let _arg1: i32 = 1; + (fn_).unwrap()(_arg0, _arg1) + }) == (2)) + ); + return 0; +} diff --git a/tests/unit/out/unsafe/fn_ptr_return.rs b/tests/unit/out/unsafe/fn_ptr_return.rs new file mode 100644 index 00000000..1cda2828 --- /dev/null +++ b/tests/unit/out/unsafe/fn_ptr_return.rs @@ -0,0 +1,53 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::Seek; +use std::io::{Read, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +pub unsafe fn inc_0(mut x: i32) -> i32 { + return ((x) + (1)); +} +pub unsafe fn dec_1(mut x: i32) -> i32 { + return ((x) - (1)); +} +pub unsafe fn pick_2(mut choose_inc: i32) -> Option i32> { + if (choose_inc != 0) { + return Some(inc_0); + } + return Some(dec_1); +} +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut f: Option i32> = (unsafe { + let _choose_inc: i32 = 1; + pick_2(_choose_inc) + }); + assert!(!((f).is_none())); + assert!(((f) == (Some(inc_0)))); + assert!( + ((unsafe { + let _arg0: i32 = 10; + (f).unwrap()(_arg0) + }) == (11)) + ); + let mut g: Option i32> = (unsafe { + let _choose_inc: i32 = 0; + pick_2(_choose_inc) + }); + assert!(((g) == (Some(dec_1)))); + assert!( + ((unsafe { + let _arg0: i32 = 10; + (g).unwrap()(_arg0) + }) == (9)) + ); + assert!(((f) != (g))); + return 0; +} diff --git a/tests/unit/out/unsafe/fn_ptr_stable_sort.rs b/tests/unit/out/unsafe/fn_ptr_stable_sort.rs new file mode 100644 index 00000000..123a880c --- /dev/null +++ b/tests/unit/out/unsafe/fn_ptr_stable_sort.rs @@ -0,0 +1,44 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::Seek; +use std::io::{Read, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +#[derive(Copy, Clone, Default)] +pub struct Item { + pub key: i32, + pub value: i32, +} +pub unsafe fn Compare_0(a: *const Item, b: *const Item) -> bool { + return (((*a).key) < ((*b).key)); +} +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut v: Vec = Vec::new(); + v.push(Item { key: 3, value: 30 }); + v.push(Item { key: 1, value: 10 }); + v.push(Item { key: 2, value: 20 }); + { + let len = v.as_mut_ptr().add(v.len()).offset_from(v.as_mut_ptr()) as usize; + ::std::slice::from_raw_parts_mut(v.as_mut_ptr(), len).sort_by(|x, y| { + if (Compare_0)(x, y) { + std::cmp::Ordering::Less + } else if (Compare_0)(y, x) { + std::cmp::Ordering::Greater + } else { + std::cmp::Ordering::Equal + } + }) + }; + assert!(((v[(0_u64) as usize].key) == (1))); + assert!(((v[(1_u64) as usize].key) == (2))); + assert!(((v[(2_u64) as usize].key) == (3))); + return 0; +} diff --git a/tests/unit/out/unsafe/fn_ptr_struct.rs b/tests/unit/out/unsafe/fn_ptr_struct.rs new file mode 100644 index 00000000..ae9e3a7f --- /dev/null +++ b/tests/unit/out/unsafe/fn_ptr_struct.rs @@ -0,0 +1,65 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::Seek; +use std::io::{Read, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +#[derive(Clone)] +pub struct Handler { + pub tag: i32, + pub cb: Option i32>, +} +impl Default for Handler { + fn default() -> Self { + Handler { + tag: 0_i32, + cb: None, + } + } +} +pub unsafe fn double_it_0(mut x: i32) -> i32 { + return ((x) * (2)); +} +pub unsafe fn negate_1(mut x: i32) -> i32 { + return -x; +} +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut h1: Handler = Handler { + tag: 1, + cb: Some(double_it_0), + }; + let mut h2: Handler = Handler { + tag: 2, + cb: Some(negate_1), + }; + assert!(!((h1.cb).is_none())); + assert!( + ((unsafe { + let _arg0: i32 = 5; + (h1.cb).unwrap()(_arg0) + }) == (10)) + ); + assert!( + ((unsafe { + let _arg0: i32 = 7; + (h2.cb).unwrap()(_arg0) + }) == (-7_i32)) + ); + (h1.cb) = Some(negate_1); + assert!( + ((unsafe { + let _arg0: i32 = 3; + (h1.cb).unwrap()(_arg0) + }) == (-3_i32)) + ); + assert!(((h1.cb) == (h2.cb))); + return 0; +} diff --git a/tests/unit/out/unsafe/fn_ptr_void_return.rs b/tests/unit/out/unsafe/fn_ptr_void_return.rs new file mode 100644 index 00000000..72ab341a --- /dev/null +++ b/tests/unit/out/unsafe/fn_ptr_void_return.rs @@ -0,0 +1,50 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::Seek; +use std::io::{Read, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +pub unsafe fn negate_0(mut x: *mut i32) { + (*x) = -(*x); +} +pub unsafe fn zero_out_1(mut x: *mut i32) { + (*x) = 0; +} +pub unsafe fn run_2(mut fn_: Option, mut x: *mut i32) { + (unsafe { + let _arg0: *mut i32 = x; + (fn_).unwrap()(_arg0) + }); +} +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut a: i32 = 42; + (unsafe { + let _fn: Option = Some(negate_0); + let _x: *mut i32 = (&mut a as *mut i32); + run_2(_fn, _x) + }); + assert!(((a) == (-42_i32))); + (unsafe { + let _fn: Option = Some(zero_out_1); + let _x: *mut i32 = (&mut a as *mut i32); + run_2(_fn, _x) + }); + assert!(((a) == (0))); + let mut fn_: Option = Some(negate_0); + assert!(!((fn_).is_none())); + let mut b: i32 = 10; + (unsafe { + let _arg0: *mut i32 = (&mut b as *mut i32); + (fn_).unwrap()(_arg0) + }); + assert!(((b) == (-10_i32))); + return 0; +} diff --git a/tests/unit/out/unsafe/fn_ptr_vtable.rs b/tests/unit/out/unsafe/fn_ptr_vtable.rs new file mode 100644 index 00000000..48e820e6 --- /dev/null +++ b/tests/unit/out/unsafe/fn_ptr_vtable.rs @@ -0,0 +1,68 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::Seek; +use std::io::{Read, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +#[derive(Clone)] +pub struct Vtable { + pub create: Option *mut ::libc::c_void>, + pub get: Option i32>, + pub destroy: Option, +} +impl Default for Vtable { + fn default() -> Self { + Vtable { + create: None, + get: None, + destroy: None, + } + } +} +pub static mut storage: i32 = 0_i32; +pub unsafe fn int_create_0(mut val: i32) -> *mut ::libc::c_void { + storage = val; + return ((&mut storage as *mut i32) as *mut i32 as *mut ::libc::c_void); +} +pub unsafe fn int_get_1(mut p: *mut ::libc::c_void) -> i32 { + return (*(p as *mut i32)); +} +pub unsafe fn int_destroy_2(mut p: *mut ::libc::c_void) { + (*(p as *mut i32)) = 0; +} +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut vt: Vtable = Vtable { + create: Some(int_create_0), + get: Some(int_get_1), + destroy: Some(int_destroy_2), + }; + assert!(!((vt.create).is_none())); + assert!(!((vt.get).is_none())); + assert!(!((vt.destroy).is_none())); + let mut obj: *mut ::libc::c_void = (unsafe { + let _arg0: i32 = 42; + (vt.create).unwrap()(_arg0) + }); + assert!( + ((unsafe { + let _arg0: *mut ::libc::c_void = obj; + (vt.get).unwrap()(_arg0) + }) == (42)) + ); + (unsafe { + let _arg0: *mut ::libc::c_void = obj; + (vt.destroy).unwrap()(_arg0) + }); + assert!(((storage) == (0))); + (vt.get) = None; + assert!((vt.get).is_none()); + return 0; +} diff --git a/tests/unit/out/unsafe/lambda_capture_pass.rs b/tests/unit/out/unsafe/lambda_capture_pass.rs new file mode 100644 index 00000000..bf1f4fa3 --- /dev/null +++ b/tests/unit/out/unsafe/lambda_capture_pass.rs @@ -0,0 +1,62 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::Seek; +use std::io::{Read, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +pub unsafe fn apply_0(mut fn_: impl Fn(i32) -> i32, mut x: i32) -> i32 { + return (unsafe { + let _x: i32 = x; + fn_(_x) + }); +} +pub unsafe fn apply_1(mut fn_: impl Fn(i32) -> i32, mut x: i32) -> i32 { + return (unsafe { + let _x: i32 = x; + fn_(_x) + }); +} +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut base: i32 = 10; + assert!( + ((unsafe { + let _fn: _ = (|x: i32| { + return ((x) + (base)); + }) + .clone(); + let _x: i32 = 5; + apply_0(_fn, _x) + }) == (15)) + ); + base = 100; + assert!( + ((unsafe { + let _fn: _ = (|x: i32| { + return ((x) + (base)); + }) + .clone(); + let _x: i32 = 5; + apply_0(_fn, _x) + }) == (105)) + ); + let mut factor: i32 = 3; + assert!( + ((unsafe { + let _fn: _ = (|x: i32| { + return ((x) * (factor)); + }) + .clone(); + let _x: i32 = 4; + apply_1(_fn, _x) + }) == (12)) + ); + return 0; +} diff --git a/tests/unit/out/unsafe/lambda_nested.rs b/tests/unit/out/unsafe/lambda_nested.rs new file mode 100644 index 00000000..542a59db --- /dev/null +++ b/tests/unit/out/unsafe/lambda_nested.rs @@ -0,0 +1,45 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::Seek; +use std::io::{Read, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut x: i32 = 10; + assert!( + ((unsafe { + let _y: i32 = 20; + (|y: i32| { + return (unsafe { + let _z: i32 = 1; + (|z: i32| { + return (((x) + (y)) + (z)); + })(_z) + }); + })(_y) + }) == (31)) + ); + x = 100; + assert!( + ((unsafe { + let _y: i32 = 20; + (|y: i32| { + return (unsafe { + let _z: i32 = 1; + (|z: i32| { + return (((x) + (y)) + (z)); + })(_z) + }); + })(_y) + }) == (121)) + ); + return 0; +} diff --git a/tests/unit/out/unsafe/no_direct_callee.rs b/tests/unit/out/unsafe/no_direct_callee.rs index 5c962fe7..b4eac215 100644 --- a/tests/unit/out/unsafe/no_direct_callee.rs +++ b/tests/unit/out/unsafe/no_direct_callee.rs @@ -10,8 +10,8 @@ use std::rc::Rc; pub unsafe fn test1_0() -> bool { return false; } -pub unsafe fn test_1(mut fn_: Rc bool>) -> i32 { - if !(unsafe { fn_() }) { +pub unsafe fn test_1(mut fn_: Option bool>) -> i32 { + if !(unsafe { (fn_).unwrap()() }) { return 1; } return 0; @@ -23,7 +23,7 @@ pub fn main() { } unsafe fn main_0() -> i32 { return (unsafe { - let _fn: Rc bool> = Rc::new(|| unsafe { test1_0() }); + let _fn: Option bool> = Some(test1_0); test_1(_fn) }); } diff --git a/tests/unit/out/unsafe/prvalue-as-lvalue.rs b/tests/unit/out/unsafe/prvalue-as-lvalue.rs index 515e0986..4d1040db 100644 --- a/tests/unit/out/unsafe/prvalue-as-lvalue.rs +++ b/tests/unit/out/unsafe/prvalue-as-lvalue.rs @@ -20,7 +20,7 @@ unsafe fn main_0() -> i32 { let mut pa: *mut i32 = (&mut a as *mut i32); let b: *const i32 = (unsafe { let _a: *const i32 = &(*pa) as *const i32; - Rc::new(|a0| unsafe { foo_0(a0) })(_a) + foo_0(_a) }); return (*b); } diff --git a/tests/unit/out/unsafe/ref_calls.rs b/tests/unit/out/unsafe/ref_calls.rs index 0c24b4a9..b32c2b28 100644 --- a/tests/unit/out/unsafe/ref_calls.rs +++ b/tests/unit/out/unsafe/ref_calls.rs @@ -26,7 +26,7 @@ unsafe fn main_0() -> i32 { })); let z: *mut i32 = (unsafe { let _x: *mut i32 = &mut x as *mut i32; - Rc::new(|a0| unsafe { foo_1(a0) })(_x) + foo_1(_x) }); return ((((*(unsafe { let _x: *mut i32 = &mut x as *mut i32;