From 117afb3ce52f18cb996a3d63518b2342d46c7281 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Mon, 13 Apr 2026 20:18:07 +0100 Subject: [PATCH 01/35] Translate free function ptr as Option --- cpp2rust/converter/converter.cpp | 33 ++++--------------- .../converter/models/converter_refcount.cpp | 2 +- 2 files changed, 7 insertions(+), 28 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 0f6f48d..64f8ee4 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -226,7 +226,7 @@ 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))); } @@ -1993,23 +1993,9 @@ bool Converter::VisitDeclRefExpr(clang::DeclRefExpr *expr) { return false; } - if (auto function = clang::dyn_cast(decl)) { + if (clang::isa(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); + StrCat(std::format("Some({})", str)); return false; } } @@ -2609,15 +2595,7 @@ bool Converter::VisitCXXStdInitializerListExpr( 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; + return "None"; } std::string Converter::GetDefaultAsString(clang::QualType qual_type) { @@ -2816,7 +2794,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()"); diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index 6c58987..a31945d 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -570,7 +570,7 @@ bool ConverterRefCount::VisitDeclRefExpr(clang::DeclRefExpr *expr) { if (clang::isa(decl)) { if (isAddrOf()) { - StrCat(std::format("Rc::new({})", str)); + StrCat(std::format("Some({})", str)); } else { StrCat(str); } From 562978b764b56bf37161e7d15573305a2e3b22ae Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Mon, 13 Apr 2026 20:18:45 +0100 Subject: [PATCH 02/35] Fix null ptr deref --- cpp2rust/converter/converter.cpp | 2 +- cpp2rust/converter/converter_lib.cpp | 24 ++++++++++++------------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 64f8ee4..23b052e 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -1384,7 +1384,7 @@ 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) { diff --git a/cpp2rust/converter/converter_lib.cpp b/cpp2rust/converter/converter_lib.cpp index ba3899a..b299bcb 100644 --- a/cpp2rust/converter/converter_lib.cpp +++ b/cpp2rust/converter/converter_lib.cpp @@ -320,18 +320,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"); From 32ae03cf4d008c92b7346a6f5c5f59b8259f3dc9 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Mon, 13 Apr 2026 20:24:41 +0100 Subject: [PATCH 03/35] Fix translation of lambdas Non-capturing lambdas are translated as Option, same as free functions, because they can be decayed to free functions. Capturing lambdas remain Rc. --- cpp2rust/converter/converter.cpp | 49 +++++++++++++++---- cpp2rust/converter/converter_lib.cpp | 11 +++++ cpp2rust/converter/converter_lib.h | 2 + .../converter/models/converter_refcount.cpp | 11 +++-- 4 files changed, 61 insertions(+), 12 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 23b052e..92f351e 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -417,6 +417,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())) { @@ -1432,7 +1435,14 @@ void Converter::ConvertGenericCallExpr(clang::CallExpr *expr) { } } - Convert(callee); + if (proto && !function) { + StrCat(token::kOpenParen); + Convert(callee); + StrCat(").unwrap()"); + } else { + PushExprKind push(*this, ExprKind::RValue); + Convert(StripFunctionPointerDecay(callee)); + } StrCat(token::kOpenParen); for (unsigned i = 0; i < num_named_params && i < num_args; ++i) { auto *arg = expr->getArg(i + arg_begin); @@ -1648,7 +1658,11 @@ bool Converter::VisitImplicitCastExpr(clang::ImplicitCastExpr *expr) { break; } case clang::CastKind::CK_FunctionToPointerDecay: - case clang::CastKind::CK_BuiltinFnToFnPtr: + case clang::CastKind::CK_BuiltinFnToFnPtr: { + PushExprKind push(*this, ExprKind::AddrOf); + Convert(sub_expr); + break; + } case clang::CastKind::CK_ConstructorConversion: case clang::CastKind::CK_DerivedToBase: Convert(sub_expr); @@ -2001,13 +2015,15 @@ bool Converter::VisitDeclRefExpr(clang::DeclRefExpr *expr) { } 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; + } } } } @@ -2466,6 +2482,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()) { @@ -2749,6 +2768,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); @@ -3180,6 +3209,8 @@ void Converter::PlaceholderCtx::dump() const { std::string Converter::ConvertPlaceholder(clang::Expr *expr, clang::Expr *arg, const PlaceholderCtx &ph_ctx) { + arg = StripFunctionPointerDecay(arg); + if (ph_ctx.needs_materialization()) { auto materialized = ph_ctx.materialize_ctx->GetOrMaterialize( static_cast(ph_ctx.materialize_idx), diff --git a/cpp2rust/converter/converter_lib.cpp b/cpp2rust/converter/converter_lib.cpp index b299bcb..26624a0 100644 --- a/cpp2rust/converter/converter_lib.cpp +++ b/cpp2rust/converter/converter_lib.cpp @@ -338,6 +338,17 @@ clang::QualType GetReturnTypeOfFunction(const clang::CallExpr *expr) { return {}; } +clang::Expr *StripFunctionPointerDecay(clang::Expr *expr) { + if (auto *ice = clang::dyn_cast(expr)) { + auto ck = ice->getCastKind(); + if (ck == clang::CK_FunctionToPointerDecay || + ck == clang::CK_BuiltinFnToFnPtr) { + return ice->getSubExpr(); + } + } + return expr; +} + std::string GetOverloadedOperator(const clang::FunctionDecl *decl) { switch (decl->getOverloadedOperator()) { case clang::OO_Less: diff --git a/cpp2rust/converter/converter_lib.h b/cpp2rust/converter/converter_lib.h index c0d2a65..68c2704 100644 --- a/cpp2rust/converter/converter_lib.h +++ b/cpp2rust/converter/converter_lib.h @@ -91,6 +91,8 @@ template llvm::SmallString<16> GetNumAsString(const T &num) { clang::QualType GetReturnTypeOfFunction(const clang::CallExpr *expr); +clang::Expr *StripFunctionPointerDecay(clang::Expr *expr); + std::string GetOverloadedOperator(const clang::FunctionDecl *decl); bool IsOverloadedComparisonOperator(const clang::CXXMethodDecl *decl); diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index a31945d..630287c 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -1477,9 +1477,14 @@ 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) { + PushExprKind addr_of(*this, ExprKind::AddrOf); + VisitLambdaExpr(lambda); + } else { + StrCat("Rc::new("); + VisitLambdaExpr(lambda); + StrCat(")"); + } str = std::move(buf).str(); } StrCat(BoxValue(std::move(str))); From c431b2953fb78665e3185b6cbd1e7e7efc69b2ce Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Mon, 13 Apr 2026 21:30:05 +0100 Subject: [PATCH 04/35] Translate type of lambda as _ instead of Rc --- cpp2rust/converter/converter.cpp | 24 +++++++++++-------- .../converter/models/converter_refcount.cpp | 2 -- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 92f351e..3ecee28 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -130,17 +130,21 @@ 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_) { + // Function parameters can't use `_`. Emit `impl Fn(args) -> ret`. + auto call_op = lambda->getLambdaCallOperator(); + StrCat("impl Fn("); + for (auto p : call_op->parameters()) { + StrCat(std::format("{},", ToStringBase(p->getType()))); + } + StrCat(")"); + if (!call_op->getReturnType()->isVoidType()) { + StrCat("->"); + StrCat(ToStringBase(call_op->getReturnType())); + } + } else { + StrCat("_"); } - StrCat(">"); return false; } } diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index 630287c..aea26e4 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -1481,9 +1481,7 @@ void ConverterRefCount::ConvertVarInit(clang::QualType qual_type, PushExprKind addr_of(*this, ExprKind::AddrOf); VisitLambdaExpr(lambda); } else { - StrCat("Rc::new("); VisitLambdaExpr(lambda); - StrCat(")"); } str = std::move(buf).str(); } From de9631532363467302be125e2ed3a2fbd772e8f3 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Mon, 13 Apr 2026 21:30:42 +0100 Subject: [PATCH 05/35] Translate non-const globals as static mut --- cpp2rust/converter/converter.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 3ecee28..f8542c8 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -387,9 +387,15 @@ bool Converter::ConvertVarDeclSkipInit(clang::VarDecl *decl) { return false; } StrCat(AccessSpecifierAsString(decl->getAccess()), keyword::kStatic); + if (!qual_type.isConstQualified()) { + StrCat(keyword_mut_); + } ENSURE(decl_ids_.insert(GetID(decl)).second); } else if (decl->isStaticLocal()) { StrCat(keyword::kStatic); + if (!qual_type.isConstQualified()) { + StrCat(keyword_mut_); + } } else if (decl->isLocalVarDecl()) { StrCat(keyword::kLet); } From 212d22bb67c1f993ac7bc7f4eb64aa788952440c Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Mon, 13 Apr 2026 21:31:32 +0100 Subject: [PATCH 06/35] Use concerete default val for initializing globals --- cpp2rust/converter/converter.cpp | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index f8542c8..a17e27a 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -1687,7 +1687,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: @@ -2686,18 +2690,18 @@ std::string Converter::GetDefaultAsString(clang::QualType qual_type) { } std::string Converter::GetDefaultAsStringFallback(clang::QualType qual_type) { - static llvm::DenseMap default_for_type = { - {clang::BuiltinType::Char_U, "0_u8"}, - {clang::BuiltinType::SChar, "0_i8"}, - {clang::BuiltinType::UChar, "0_u8"}, - }; - qual_type = qual_type.getUnqualifiedType().getCanonicalType(); - if (auto builtin = qual_type->getAs()) { - auto it = default_for_type.find(builtin->getKind()); - if (it != default_for_type.end()) { - return it->second; - } + + if (qual_type->isBooleanType()) { + return "false"; + } + + if (qual_type->isIntegerType()) { + return std::format("0 as {}", ToString(qual_type)); + } + + if (qual_type->isFloatingType()) { + return std::format("0.0 as {}", ToString(qual_type)); } return std::format("<{}>::default()", ToString(qual_type)); From 58c39b9ef0f144e8ff7b212720ee049062d2fbcb Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Mon, 13 Apr 2026 21:31:53 +0100 Subject: [PATCH 07/35] Help the compiler deduce the type of a function --- cpp2rust/converter/converter.cpp | 2 +- cpp2rust/converter/models/converter_refcount.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index a17e27a..95ae9d3 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -2023,7 +2023,7 @@ bool Converter::VisitDeclRefExpr(clang::DeclRefExpr *expr) { if (clang::isa(decl)) { if (isAddrOf()) { - StrCat(std::format("Some({})", str)); + StrCat(std::format("Some({} as _)", str)); return false; } } diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index aea26e4..8234a2c 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -570,7 +570,7 @@ bool ConverterRefCount::VisitDeclRefExpr(clang::DeclRefExpr *expr) { if (clang::isa(decl)) { if (isAddrOf()) { - StrCat(std::format("Some({})", str)); + StrCat(std::format("Some({} as _)", str)); } else { StrCat(str); } From 12a44335ca2493122601fa68d9993cf8e23a6c98 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Mon, 13 Apr 2026 21:32:10 +0100 Subject: [PATCH 08/35] Don't add &mut in function ptr conditionals --- cpp2rust/converter/converter.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 95ae9d3..747a002 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -1962,12 +1962,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()); From 7ab067db8637f5ed22319e8f352d7d6718564345 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Mon, 13 Apr 2026 21:32:49 +0100 Subject: [PATCH 09/35] Add fn_ptr and lambda tests --- tests/unit/fn_ptr.cpp | 21 ++++ tests/unit/fn_ptr_array.cpp | 21 ++++ tests/unit/fn_ptr_as_condition.cpp | 33 +++++++ tests/unit/fn_ptr_cast.cpp | 44 +++++++++ tests/unit/fn_ptr_conditional.cpp | 27 ++++++ tests/unit/fn_ptr_default_arg.cpp | 23 +++++ tests/unit/fn_ptr_global.cpp | 36 +++++++ tests/unit/fn_ptr_reassign.cpp | 27 ++++++ tests/unit/fn_ptr_return.cpp | 27 ++++++ tests/unit/fn_ptr_stable_sort.cpp | 25 +++++ tests/unit/fn_ptr_stdlib_compare.cpp | 32 ++++++ tests/unit/fn_ptr_struct.cpp | 26 +++++ tests/unit/fn_ptr_void_return.cpp | 27 ++++++ tests/unit/fn_ptr_vtable.cpp | 41 ++++++++ tests/unit/lambda_capture_pass.cpp | 20 ++++ tests/unit/lambda_nested.cpp | 17 ++++ tests/unit/out/refcount/fn_ptr.rs | 48 +++++++++ tests/unit/out/refcount/fn_ptr_array.rs | 59 +++++++++++ .../unit/out/refcount/fn_ptr_as_condition.rs | 59 +++++++++++ tests/unit/out/refcount/fn_ptr_cast.rs | 97 +++++++++++++++++++ tests/unit/out/refcount/fn_ptr_conditional.rs | 97 +++++++++++++++++++ tests/unit/out/refcount/fn_ptr_default_arg.rs | 62 ++++++++++++ tests/unit/out/refcount/fn_ptr_global.rs | 86 ++++++++++++++++ tests/unit/out/refcount/fn_ptr_reassign.rs | 65 +++++++++++++ tests/unit/out/refcount/fn_ptr_return.rs | 67 +++++++++++++ tests/unit/out/refcount/fn_ptr_stable_sort.rs | 80 +++++++++++++++ tests/unit/out/refcount/fn_ptr_struct.rs | 78 +++++++++++++++ tests/unit/out/refcount/fn_ptr_void_return.rs | 53 ++++++++++ tests/unit/out/refcount/fn_ptr_vtable.rs | 84 ++++++++++++++++ .../unit/out/refcount/lambda_capture_local.rs | 74 ++++++++++++++ .../unit/out/refcount/lambda_capture_pass.rs | 69 +++++++++++++ tests/unit/out/refcount/lambda_nested.rs | 45 +++++++++ tests/unit/out/refcount/lambda_nocapture.rs | 74 ++++++++++++++ tests/unit/out/unsafe/fn_ptr.rs | 43 ++++++++ tests/unit/out/unsafe/fn_ptr_array.rs | 52 ++++++++++ tests/unit/out/unsafe/fn_ptr_as_condition.rs | 54 +++++++++++ tests/unit/out/unsafe/fn_ptr_cast.rs | 69 +++++++++++++ tests/unit/out/unsafe/fn_ptr_conditional.rs | 92 ++++++++++++++++++ tests/unit/out/unsafe/fn_ptr_default_arg.rs | 61 ++++++++++++ tests/unit/out/unsafe/fn_ptr_global.rs | 76 +++++++++++++++ tests/unit/out/unsafe/fn_ptr_mapped.rs | 45 +++++++++ tests/unit/out/unsafe/fn_ptr_reassign.rs | 61 ++++++++++++ tests/unit/out/unsafe/fn_ptr_return.rs | 53 ++++++++++ tests/unit/out/unsafe/fn_ptr_stable_sort.rs | 44 +++++++++ tests/unit/out/unsafe/fn_ptr_struct.rs | 65 +++++++++++++ tests/unit/out/unsafe/fn_ptr_void_return.rs | 50 ++++++++++ tests/unit/out/unsafe/fn_ptr_vtable.rs | 68 +++++++++++++ tests/unit/out/unsafe/lambda_capture_local.rs | 72 ++++++++++++++ tests/unit/out/unsafe/lambda_capture_pass.rs | 62 ++++++++++++ tests/unit/out/unsafe/lambda_nested.rs | 45 +++++++++ tests/unit/out/unsafe/lambda_nocapture.rs | 64 ++++++++++++ 51 files changed, 2720 insertions(+) create mode 100644 tests/unit/fn_ptr.cpp create mode 100644 tests/unit/fn_ptr_array.cpp create mode 100644 tests/unit/fn_ptr_as_condition.cpp create mode 100644 tests/unit/fn_ptr_cast.cpp create mode 100644 tests/unit/fn_ptr_conditional.cpp create mode 100644 tests/unit/fn_ptr_default_arg.cpp create mode 100644 tests/unit/fn_ptr_global.cpp create mode 100644 tests/unit/fn_ptr_reassign.cpp create mode 100644 tests/unit/fn_ptr_return.cpp create mode 100644 tests/unit/fn_ptr_stable_sort.cpp create mode 100644 tests/unit/fn_ptr_stdlib_compare.cpp create mode 100644 tests/unit/fn_ptr_struct.cpp create mode 100644 tests/unit/fn_ptr_void_return.cpp create mode 100644 tests/unit/fn_ptr_vtable.cpp create mode 100644 tests/unit/lambda_capture_pass.cpp create mode 100644 tests/unit/lambda_nested.cpp create mode 100644 tests/unit/out/refcount/fn_ptr.rs create mode 100644 tests/unit/out/refcount/fn_ptr_array.rs create mode 100644 tests/unit/out/refcount/fn_ptr_as_condition.rs create mode 100644 tests/unit/out/refcount/fn_ptr_cast.rs create mode 100644 tests/unit/out/refcount/fn_ptr_conditional.rs create mode 100644 tests/unit/out/refcount/fn_ptr_default_arg.rs create mode 100644 tests/unit/out/refcount/fn_ptr_global.rs create mode 100644 tests/unit/out/refcount/fn_ptr_reassign.rs create mode 100644 tests/unit/out/refcount/fn_ptr_return.rs create mode 100644 tests/unit/out/refcount/fn_ptr_stable_sort.rs create mode 100644 tests/unit/out/refcount/fn_ptr_struct.rs create mode 100644 tests/unit/out/refcount/fn_ptr_void_return.rs create mode 100644 tests/unit/out/refcount/fn_ptr_vtable.rs create mode 100644 tests/unit/out/refcount/lambda_capture_local.rs create mode 100644 tests/unit/out/refcount/lambda_capture_pass.rs create mode 100644 tests/unit/out/refcount/lambda_nested.rs create mode 100644 tests/unit/out/refcount/lambda_nocapture.rs create mode 100644 tests/unit/out/unsafe/fn_ptr.rs create mode 100644 tests/unit/out/unsafe/fn_ptr_array.rs create mode 100644 tests/unit/out/unsafe/fn_ptr_as_condition.rs create mode 100644 tests/unit/out/unsafe/fn_ptr_cast.rs create mode 100644 tests/unit/out/unsafe/fn_ptr_conditional.rs create mode 100644 tests/unit/out/unsafe/fn_ptr_default_arg.rs create mode 100644 tests/unit/out/unsafe/fn_ptr_global.rs create mode 100644 tests/unit/out/unsafe/fn_ptr_mapped.rs create mode 100644 tests/unit/out/unsafe/fn_ptr_reassign.rs create mode 100644 tests/unit/out/unsafe/fn_ptr_return.rs create mode 100644 tests/unit/out/unsafe/fn_ptr_stable_sort.rs create mode 100644 tests/unit/out/unsafe/fn_ptr_struct.rs create mode 100644 tests/unit/out/unsafe/fn_ptr_void_return.rs create mode 100644 tests/unit/out/unsafe/fn_ptr_vtable.rs create mode 100644 tests/unit/out/unsafe/lambda_capture_local.rs create mode 100644 tests/unit/out/unsafe/lambda_capture_pass.rs create mode 100644 tests/unit/out/unsafe/lambda_nested.rs create mode 100644 tests/unit/out/unsafe/lambda_nocapture.rs diff --git a/tests/unit/fn_ptr.cpp b/tests/unit/fn_ptr.cpp new file mode 100644 index 0000000..c7c9c7e --- /dev/null +++ b/tests/unit/fn_ptr.cpp @@ -0,0 +1,21 @@ +#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 0000000..f7521fa --- /dev/null +++ b/tests/unit/fn_ptr_array.cpp @@ -0,0 +1,21 @@ +#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 0000000..5817f7e --- /dev/null +++ b/tests/unit/fn_ptr_as_condition.cpp @@ -0,0 +1,33 @@ +#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 0000000..d9fc7ba --- /dev/null +++ b/tests/unit/fn_ptr_cast.cpp @@ -0,0 +1,44 @@ +#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); +} + +int main() { + test_roundtrip(); + test_double_cast(); + test_void_ptr_to_fn(); + return 0; +} diff --git a/tests/unit/fn_ptr_conditional.cpp b/tests/unit/fn_ptr_conditional.cpp new file mode 100644 index 0000000..ad39614 --- /dev/null +++ b/tests/unit/fn_ptr_conditional.cpp @@ -0,0 +1,27 @@ +#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 0000000..c5e0f55 --- /dev/null +++ b/tests/unit/fn_ptr_default_arg.cpp @@ -0,0 +1,23 @@ +#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 0000000..5ff3082 --- /dev/null +++ b/tests/unit/fn_ptr_global.cpp @@ -0,0 +1,36 @@ +#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 0000000..b8dc48f --- /dev/null +++ b/tests/unit/fn_ptr_reassign.cpp @@ -0,0 +1,27 @@ +#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 0000000..6e57093 --- /dev/null +++ b/tests/unit/fn_ptr_return.cpp @@ -0,0 +1,27 @@ +#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 0000000..8361b5a --- /dev/null +++ b/tests/unit/fn_ptr_stable_sort.cpp @@ -0,0 +1,25 @@ +#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_stdlib_compare.cpp b/tests/unit/fn_ptr_stdlib_compare.cpp new file mode 100644 index 0000000..e2ca1c3 --- /dev/null +++ b/tests/unit/fn_ptr_stdlib_compare.cpp @@ -0,0 +1,32 @@ +#include +#include +#include + +typedef size_t (*read_fn)(void *, size_t, size_t, FILE *); +typedef void (*free_fn)(void *); +typedef void *(*malloc_fn)(size_t); + +int main() { + read_fn rfn = fread; + assert(rfn == fread); + assert(rfn != nullptr); + + free_fn ffn = free; + assert(ffn == free); + assert(ffn != nullptr); + + malloc_fn mfn = malloc; + assert(mfn == malloc); + assert(mfn != nullptr); + + // Reassign and compare + read_fn rfn2 = fread; + assert(rfn == rfn2); + + free_fn ffn2 = nullptr; + assert(ffn != ffn2); + ffn2 = free; + assert(ffn == ffn2); + + return 0; +} diff --git a/tests/unit/fn_ptr_struct.cpp b/tests/unit/fn_ptr_struct.cpp new file mode 100644 index 0000000..55216e7 --- /dev/null +++ b/tests/unit/fn_ptr_struct.cpp @@ -0,0 +1,26 @@ +#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 0000000..ebf7b39 --- /dev/null +++ b/tests/unit/fn_ptr_void_return.cpp @@ -0,0 +1,27 @@ +#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 0000000..8d318a5 --- /dev/null +++ b/tests/unit/fn_ptr_vtable.cpp @@ -0,0 +1,41 @@ +#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 0000000..1a7637f --- /dev/null +++ b/tests/unit/lambda_capture_pass.cpp @@ -0,0 +1,20 @@ +#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 0000000..f7f26e9 --- /dev/null +++ b/tests/unit/lambda_nested.cpp @@ -0,0 +1,17 @@ +#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/fn_ptr.rs b/tests/unit/out/refcount/fn_ptr.rs new file mode 100644 index 0000000..77a3f29 --- /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_: Option 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()).unwrap()(_arg0) + }); +} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let fn_: Value i32>> = Rc::new(RefCell::new(None)); + assert!((*fn_.borrow()).is_none()); + assert!({ + let _lhs = (*fn_.borrow()).clone(); + _lhs != Some(my_foo_0 as _) + }); + (*fn_.borrow_mut()) = Some(my_foo_0 as _); + assert!(!((*fn_.borrow()).is_none())); + assert!({ + let _lhs = (*fn_.borrow()).clone(); + _lhs == Some(my_foo_0 as _) + }); + let a: Value = Rc::new(RefCell::new(10)); + assert!({ + let _lhs = ({ + let _fn: Option 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 0000000..3323c92 --- /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([ + Some(add_0 as _), + Some(sub_1 as _), + Some(mul_2 as _), + ]))); + assert!( + (({ + let _arg0: i32 = 2; + let _arg1: i32 = 3; + ((*ops.borrow())[(0) as usize]).unwrap()(_arg0, _arg1) + }) == 5) + ); + assert!( + (({ + let _arg0: i32 = 7; + let _arg1: i32 = 4; + ((*ops.borrow())[(1) as usize]).unwrap()(_arg0, _arg1) + }) == 3) + ); + assert!( + (({ + let _arg0: i32 = 6; + let _arg1: i32 = 5; + ((*ops.borrow())[(2) as usize]).unwrap()(_arg0, _arg1) + }) == 30) + ); + assert!(!(((*ops.borrow())[(0) as usize]).is_none())); + assert!(((*ops.borrow())[(0) as usize] == Some(add_0 as _))); + assert!(((*ops.borrow())[(0) as usize] != Some(sub_1 as _))); + 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 0000000..5547185 --- /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: Option)>, x: Ptr) { + let cb: Value)>> = Rc::new(RefCell::new(cb)); + let x: Value> = Rc::new(RefCell::new(x)); + if !(*cb.borrow()).is_none() { + ({ + let _arg0: Ptr = (*x.borrow()).clone(); + (*cb.borrow()).unwrap()(_arg0) + }); + } +} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let a: Value = Rc::new(RefCell::new(5)); + ({ + let _cb: Option)> = Some(double_it_0 as _); + 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: Option)> = None; + let _x: Ptr = (b.as_pointer()); + maybe_call_1(_cb, _x) + }); + assert!(((*b.borrow()) == 5)); + let fn_: Value)>> = Rc::new(RefCell::new(None)); + if !!(*fn_.borrow()).is_none() { + (*fn_.borrow_mut()) = (Some(double_it_0 as _)).clone(); + } + let c: Value = Rc::new(RefCell::new(3)); + if !(*fn_.borrow()).is_none() { + ({ + let _arg0: Ptr = (c.as_pointer()); + (*fn_.borrow()).unwrap()(_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 0000000..cb0f77d --- /dev/null +++ b/tests/unit/out/refcount/fn_ptr_cast.rs @@ -0,0 +1,97 @@ +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(Some(double_it_0 as _))); + assert!( + (({ + let _arg0: i32 = 5; + (*fn_.borrow()).unwrap()(_arg0) + }) == 10) + ); + let gfn: Value> = Rc::new(RefCell::new( + ((*fn_.borrow()).to_strong().as_pointer() as Value>).clone(), + )); + assert!(!((*gfn.borrow()).is_none())); + let fn2: Value i32>> = Rc::new(RefCell::new( + ((*gfn.borrow()).to_strong().as_pointer() as Value i32>>).clone(), + )); + assert!( + (({ + let _arg0: i32 = 5; + (*fn2.borrow()).unwrap()(_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(Some(double_it_0 as _))); + let fn2: Value i32>> = Rc::new(RefCell::new( + (((*fn_.borrow()).to_strong().as_pointer() as Value>) + .to_strong() + .as_pointer() as Value i32>>) + .clone(), + )); + assert!( + (({ + let _arg0: i32 = 5; + (*fn2.borrow()).unwrap()(_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()) = + (Some(double_it_0 as _).to_strong().as_pointer() as AnyPtr); + let fn_: Value i32>> = Rc::new(RefCell::new( + ((*(*cmd.borrow()).data.borrow()) + .cast::() + .expect("ub:wrong type")) + .clone(), + )); + assert!( + (({ + let _arg0: i32 = 5; + (*fn_.borrow()).unwrap()(_arg0) + }) == 10) + ); +} +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() }); + 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 0000000..6cc940a --- /dev/null +++ b/tests/unit/out/refcount/fn_ptr_conditional.rs @@ -0,0 +1,97 @@ +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) -> Option i32> { + let mode: Value = Rc::new(RefCell::new(mode)); + return if ((*mode.borrow()) > 0) { + Some(inc_0 as _) + } else { + if ((*mode.borrow()) < 0) { + Some(dec_1 as _) + } else { + Some(identity_2 as _) + } + }; +} +pub fn apply_4(fn_: Option 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_none() { + (*fn_.borrow()).clone() + } else { + Some(identity_2 as _) + })); + return ({ + let _arg0: i32 = (*x.borrow()); + (*actual.borrow()).unwrap()(_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) + }) + .unwrap()(_arg0) + }) == 11) + ); + assert!( + (({ + let _arg0: i32 = 10; + ({ + let _mode: i32 = -1_i32; + pick_3(_mode) + }) + .unwrap()(_arg0) + }) == 9) + ); + assert!( + (({ + let _arg0: i32 = 10; + ({ + let _mode: i32 = 0; + pick_3(_mode) + }) + .unwrap()(_arg0) + }) == 10) + ); + assert!( + (({ + let _fn: Option i32> = Some(inc_0 as _); + let _x: i32 = 5; + apply_4(_fn, _x) + }) == 6) + ); + assert!( + (({ + let _fn: Option i32> = None; + 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 0000000..68af5d9 --- /dev/null +++ b/tests/unit/out/refcount/fn_ptr_default_arg.rs @@ -0,0 +1,62 @@ +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(None))); + if !(*fn_.borrow()).is_none() { + return ({ + let _arg0: i32 = (*x.borrow()); + (*fn_.borrow()).unwrap()(_arg0) + }); + } + return (*x.borrow()); +} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + assert!( + (({ + let _x: i32 = 5; + let _fn: Option i32> = Default::default(); + apply_1(_x, Some(_fn)) + }) == 5) + ); + assert!( + (({ + let _x: i32 = 5; + let _fn: Option i32> = None; + apply_1(_x, Some(_fn)) + }) == 5) + ); + assert!( + (({ + let _x: i32 = 5; + let _fn: Option i32> = Some(identity_0 as _); + apply_1(_x, Some(_fn)) + }) == 5) + ); + let negate: Value i32>> = Rc::new(RefCell::new(Some(|x: i32| { + let x: Value = Rc::new(RefCell::new(x)); + return -(*x.borrow()); + }))); + assert!( + (({ + let _x: i32 = 5; + let _fn: Option 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 0000000..c7bf056 --- /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(None)); +); +pub fn set_op_2(fn_: Option 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_none() { + return ({ + let _arg0: i32 = (*x.borrow()); + (*g_op.with(Value::clone).borrow()).unwrap()(_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: Option i32> = Some(double_it_0 as _); + set_op_2(_fn) + }); + assert!(!((*g_op.with(Value::clone).borrow()).is_none())); + assert!({ + let _lhs = (*g_op.with(Value::clone).borrow()).clone(); + _lhs == Some(double_it_0 as _) + }); + assert!( + (({ + let _x: i32 = 5; + call_op_3(_x) + }) == 10) + ); + ({ + let _fn: Option i32> = Some(triple_it_1 as _); + set_op_2(_fn) + }); + assert!({ + let _lhs = (*g_op.with(Value::clone).borrow()).clone(); + _lhs == Some(triple_it_1 as _) + }); + assert!( + (({ + let _x: i32 = 5; + call_op_3(_x) + }) == 15) + ); + ({ + let _fn: Option i32> = None; + set_op_2(_fn) + }); + assert!((*g_op.with(Value::clone).borrow()).is_none()); + 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 0000000..98f6def --- /dev/null +++ b/tests/unit/out/refcount/fn_ptr_reassign.rs @@ -0,0 +1,65 @@ +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(Some(add_0 as _))); + assert!( + (({ + let _arg0: i32 = 3; + let _arg1: i32 = 4; + (*fn_.borrow()).unwrap()(_arg0, _arg1) + }) == 7) + ); + (*fn_.borrow_mut()) = Some(sub_1 as _); + assert!( + (({ + let _arg0: i32 = 10; + let _arg1: i32 = 3; + (*fn_.borrow()).unwrap()(_arg0, _arg1) + }) == 7) + ); + (*fn_.borrow_mut()) = Some(mul_2 as _); + assert!( + (({ + let _arg0: i32 = 6; + let _arg1: i32 = 7; + (*fn_.borrow()).unwrap()(_arg0, _arg1) + }) == 42) + ); + (*fn_.borrow_mut()) = None; + assert!((*fn_.borrow()).is_none()); + (*fn_.borrow_mut()) = Some(add_0 as _); + assert!(!((*fn_.borrow()).is_none())); + assert!( + (({ + let _arg0: i32 = 1; + let _arg1: i32 = 1; + (*fn_.borrow()).unwrap()(_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 0000000..9dead5c --- /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) -> Option i32> { + let choose_inc: Value = Rc::new(RefCell::new(choose_inc)); + if ((*choose_inc.borrow()) != 0) { + return Some(inc_0 as _); + } + return Some(dec_1 as _); +} +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_none())); + assert!({ + let _lhs = (*f.borrow()).clone(); + _lhs == Some(inc_0 as _) + }); + assert!( + (({ + let _arg0: i32 = 10; + (*f.borrow()).unwrap()(_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 == Some(dec_1 as _) + }); + assert!( + (({ + let _arg0: i32 = 10; + (*g.borrow()).unwrap()(_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 0000000..2770c95 --- /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 0000000..433b3f4 --- /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(None)), + } + } +} +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(Some(double_it_0 as _))), + })); + let h2: Value = Rc::new(RefCell::new(Handler { + tag: Rc::new(RefCell::new(2)), + cb: Rc::new(RefCell::new(Some(negate_1 as _))), + })); + assert!(!((*(*h1.borrow()).cb.borrow()).is_none())); + assert!( + (({ + let _arg0: i32 = 5; + (*(*h1.borrow()).cb.borrow()).unwrap()(_arg0) + }) == 10) + ); + assert!( + (({ + let _arg0: i32 = 7; + (*(*h2.borrow()).cb.borrow()).unwrap()(_arg0) + }) == -7_i32) + ); + (*(*h1.borrow()).cb.borrow_mut()) = Some(negate_1 as _); + assert!( + (({ + let _arg0: i32 = 3; + (*(*h1.borrow()).cb.borrow()).unwrap()(_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 0000000..9c2011b --- /dev/null +++ b/tests/unit/out/refcount/fn_ptr_void_return.rs @@ -0,0 +1,53 @@ +extern crate libcc2rs; +use libcc2rs::*; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::io::prelude::*; +use std::io::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_: Option)>, 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()).unwrap()(_arg0) + }); +} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let a: Value = Rc::new(RefCell::new(42)); + ({ + let _fn: Option)> = Some(negate_0 as _); + let _x: Ptr = (a.as_pointer()); + run_2(_fn, _x) + }); + assert!(((*a.borrow()) == -42_i32)); + ({ + let _fn: Option)> = Some(zero_out_1 as _); + let _x: Ptr = (a.as_pointer()); + run_2(_fn, _x) + }); + assert!(((*a.borrow()) == 0)); + let fn_: Value)>> = Rc::new(RefCell::new(Some(negate_0 as _))); + assert!(!((*fn_.borrow()).is_none())); + let b: Value = Rc::new(RefCell::new(10)); + ({ + let _arg0: Ptr = (b.as_pointer()); + (*fn_.borrow()).unwrap()(_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 0000000..a9128c9 --- /dev/null +++ b/tests/unit/out/refcount/fn_ptr_vtable.rs @@ -0,0 +1,84 @@ +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(None)), + get: Rc::new(RefCell::new(None)), + destroy: Rc::new(RefCell::new(None)), + } + } +} +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((Some(int_create_0 as _)).clone())), + get: Rc::new(RefCell::new(Some(int_get_1 as _))), + destroy: Rc::new(RefCell::new(Some(int_destroy_2 as _))), + })); + assert!(!((*(*vt.borrow()).create.borrow()).is_none())); + assert!(!((*(*vt.borrow()).get.borrow()).is_none())); + assert!(!((*(*vt.borrow()).destroy.borrow()).is_none())); + let obj: Value = Rc::new(RefCell::new( + ({ + let _arg0: i32 = 42; + (*(*vt.borrow()).create.borrow()).unwrap()(_arg0) + }), + )); + assert!( + (({ + let _arg0: AnyPtr = (*obj.borrow()).clone(); + (*(*vt.borrow()).get.borrow()).unwrap()(_arg0) + }) == 42) + ); + ({ + let _arg0: AnyPtr = (*obj.borrow()).clone(); + (*(*vt.borrow()).destroy.borrow()).unwrap()(_arg0) + }); + assert!(((*storage.with(Value::clone).borrow()) == 0)); + (*(*vt.borrow()).get.borrow_mut()) = None; + assert!((*(*vt.borrow()).get.borrow()).is_none()); + return 0; +} diff --git a/tests/unit/out/refcount/lambda_capture_local.rs b/tests/unit/out/refcount/lambda_capture_local.rs new file mode 100644 index 0000000..5b4a525 --- /dev/null +++ b/tests/unit/out/refcount/lambda_capture_local.rs @@ -0,0 +1,74 @@ +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 base: Value = Rc::new(RefCell::new(10)); + let factor: Value = Rc::new(RefCell::new(3)); + let add_base: Value i32>> = Rc::new(RefCell::new(Rc::new( + (|x: i32| { + let x: Value = Rc::new(RefCell::new(x)); + return ((*x.borrow()) + (*base.borrow())); + }), + ))); + let scale: Value i32>> = Rc::new(RefCell::new(Rc::new( + (|x: i32| { + let x: Value = Rc::new(RefCell::new(x)); + return ((*x.borrow()) * (*factor.borrow())); + }), + ))); + assert!( + (({ + let _x: i32 = 5; + (*add_base.borrow())(_x) + }) == 15) + ); + assert!( + (({ + let _x: i32 = 4; + (*scale.borrow())(_x) + }) == 12) + ); + (*base.borrow_mut()) = 100; + assert!( + (({ + let _x: i32 = 5; + (*add_base.borrow())(_x) + }) == 105) + ); + assert!( + (({ + let _x: i32 = 4; + (*scale.borrow())(_x) + }) == 12) + ); + let sum: Value = Rc::new(RefCell::new(0)); + let accumulate: Value> = Rc::new(RefCell::new(Rc::new( + (|x: i32| { + let x: Value = Rc::new(RefCell::new(x)); + (*sum.borrow_mut()) += (*x.borrow()); + }), + ))); + ({ + let _x: i32 = 1; + (*accumulate.borrow())(_x) + }); + ({ + let _x: i32 = 2; + (*accumulate.borrow())(_x) + }); + ({ + let _x: i32 = 3; + (*accumulate.borrow())(_x) + }); + assert!(((*sum.borrow()) == 6)); + 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 0000000..d7e0865 --- /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())(_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())(_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 0000000..d562d80 --- /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())(_z) + }) + .clone(); + }), + )); + assert!( + (({ + let _y: i32 = 20; + (*outer.borrow())(_y) + }) == 31) + ); + (*x.borrow_mut()) = 100; + assert!( + (({ + let _y: i32 = 20; + (*outer.borrow())(_y) + }) == 121) + ); + return 0; +} diff --git a/tests/unit/out/refcount/lambda_nocapture.rs b/tests/unit/out/refcount/lambda_nocapture.rs new file mode 100644 index 0000000..6936dc8 --- /dev/null +++ b/tests/unit/out/refcount/lambda_nocapture.rs @@ -0,0 +1,74 @@ +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 call_0(f: Option i32>, a: i32, b: i32) -> i32 { + let f: Value i32>> = Rc::new(RefCell::new(f)); + let a: Value = Rc::new(RefCell::new(a)); + let b: Value = Rc::new(RefCell::new(b)); + return ({ + let _arg0: i32 = (*a.borrow()); + let _arg1: i32 = (*b.borrow()); + (*f.borrow()).unwrap()(_arg0, _arg1) + }); +} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let add: Value i32>> = Rc::new(RefCell::new(Some(|a: i32, b: i32| { + let a: Value = Rc::new(RefCell::new(a)); + let b: Value = Rc::new(RefCell::new(b)); + return ((*a.borrow()) + (*b.borrow())); + }))); + let sub: Value i32>> = Rc::new(RefCell::new(Some(|a: i32, b: i32| { + let a: Value = Rc::new(RefCell::new(a)); + let b: Value = Rc::new(RefCell::new(b)); + return ((*a.borrow()) - (*b.borrow())); + }))); + assert!(!((*add.borrow()).is_none())); + assert!({ + let _lhs = (*add.borrow()).clone(); + _lhs != (*sub.borrow()).clone() + }); + assert!( + (({ + let _arg0: i32 = 2; + let _arg1: i32 = 3; + (*add.borrow()).unwrap()(_arg0, _arg1) + }) == 5) + ); + assert!( + (({ + let _arg0: i32 = 10; + let _arg1: i32 = 4; + (*sub.borrow()).unwrap()(_arg0, _arg1) + }) == 6) + ); + assert!( + (({ + let _f: Option i32> = (*add.borrow()).clone(); + let _a: i32 = 7; + let _b: i32 = 8; + call_0(_f, _a, _b) + }) == 15) + ); + assert!( + (({ + let _f: Option i32> = Some(|a: i32, b: i32| { + let a: Value = Rc::new(RefCell::new(a)); + let b: Value = Rc::new(RefCell::new(b)); + return ((*a.borrow()) * (*b.borrow())); + }); + let _a: i32 = 6; + let _b: i32 = 7; + call_0(_f, _a, _b) + }) == 42) + ); + return 0; +} diff --git a/tests/unit/out/unsafe/fn_ptr.rs b/tests/unit/out/unsafe/fn_ptr.rs new file mode 100644 index 0000000..cc9d4ae --- /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 as _)))); + fn_ = Some(my_foo_0 as _); + assert!(!((fn_).is_none())); + assert!(((fn_) == (Some(my_foo_0 as _)))); + 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 0000000..f69829e --- /dev/null +++ b/tests/unit/out/unsafe/fn_ptr_array.rs @@ -0,0 +1,52 @@ +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 as _), Some(sub_1 as _), Some(mul_2 as _)]; + 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 as _)))); + assert!(((ops[(0) as usize]) != (Some(sub_1 as _)))); + 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 0000000..ce851f5 --- /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 as _); + 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 as _); + } + 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 0000000..caf6a62 --- /dev/null +++ b/tests/unit/out/unsafe/fn_ptr_cast.rs @@ -0,0 +1,69 @@ +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 as _); + assert!( + ((unsafe { + let _arg0: i32 = 5; + (fn_).unwrap()(_arg0) + }) == (10)) + ); + let mut gfn: Option = (fn_ as Option); + assert!(!((gfn).is_none())); + let mut fn2: Option i32> = (gfn as Option i32>); + 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 as _); + let mut fn2: Option i32> = + ((fn_ as Option) as Option i32>); + 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 = (Some(double_it_0 as _) as *mut ::libc::c_void); + let mut fn_: Option i32> = (cmd.data as Option i32>); + assert!( + ((unsafe { + let _arg0: i32 = 5; + (fn_).unwrap()(_arg0) + }) == (10)) + ); +} +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() }); + 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 0000000..adfad96 --- /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 as _) + } else { + if ((mode) < (0)) { + Some(dec_1 as _) + } else { + Some(identity_2 as _) + } + }; +} +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 as _) + }; + 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 as _); + 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 0000000..5decf93 --- /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 as _); + 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 0000000..d4ce4c2 --- /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 as _); + set_op_2(_fn) + }); + assert!(!((g_op).is_none())); + assert!(((g_op) == (Some(double_it_0 as _)))); + assert!( + ((unsafe { + let _x: i32 = 5; + call_op_3(_x) + }) == (10)) + ); + (unsafe { + let _fn: Option i32> = Some(triple_it_1 as _); + set_op_2(_fn) + }); + assert!(((g_op) == (Some(triple_it_1 as _)))); + 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_mapped.rs b/tests/unit/out/unsafe/fn_ptr_mapped.rs new file mode 100644 index 0000000..e19a1f5 --- /dev/null +++ b/tests/unit/out/unsafe/fn_ptr_mapped.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 unsafe fn foo_0( + mut fn_: Rc u64>, + mut p: *mut ::libc::c_void, + mut size: u64, + mut nmemb: u64, + mut f: *mut ::std::fs::File, +) -> u64 { + return (unsafe { + let _arg0: *mut ::libc::c_void = p; + let _arg1: u64 = size; + let _arg2: u64 = nmemb; + let _arg3: *mut ::std::fs::File = f; + fn_(_arg0, _arg1, _arg2, _arg3) + }); +} +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut fn_: Rc u64> = + (Rc::new(|a0, a1, a2, a3| unsafe { fread_1(a0, a1, a2, a3) }) + as Rc u64>); + (unsafe { + let _fn: Rc u64> = + Rc::new(|a0, a1, a2, a3| unsafe { fread_1(a0, a1, a2, a3) }); + let _p: *mut ::libc::c_void = Default::default(); + let _size: u64 = 0_u64; + let _nmemb: u64 = 0_u64; + let _f: *mut ::std::fs::File = Default::default(); + foo_0(_fn, _p, _size, _nmemb, _f) + }); + assert!(((fn_) != (Default::default()))); + 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 0000000..19ade02 --- /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 as _); + assert!( + ((unsafe { + let _arg0: i32 = 3; + let _arg1: i32 = 4; + (fn_).unwrap()(_arg0, _arg1) + }) == (7)) + ); + fn_ = Some(sub_1 as _); + assert!( + ((unsafe { + let _arg0: i32 = 10; + let _arg1: i32 = 3; + (fn_).unwrap()(_arg0, _arg1) + }) == (7)) + ); + fn_ = Some(mul_2 as _); + 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 as _); + 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 0000000..7e2e927 --- /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 as _); + } + return Some(dec_1 as _); +} +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 as _)))); + 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 as _)))); + 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 0000000..123a880 --- /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 0000000..fc5a107 --- /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 as 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 as _), + }; + let mut h2: Handler = Handler { + tag: 2, + cb: Some(negate_1 as _), + }; + 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 as _); + 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 0000000..00817f0 --- /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 as _); + 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 as _); + let _x: *mut i32 = (&mut a as *mut i32); + run_2(_fn, _x) + }); + assert!(((a) == (0))); + let mut fn_: Option = Some(negate_0 as _); + 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 0000000..677cceb --- /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 as 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 as _), + get: Some(int_get_1 as _), + destroy: Some(int_destroy_2 as _), + }; + 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_local.rs b/tests/unit/out/unsafe/lambda_capture_local.rs new file mode 100644 index 0000000..9e449d6 --- /dev/null +++ b/tests/unit/out/unsafe/lambda_capture_local.rs @@ -0,0 +1,72 @@ +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 base: i32 = 10; + let mut factor: i32 = 3; + assert!( + ((unsafe { + let _x: i32 = 5; + (|x: i32| { + return ((x) + (base)); + })(_x) + }) == (15)) + ); + assert!( + ((unsafe { + let _x: i32 = 4; + (|x: i32| { + return ((x) * (factor)); + })(_x) + }) == (12)) + ); + base = 100; + assert!( + ((unsafe { + let _x: i32 = 5; + (|x: i32| { + return ((x) + (base)); + })(_x) + }) == (105)) + ); + assert!( + ((unsafe { + let _x: i32 = 4; + (|x: i32| { + return ((x) * (factor)); + })(_x) + }) == (12)) + ); + let mut sum: i32 = 0; + (unsafe { + let _x: i32 = 1; + (|x: i32| { + sum += x; + })(_x) + }); + (unsafe { + let _x: i32 = 2; + (|x: i32| { + sum += x; + })(_x) + }); + (unsafe { + let _x: i32 = 3; + (|x: i32| { + sum += x; + })(_x) + }); + assert!(((sum) == (6))); + 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 0000000..bf1f4fa --- /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 0000000..542a59d --- /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/lambda_nocapture.rs b/tests/unit/out/unsafe/lambda_nocapture.rs new file mode 100644 index 0000000..d71ab10 --- /dev/null +++ b/tests/unit/out/unsafe/lambda_nocapture.rs @@ -0,0 +1,64 @@ +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 call_0(mut f: Option i32>, mut a: i32, mut b: i32) -> i32 { + return (unsafe { + let _arg0: i32 = a; + let _arg1: i32 = b; + (f).unwrap()(_arg0, _arg1) + }); +} +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut add: Option i32> = Some(|a: i32, b: i32| { + return ((a) + (b)); + }); + let mut sub: Option i32> = Some(|a: i32, b: i32| { + return ((a) - (b)); + }); + assert!(!((add).is_none())); + assert!(((add) != (sub))); + assert!( + ((unsafe { + let _arg0: i32 = 2; + let _arg1: i32 = 3; + (add).unwrap()(_arg0, _arg1) + }) == (5)) + ); + assert!( + ((unsafe { + let _arg0: i32 = 10; + let _arg1: i32 = 4; + (sub).unwrap()(_arg0, _arg1) + }) == (6)) + ); + assert!( + ((unsafe { + let _f: Option i32> = add; + let _a: i32 = 7; + let _b: i32 = 8; + call_0(_f, _a, _b) + }) == (15)) + ); + assert!( + ((unsafe { + let _f: Option i32> = Some(|a: i32, b: i32| { + return ((a) * (b)); + }); + let _a: i32 = 6; + let _b: i32 = 7; + call_0(_f, _a, _b) + }) == (42)) + ); + return 0; +} From ddd13a8f6c7f7e9241c2558d5a5a670871c9c890 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Mon, 13 Apr 2026 21:36:20 +0100 Subject: [PATCH 10/35] clang-format --- cpp2rust/converter/converter.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 747a002..8b117c7 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -1397,7 +1397,8 @@ void Converter::ConvertGenericCallExpr(clang::CallExpr *expr) { StrCat(token::kOpenParen); StrCat(keyword_unsafe_); StrCat(token::kOpenCurlyBracket); - const auto *function = expr->getCalleeDecl() ? expr->getCalleeDecl()->getAsFunction() : nullptr; + const auto *function = + expr->getCalleeDecl() ? expr->getCalleeDecl()->getAsFunction() : nullptr; const clang::FunctionProtoType *proto = nullptr; if (!function) { From 4d93cd4bbac5948be8d8a83cd228f0e644e60f40 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Mon, 13 Apr 2026 21:45:45 +0100 Subject: [PATCH 11/35] Update tests --- .../ub/out/refcount/dangling-prvalue-as-lvalue.rs | 2 +- tests/ub/out/refcount/ub1.rs | 2 +- tests/ub/out/unsafe/dangling-prvalue-as-lvalue.rs | 2 +- tests/ub/out/unsafe/ub1.rs | 2 +- tests/ub/out/unsafe/ub10.rs | 8 ++------ tests/ub/out/unsafe/ub14.rs | 8 ++------ tests/ub/out/unsafe/ub15.rs | 8 ++------ tests/ub/out/unsafe/ub16.rs | 8 ++------ tests/ub/out/unsafe/ub20.rs | 8 ++------ tests/ub/out/unsafe/ub9.rs | 8 ++------ tests/unit/out/refcount/complex_function.rs | 14 +++++++------- tests/unit/out/refcount/no_direct_callee.rs | 8 ++++---- tests/unit/out/refcount/printfs.rs | 4 ++-- tests/unit/out/refcount/prvalue-as-lvalue.rs | 2 +- tests/unit/out/refcount/ref_calls.rs | 2 +- tests/unit/out/unsafe/06_new_array.rs | 2 +- tests/unit/out/unsafe/clone_vs_move.rs | 4 ++-- tests/unit/out/unsafe/complex_function.rs | 8 ++++---- tests/unit/out/unsafe/default.rs | 2 +- tests/unit/out/unsafe/init.rs | 2 +- tests/unit/out/unsafe/init_list.rs | 4 ++-- tests/unit/out/unsafe/memset.rs | 8 ++------ tests/unit/out/unsafe/new_alloc_array.rs | 8 ++------ tests/unit/out/unsafe/new_array.rs | 8 ++------ tests/unit/out/unsafe/new_array_var_size.rs | 10 +++------- tests/unit/out/unsafe/no_direct_callee.rs | 6 +++--- tests/unit/out/unsafe/pointer_call_offset.rs | 8 ++------ tests/unit/out/unsafe/prvalue-as-lvalue.rs | 2 +- tests/unit/out/unsafe/random.rs | 6 +++--- tests/unit/out/unsafe/ref_calls.rs | 2 +- .../out/unsafe/reinterpret_cast_large_array.rs | 8 ++------ .../unit/out/unsafe/reinterpret_cast_new_array.rs | 2 +- tests/unit/out/unsafe/static_local.rs | 2 +- tests/unit/out/unsafe/stdcopy.rs | 2 +- tests/unit/out/unsafe/swap_extended.rs | 2 +- tests/unit/out/unsafe/unique_ptr.rs | 8 ++------ tests/unit/out/unsafe/vector2.rs | 2 +- tests/unit/static_local.cpp | 1 - 38 files changed, 70 insertions(+), 123 deletions(-) diff --git a/tests/ub/out/refcount/dangling-prvalue-as-lvalue.rs b/tests/ub/out/refcount/dangling-prvalue-as-lvalue.rs index c5ffd85..fd03296 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 0b4feef..e525fce 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 11ddb63..eeaa1d9 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 bc49a90..002d9c7 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/ub/out/unsafe/ub10.rs b/tests/ub/out/unsafe/ub10.rs index 14ba0ea..e60c673 100644 --- a/tests/ub/out/unsafe/ub10.rs +++ b/tests/ub/out/unsafe/ub10.rs @@ -13,12 +13,8 @@ pub fn main() { } } unsafe fn main_0() -> i32 { - let mut arr: *mut i32 = Box::leak( - (0..10_u64) - .map(|_| ::default()) - .collect::>(), - ) - .as_mut_ptr(); + let mut arr: *mut i32 = + Box::leak((0..10_u64).map(|_| 0 as i32).collect::>()).as_mut_ptr(); let mut ptr: *mut i32 = arr.offset((1) as isize); let mut out: i32 = (*ptr); diff --git a/tests/ub/out/unsafe/ub14.rs b/tests/ub/out/unsafe/ub14.rs index 491de59..7a21361 100644 --- a/tests/ub/out/unsafe/ub14.rs +++ b/tests/ub/out/unsafe/ub14.rs @@ -13,12 +13,8 @@ pub fn main() { } } unsafe fn main_0() -> i32 { - let mut arr1: *mut i32 = Box::leak( - (0..100_u64) - .map(|_| ::default()) - .collect::>(), - ) - .as_mut_ptr(); + let mut arr1: *mut i32 = + Box::leak((0..100_u64).map(|_| 0 as i32).collect::>()).as_mut_ptr(); (*arr1.offset((100) as isize)) = 1; ::std::mem::drop(Box::from_raw(::std::slice::from_raw_parts_mut( diff --git a/tests/ub/out/unsafe/ub15.rs b/tests/ub/out/unsafe/ub15.rs index dc08aa1..b7ed844 100644 --- a/tests/ub/out/unsafe/ub15.rs +++ b/tests/ub/out/unsafe/ub15.rs @@ -13,12 +13,8 @@ pub fn main() { } } unsafe fn main_0() -> i32 { - let mut arr: *mut i32 = Box::leak( - (0..15_u64) - .map(|_| ::default()) - .collect::>(), - ) - .as_mut_ptr(); + let mut arr: *mut i32 = + Box::leak((0..15_u64).map(|_| 0 as i32).collect::>()).as_mut_ptr(); let mut ptr: *mut i32 = arr.offset((15) as isize); let mut out: i32 = (*ptr); diff --git a/tests/ub/out/unsafe/ub16.rs b/tests/ub/out/unsafe/ub16.rs index a53d884..b558d41 100644 --- a/tests/ub/out/unsafe/ub16.rs +++ b/tests/ub/out/unsafe/ub16.rs @@ -16,12 +16,8 @@ pub fn main() { } } unsafe fn main_0() -> i32 { - let mut p1: *mut i32 = Box::leak( - (0..10_u64) - .map(|_| ::default()) - .collect::>(), - ) - .as_mut_ptr(); + let mut p1: *mut i32 = + Box::leak((0..10_u64).map(|_| 0 as i32).collect::>()).as_mut_ptr(); let mut out: i32 = (*(unsafe { let _a: *mut i32 = (&mut (*p1.offset((1) as isize)) as *mut i32); foo_0(_a) diff --git a/tests/ub/out/unsafe/ub20.rs b/tests/ub/out/unsafe/ub20.rs index 8517a69..b57376f 100644 --- a/tests/ub/out/unsafe/ub20.rs +++ b/tests/ub/out/unsafe/ub20.rs @@ -16,12 +16,8 @@ pub fn main() { } } unsafe fn main_0() -> i32 { - let mut x: *mut i32 = Box::leak( - (0..10_u64) - .map(|_| ::default()) - .collect::>(), - ) - .as_mut_ptr(); + let mut x: *mut i32 = + Box::leak((0..10_u64).map(|_| 0 as i32).collect::>()).as_mut_ptr(); (unsafe { let _single: *mut i32 = x; foo_0(_single) diff --git a/tests/ub/out/unsafe/ub9.rs b/tests/ub/out/unsafe/ub9.rs index f2136e7..f8206b7 100644 --- a/tests/ub/out/unsafe/ub9.rs +++ b/tests/ub/out/unsafe/ub9.rs @@ -13,12 +13,8 @@ pub fn main() { } } unsafe fn main_0() -> i32 { - let mut arr: *mut i32 = Box::leak( - (0..10_u64) - .map(|_| ::default()) - .collect::>(), - ) - .as_mut_ptr(); + let mut arr: *mut i32 = + Box::leak((0..10_u64).map(|_| 0 as i32).collect::>()).as_mut_ptr(); let mut out: i32 = (*arr.offset((10) as isize)); ::std::mem::drop(Box::from_raw(::std::slice::from_raw_parts_mut( diff --git a/tests/unit/out/refcount/complex_function.rs b/tests/unit/out/refcount/complex_function.rs index 7a7c203..2d778ae 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/no_direct_callee.rs b/tests/unit/out/refcount/no_direct_callee.rs index a01b00d..33d09c6 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_: Option bool>) -> i32 { + let fn_: Value bool>> = Rc::new(RefCell::new(fn_)); + if !({ (*fn_.borrow()).unwrap()() }) { 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: Option bool> = Some(test1_0 as _); test_1(_fn) }); } diff --git a/tests/unit/out/refcount/printfs.rs b/tests/unit/out/refcount/printfs.rs index df5ffa6..a661f37 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 a8926cc..610c6ba 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 41dbbfd..f9e604f 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/06_new_array.rs b/tests/unit/out/unsafe/06_new_array.rs index cdb76f9..fdc11d3 100644 --- a/tests/unit/out/unsafe/06_new_array.rs +++ b/tests/unit/out/unsafe/06_new_array.rs @@ -14,7 +14,7 @@ pub fn main() { } unsafe fn main_0() -> i32 { let mut e: *mut i32 = - Box::leak((0..2_u64).map(|_| ::default()).collect::>()).as_mut_ptr(); + Box::leak((0..2_u64).map(|_| 0 as i32).collect::>()).as_mut_ptr(); (*e.offset((0) as isize)) = 6; (*e.offset((1) as isize)) = 7; diff --git a/tests/unit/out/unsafe/clone_vs_move.rs b/tests/unit/out/unsafe/clone_vs_move.rs index c19f9ec..065ba07 100644 --- a/tests/unit/out/unsafe/clone_vs_move.rs +++ b/tests/unit/out/unsafe/clone_vs_move.rs @@ -22,10 +22,10 @@ pub struct Foo { impl Default for Foo { fn default() -> Self { Foo { - x: ::default(), + x: 0 as i32, y: <*mut i32>::default(), z: Default::default(), - a: [::default(); 3], + a: [0 as i32; 3], bar: ::default(), } } diff --git a/tests/unit/out/unsafe/complex_function.rs b/tests/unit/out/unsafe/complex_function.rs index 5d741ea..5707ff9 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/default.rs b/tests/unit/out/unsafe/default.rs index 6868377..990bf33 100644 --- a/tests/unit/out/unsafe/default.rs +++ b/tests/unit/out/unsafe/default.rs @@ -22,7 +22,7 @@ impl Default for Pointers { x2: Default::default(), x3: [Default::default(); 5], x4: [Default::default(); 10], - x5: ::default(), + x5: 0 as i32, } } } diff --git a/tests/unit/out/unsafe/init.rs b/tests/unit/out/unsafe/init.rs index 894070b..e767538 100644 --- a/tests/unit/out/unsafe/init.rs +++ b/tests/unit/out/unsafe/init.rs @@ -20,7 +20,7 @@ pub fn main() { } } unsafe fn main_0() -> i32 { - let mut x: i32 = ::default(); + let mut x: i32 = 0 as i32; let mut p: *mut i32 = Default::default(); let g: *mut i32 = &mut x as *mut i32; let mut q: *mut i32 = (&mut x as *mut i32); diff --git a/tests/unit/out/unsafe/init_list.rs b/tests/unit/out/unsafe/init_list.rs index d8e2166..1d5e27e 100644 --- a/tests/unit/out/unsafe/init_list.rs +++ b/tests/unit/out/unsafe/init_list.rs @@ -15,9 +15,9 @@ pub fn main() { } unsafe fn main_0() -> i32 { let mut i1: i32 = 3; - let mut i2: i32 = ::default(); + let mut i2: i32 = 0 as i32; let mut carr1: [i32; 2] = [1, 2]; - let mut carr2: [i32; 3] = [1, ::default(), ::default()]; + let mut carr2: [i32; 3] = [1, 0 as i32, 0 as i32]; let mut arr: Vec = vec![1, 2, 3]; let mut vec_: Vec = vec![1, 2, 3]; (unsafe { diff --git a/tests/unit/out/unsafe/memset.rs b/tests/unit/out/unsafe/memset.rs index ec8fd42..26eb5e6 100644 --- a/tests/unit/out/unsafe/memset.rs +++ b/tests/unit/out/unsafe/memset.rs @@ -14,12 +14,8 @@ pub fn main() { } unsafe fn main_0() -> i32 { let N: i32 = 3; - let mut arr: *mut i32 = Box::leak( - (0..(N as u64)) - .map(|_| ::default()) - .collect::>(), - ) - .as_mut_ptr(); + let mut arr: *mut i32 = + Box::leak((0..(N as u64)).map(|_| 0 as i32).collect::>()).as_mut_ptr(); { let byte_0 = (arr as *mut i32 as *mut ::libc::c_void) as *mut u8; for offset in 0..(::std::mem::size_of::() as u64 as u64).wrapping_mul((N as u64)) { diff --git a/tests/unit/out/unsafe/new_alloc_array.rs b/tests/unit/out/unsafe/new_alloc_array.rs index 697fe0a..5a83f05 100644 --- a/tests/unit/out/unsafe/new_alloc_array.rs +++ b/tests/unit/out/unsafe/new_alloc_array.rs @@ -13,12 +13,8 @@ pub fn main() { } } unsafe fn main_0() -> i32 { - let mut array: *mut i32 = Box::leak( - (0..100_u64) - .map(|_| ::default()) - .collect::>(), - ) - .as_mut_ptr(); + let mut array: *mut i32 = + Box::leak((0..100_u64).map(|_| 0 as i32).collect::>()).as_mut_ptr(); { let byte_0 = (array as *mut i32 as *mut ::libc::c_void) as *mut u8; for offset in 0..(::std::mem::size_of::() as u64 as u64).wrapping_mul(100_u64) { diff --git a/tests/unit/out/unsafe/new_array.rs b/tests/unit/out/unsafe/new_array.rs index e2243ee..b73aea8 100644 --- a/tests/unit/out/unsafe/new_array.rs +++ b/tests/unit/out/unsafe/new_array.rs @@ -13,12 +13,8 @@ pub fn main() { } } unsafe fn main_0() -> i32 { - let mut array: *mut i32 = Box::leak( - (0..100_u64) - .map(|_| ::default()) - .collect::>(), - ) - .as_mut_ptr(); + let mut array: *mut i32 = + Box::leak((0..100_u64).map(|_| 0 as i32).collect::>()).as_mut_ptr(); ::std::mem::drop(Box::from_raw(::std::slice::from_raw_parts_mut( array, diff --git a/tests/unit/out/unsafe/new_array_var_size.rs b/tests/unit/out/unsafe/new_array_var_size.rs index cfdf0c1..ff403a2 100644 --- a/tests/unit/out/unsafe/new_array_var_size.rs +++ b/tests/unit/out/unsafe/new_array_var_size.rs @@ -14,12 +14,8 @@ pub fn main() { } unsafe fn main_0() -> i32 { let mut N: i32 = 5; - let mut A: *mut i32 = Box::leak( - (0..(N as u64)) - .map(|_| ::default()) - .collect::>(), - ) - .as_mut_ptr(); + let mut A: *mut i32 = + Box::leak((0..(N as u64)).map(|_| 0 as i32).collect::>()).as_mut_ptr(); ::std::mem::drop(Box::from_raw(::std::slice::from_raw_parts_mut( A, @@ -28,7 +24,7 @@ unsafe fn main_0() -> i32 { let N2: *mut i32 = &mut N as *mut i32; let mut A2: *mut i32 = Box::leak( (0..((*N2) as u64)) - .map(|_| ::default()) + .map(|_| 0 as i32) .collect::>(), ) .as_mut_ptr(); diff --git a/tests/unit/out/unsafe/no_direct_callee.rs b/tests/unit/out/unsafe/no_direct_callee.rs index 5c962fe..1136da6 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 as _); test_1(_fn) }); } diff --git a/tests/unit/out/unsafe/pointer_call_offset.rs b/tests/unit/out/unsafe/pointer_call_offset.rs index fdbca43..8d9472e 100644 --- a/tests/unit/out/unsafe/pointer_call_offset.rs +++ b/tests/unit/out/unsafe/pointer_call_offset.rs @@ -16,12 +16,8 @@ pub fn main() { } } unsafe fn main_0() -> i32 { - let mut p1: *mut i32 = Box::leak( - (0..10_u64) - .map(|_| ::default()) - .collect::>(), - ) - .as_mut_ptr(); + let mut p1: *mut i32 = + Box::leak((0..10_u64).map(|_| 0 as i32).collect::>()).as_mut_ptr(); let mut i: u32 = 0_u32; 'loop_: while ((i) < (10_u32)) { (*p1.offset((i) as isize)) = (i as i32); diff --git a/tests/unit/out/unsafe/prvalue-as-lvalue.rs b/tests/unit/out/unsafe/prvalue-as-lvalue.rs index 515e098..4d1040d 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/random.rs b/tests/unit/out/unsafe/random.rs index 8739723..82133af 100644 --- a/tests/unit/out/unsafe/random.rs +++ b/tests/unit/out/unsafe/random.rs @@ -40,9 +40,9 @@ impl Pair { impl Default for Pair { fn default() -> Self { Pair { - x: ::default(), - y: ::default(), - a: [::default(); 5], + x: 0 as i32, + y: 0 as i32, + a: [0 as i32; 5], r: <*mut i32>::default(), p: Default::default(), pair: Default::default(), diff --git a/tests/unit/out/unsafe/ref_calls.rs b/tests/unit/out/unsafe/ref_calls.rs index 0c24b4a..b32c2b2 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; diff --git a/tests/unit/out/unsafe/reinterpret_cast_large_array.rs b/tests/unit/out/unsafe/reinterpret_cast_large_array.rs index 6d85d33..5344c2b 100644 --- a/tests/unit/out/unsafe/reinterpret_cast_large_array.rs +++ b/tests/unit/out/unsafe/reinterpret_cast_large_array.rs @@ -14,12 +14,8 @@ pub fn main() { } unsafe fn main_0() -> i32 { let N: i32 = 10000; - let mut arr: *mut u32 = Box::leak( - (0..(N as u64)) - .map(|_| ::default()) - .collect::>(), - ) - .as_mut_ptr(); + let mut arr: *mut u32 = + Box::leak((0..(N as u64)).map(|_| 0 as u32).collect::>()).as_mut_ptr(); let mut i: i32 = 0; 'loop_: while ((i) < (N)) { (*arr.offset((i) as isize)) = 0_u32; diff --git a/tests/unit/out/unsafe/reinterpret_cast_new_array.rs b/tests/unit/out/unsafe/reinterpret_cast_new_array.rs index 87840ed..f4e567b 100644 --- a/tests/unit/out/unsafe/reinterpret_cast_new_array.rs +++ b/tests/unit/out/unsafe/reinterpret_cast_new_array.rs @@ -14,7 +14,7 @@ pub fn main() { } unsafe fn main_0() -> i32 { let mut arr: *mut u32 = - Box::leak((0..2_u64).map(|_| ::default()).collect::>()).as_mut_ptr(); + Box::leak((0..2_u64).map(|_| 0 as u32).collect::>()).as_mut_ptr(); (*arr.offset((0) as isize)) = 67305985_u32; (*arr.offset((1) as isize)) = 134678021_u32; let mut bytes: *mut u8 = (arr as *mut u8); diff --git a/tests/unit/out/unsafe/static_local.rs b/tests/unit/out/unsafe/static_local.rs index c6fe939..042a700 100644 --- a/tests/unit/out/unsafe/static_local.rs +++ b/tests/unit/out/unsafe/static_local.rs @@ -8,7 +8,7 @@ use std::io::{Read, Write}; use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; use std::rc::Rc; pub unsafe fn foo_0() -> i32 { - static kX1: i32 = 1;; + static mut kX1: i32 = 1;; static kX2: i32 = 2;; kX1 += 1; return ((kX1) + (kX2)); diff --git a/tests/unit/out/unsafe/stdcopy.rs b/tests/unit/out/unsafe/stdcopy.rs index 4c81383..706e5fb 100644 --- a/tests/unit/out/unsafe/stdcopy.rs +++ b/tests/unit/out/unsafe/stdcopy.rs @@ -14,7 +14,7 @@ pub fn main() { } unsafe fn main_0() -> i32 { let mut input: [i32; 3] = [1, 2, 3]; - let mut output: [i32; 3] = [::default(); 3]; + let mut output: [i32; 3] = [0 as i32; 3]; { let mut outptr = output.as_mut_ptr().clone(); let mut curr = input.as_mut_ptr().clone(); diff --git a/tests/unit/out/unsafe/swap_extended.rs b/tests/unit/out/unsafe/swap_extended.rs index adc9da1..8aae96c 100644 --- a/tests/unit/out/unsafe/swap_extended.rs +++ b/tests/unit/out/unsafe/swap_extended.rs @@ -94,7 +94,7 @@ unsafe fn main_0() -> i32 { (*h), ); ::std::mem::drop(Box::from_raw(h)); - let mut i: *mut i32 = Box::leak(Box::new([7, 8, ::default()])).as_mut_ptr(); + let mut i: *mut i32 = Box::leak(Box::new([7, 8, 0 as i32])).as_mut_ptr(); write!( std::fs::File::from_raw_fd( std::io::stdout() diff --git a/tests/unit/out/unsafe/unique_ptr.rs b/tests/unit/out/unsafe/unique_ptr.rs index 1db5139..a94bb75 100644 --- a/tests/unit/out/unsafe/unique_ptr.rs +++ b/tests/unit/out/unsafe/unique_ptr.rs @@ -72,9 +72,7 @@ pub unsafe fn Consume_1(mut safe_ptr: Option>) -> i32 { pub unsafe fn RndStuff_2() { let mut x1: Option> = None; let mut x2: Option> = Some(Box::from_raw(Box::leak( - (0..100_u64) - .map(|_| ::default()) - .collect::>(), + (0..100_u64).map(|_| 0 as i32).collect::>(), ))); let mut i: i32 = 0; 'loop_: while ((i) < (100)) { @@ -82,9 +80,7 @@ pub unsafe fn RndStuff_2() { i.prefix_inc(); } x2 = Some(Box::from_raw(Box::leak( - (0..200_u64) - .map(|_| ::default()) - .collect::>(), + (0..200_u64).map(|_| 0 as i32).collect::>(), ))); let mut i: i32 = 0; 'loop_: while ((i) < (200)) { diff --git a/tests/unit/out/unsafe/vector2.rs b/tests/unit/out/unsafe/vector2.rs index a62467e..640b762 100644 --- a/tests/unit/out/unsafe/vector2.rs +++ b/tests/unit/out/unsafe/vector2.rs @@ -9,7 +9,7 @@ use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; use std::rc::Rc; pub unsafe fn fn_0(v: *mut Vec, mut v3: Vec) { (*v).push(20); - let mut x: i32 = ::default(); + let mut x: i32 = 0 as i32; let mut v2: Vec = Vec::new(); let mut v4: *mut Vec = (&mut v3 as *mut Vec); v2.push(0); diff --git a/tests/unit/static_local.cpp b/tests/unit/static_local.cpp index 4378e99..acb9117 100644 --- a/tests/unit/static_local.cpp +++ b/tests/unit/static_local.cpp @@ -1,7 +1,6 @@ // Copyright (c) 2022-present INESC-ID. // Distributed under the MIT license that can be found in the LICENSE file. -// no-compile: unsafe int foo() { static int kX1 = 1; static const int kX2 = 2; From 691a4355481d3b90c0ccfb73ce493e9337d5a807 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Mon, 13 Apr 2026 21:47:18 +0100 Subject: [PATCH 12/35] clang-format --- tests/unit/fn_ptr_conditional.cpp | 4 +--- tests/unit/fn_ptr_void_return.cpp | 4 +--- tests/unit/lambda_capture_pass.cpp | 3 +-- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/tests/unit/fn_ptr_conditional.cpp b/tests/unit/fn_ptr_conditional.cpp index ad39614..d1b4c83 100644 --- a/tests/unit/fn_ptr_conditional.cpp +++ b/tests/unit/fn_ptr_conditional.cpp @@ -6,9 +6,7 @@ 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; -} +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; diff --git a/tests/unit/fn_ptr_void_return.cpp b/tests/unit/fn_ptr_void_return.cpp index ebf7b39..3ae221a 100644 --- a/tests/unit/fn_ptr_void_return.cpp +++ b/tests/unit/fn_ptr_void_return.cpp @@ -5,9 +5,7 @@ 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); -} +void run(action_t fn, int *x) { fn(x); } int main() { int a = 42; diff --git a/tests/unit/lambda_capture_pass.cpp b/tests/unit/lambda_capture_pass.cpp index 1a7637f..439b128 100644 --- a/tests/unit/lambda_capture_pass.cpp +++ b/tests/unit/lambda_capture_pass.cpp @@ -1,7 +1,6 @@ #include -template -int apply(F fn, int x) { return fn(x); } +template int apply(F fn, int x) { return fn(x); } int main() { int base = 10; From f0267287286be389560790bf18fe2935c260fbad Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Mon, 13 Apr 2026 22:16:44 +0100 Subject: [PATCH 13/35] Translate fn ptr cast using mem::transmute --- cpp2rust/converter/converter.cpp | 11 +++++++++++ tests/unit/out/unsafe/fn_ptr_cast.rs | 17 ++++++++++++----- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 8b117c7..64ccd1a 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -1737,6 +1737,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); diff --git a/tests/unit/out/unsafe/fn_ptr_cast.rs b/tests/unit/out/unsafe/fn_ptr_cast.rs index caf6a62..c4eee5e 100644 --- a/tests/unit/out/unsafe/fn_ptr_cast.rs +++ b/tests/unit/out/unsafe/fn_ptr_cast.rs @@ -18,9 +18,11 @@ pub unsafe fn test_roundtrip_1() { (fn_).unwrap()(_arg0) }) == (10)) ); - let mut gfn: Option = (fn_ as Option); + let mut gfn: Option = + std::mem::transmute:: i32>, Option>(fn_); assert!(!((gfn).is_none())); - let mut fn2: Option i32> = (gfn as Option i32>); + let mut fn2: Option i32> = + std::mem::transmute::, Option i32>>(gfn); assert!( ((unsafe { let _arg0: i32 = 5; @@ -32,7 +34,9 @@ pub unsafe fn test_roundtrip_1() { pub unsafe fn test_double_cast_2() { let mut fn_: Option i32> = Some(double_it_0 as _); let mut fn2: Option i32> = - ((fn_ as Option) as Option i32>); + std::mem::transmute::, Option i32>>( + std::mem::transmute:: i32>, Option>(fn_), + ); assert!( ((unsafe { let _arg0: i32 = 5; @@ -47,8 +51,11 @@ pub struct Command { } pub unsafe fn test_void_ptr_to_fn_3() { let mut cmd: Command = ::default(); - cmd.data = (Some(double_it_0 as _) as *mut ::libc::c_void); - let mut fn_: Option i32> = (cmd.data as Option i32>); + cmd.data = std::mem::transmute:: i32>, *mut ::libc::c_void>(Some( + double_it_0 as _, + )); + let mut fn_: Option i32> = + std::mem::transmute::<*mut ::libc::c_void, Option i32>>(cmd.data); assert!( ((unsafe { let _arg0: i32 = 5; From e320bdbb620530e2b653c24fe31cb9c171173022 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Tue, 14 Apr 2026 15:32:28 +0100 Subject: [PATCH 14/35] Add support for function pointers in PtrKind Previously function pointers were modeled as Option, but this is problematic for function pointer casts. Option works well in unsafe with std::mem::transmute, however there is no safe way to achieve the same operation in refcount. This is solved using the new Ptr. To allow casting between different function types, use type erased Rc inside the new PtrKind::Fn. Equality of function pointers is achieved through implementing the OriginalAlloc::address method. The C standard allows converting function pointers between incompatible function types. UB is triggered only when the incompatible pointer is called. For this reason the new FnState implements 2 new concepts: 1. casting adaptors (to allow argument casting between ABI compatible types) 2. provenance stack (to allow round-trip function pointer casts) For 1., consider the following cast: int fn_taking_int_ptr(int *p); int (*fn_taking_void_ptr)(void*) = (int (*)(void*))fn_taking_int_ptr; Calling fn_taking_int_ptr with an int* argument works because both int* and void* have the same size. To support this in Rust we need to create an int* -> void* adapter when casting from fn_taking_int_ptr to fn_taking_void_ptr: fn_taking_int_ptr.cast_fn:: i32>(Some( (|a0: AnyPtr| -> i32 { fn_taking_int_ptr(a0.cast::().unwrap()) }) as fn(AnyPtr) -> i32 )) The job of the adapter is to convert from AnyPtr to Ptr. Ptr::cast_fn is a new function that takes as type argument the type of the target function pointer and an optional adaptor. If cast_fn receives None, then there is no valid adaptor from source to target, matching the UB semantics of calling a function through an incompatible function pointer: int add(int a, int b) { return a + b; } void (*wrong)(void) = (void (*)(void))add; wrong() For 2., the provenance stack contains all casts performed on the pointer in the past. Compared to PtrKind::Reinterpreted, PtrKind::Fn has no backing byte storage through OriginalAlloc, so each cast must know its history in order to allow round-trip casts, such as: int (*)(int, int) -> void (*)(void) -> int (*)(int, int) (1) (2) For this specific case, where both (1) and (2) create non-compatible adaptors (because of non-compatible arguments), we cannot recover a call to the original function after (1) is performed. For this to work, save a stack of provenance, and when (2) is perfomed, cast_fn recovers the original function pointer. See test_roundtrip in fn_ptr_cast.cpp. A current limitation of this approach is that it only allows function pointer casts where the source is a direct declaration of a function. Accessing a function pointer through a member field for example, would create a capturing adapter which does not coerce in a fn inside Ptr. --- cpp2rust/converter/converter.cpp | 10 +- cpp2rust/converter/converter.h | 5 +- .../converter/models/converter_refcount.cpp | 152 +++++++++++++++++- .../converter/models/converter_refcount.h | 14 ++ libcc2rs/src/lib.rs | 7 + libcc2rs/src/rc.rs | 106 ++++++++++++ libcc2rs/src/reinterpret.rs | 18 +++ tests/unit/fn_ptr_cast.cpp | 12 ++ tests/unit/out/refcount/fn_ptr.rs | 20 +-- tests/unit/out/refcount/fn_ptr_array.rs | 20 +-- .../unit/out/refcount/fn_ptr_as_condition.rs | 22 +-- tests/unit/out/refcount/fn_ptr_cast.rs | 69 +++++--- tests/unit/out/refcount/fn_ptr_conditional.rs | 35 ++-- tests/unit/out/refcount/fn_ptr_default_arg.rs | 27 ++-- tests/unit/out/refcount/fn_ptr_global.rs | 24 +-- tests/unit/out/refcount/fn_ptr_reassign.rs | 23 +-- tests/unit/out/refcount/fn_ptr_return.rs | 20 +-- tests/unit/out/refcount/fn_ptr_struct.rs | 18 +-- tests/unit/out/refcount/fn_ptr_void_return.rs | 16 +- tests/unit/out/refcount/fn_ptr_vtable.rs | 36 +++-- tests/unit/out/refcount/no_direct_callee.rs | 8 +- tests/unit/out/unsafe/fn_ptr_cast.rs | 19 +++ 22 files changed, 518 insertions(+), 163 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 64ccd1a..1fdc402 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -1375,6 +1375,12 @@ bool Converter::VisitCallExpr(clang::CallExpr *expr) { return false; } +void Converter::EmitFnPtrCall(clang::Expr *callee) { + StrCat(token::kOpenParen); + Convert(callee); + StrCat(").unwrap()"); +} + void Converter::ConvertGenericCallExpr(clang::CallExpr *expr) { clang::Expr *callee = expr->getCallee(); auto convert_param_ty = [&](clang::QualType param_type, clang::Expr *expr) { @@ -1447,9 +1453,7 @@ void Converter::ConvertGenericCallExpr(clang::CallExpr *expr) { } if (proto && !function) { - StrCat(token::kOpenParen); - Convert(callee); - StrCat(").unwrap()"); + EmitFnPtrCall(callee); } else { PushExprKind push(*this, ExprKind::RValue); Convert(StripFunctionPointerDecay(callee)); diff --git a/cpp2rust/converter/converter.h b/cpp2rust/converter/converter.h index 899cc96..faf340c 100644 --- a/cpp2rust/converter/converter.h +++ b/cpp2rust/converter/converter.h @@ -199,6 +199,8 @@ class Converter : public clang::RecursiveASTVisitor { void ConvertGenericCallExpr(clang::CallExpr *expr); + virtual void EmitFnPtrCall(clang::Expr *callee); + virtual void ConvertPrintf(clang::CallExpr *expr); void ConvertVAArgCall(clang::CallExpr *expr); @@ -332,7 +334,8 @@ 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 + GetFunctionPointerDefaultAsString(clang::QualType qual_type); virtual std::string GetDefaultAsString(clang::QualType qual_type); diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index 8234a2c..d4637eb 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -165,10 +165,72 @@ 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) { + if (i > 0) + closure += ", "; + 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->getCanonicalDecl()) + "("; + 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->isVoidPointerType()) { + closure += std::format("a{}.cast::<{}>().unwrap()", i, + ToString(src_pty->getPointeeType())); + } else if (src_pty->isVoidPointerType() && tgt_pty->isPointerType()) { + closure += std::format("a{}.to_any()", i); + } else { + // UB: Incompatible types + return "None"; + } + closure += ", "; + } + closure += ") })"; + + return std::format("Some({} as {})", closure, GetFnTypeString(target_proto)); +} + +std::string +ConverterRefCount::GetFnTypeString(const clang::FunctionProtoType *proto) { + PushConversionKind push(*this, ConversionKind::Unboxed); + std::string result = "fn("; + for (auto p_ty : proto->param_types()) { + result += ToString(p_ty) + ","; + } + result += ")"; + if (!proto->getReturnType()->isVoidType()) { + result += std::format(" -> {}", ToString(proto->getReturnType())); + } + return result; +} + 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("Ptr<{}>", GetFnTypeString(proto))); return false; } @@ -570,7 +632,9 @@ bool ConverterRefCount::VisitDeclRefExpr(clang::DeclRefExpr *expr) { if (clang::isa(decl)) { if (isAddrOf()) { - StrCat(std::format("Some({} as _)", str)); + auto proto = decl->getType()->getAs(); + auto fn_type = GetFnTypeString(proto); + StrCat(std::format("fn_ptr!({}, {})", str, fn_type)); } else { StrCat(str); } @@ -951,9 +1015,79 @@ bool ConverterRefCount::VisitImplicitCastExpr(clang::ImplicitCastExpr *expr) { } } + if (expr->getCastKind() == clang::CastKind::CK_NullToPointer && + expr->getType()->isFunctionPointerType()) { + StrCat("Ptr::null()"); + computed_expr_type_ = ComputedExprType::FreshPointer; + return false; + } + return Converter::VisitImplicitCastExpr(expr); } +void ConverterRefCount::EmitFnPtrCall(clang::Expr *callee) { + Convert(callee); + StrCat(".call_fn()"); +} + +std::string ConverterRefCount::GetFunctionPointerDefaultAsString( + clang::QualType qual_type) { + return "Ptr::null()"; +} + +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 = GetFnTypeString(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_fn::<{}>({})", 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 = GetFnTypeString(target_proto); + StrCat(std::format("{}.cast::<{}>().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\")", @@ -1478,8 +1614,12 @@ void ConverterRefCount::ConvertVarInit(clang::QualType qual_type, Buffer buf(*this); PushConversionKind push(*this, ConversionKind::Unboxed); if (qual_type->isFunctionPointerType() && lambda->capture_size() == 0) { - PushExprKind addr_of(*this, ExprKind::AddrOf); + StrCat(std::format("Ptr::from_fn((")); VisitLambdaExpr(lambda); + StrCat(std::format( + ") as {}, 0)", + GetFnTypeString(qual_type->getPointeeType() + ->getAs()))); } else { VisitLambdaExpr(lambda); } diff --git a/cpp2rust/converter/models/converter_refcount.h b/cpp2rust/converter/models/converter_refcount.h index 8102590..cc9cc6e 100644 --- a/cpp2rust/converter/models/converter_refcount.h +++ b/cpp2rust/converter/models/converter_refcount.h @@ -59,12 +59,16 @@ class ConverterRefCount final : public Converter { void ConvertPrintf(clang::CallExpr *expr) override; + void EmitFnPtrCall(clang::Expr *callee) 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 +107,11 @@ class ConverterRefCount final : public Converter { std::string GetDefaultAsString(clang::QualType qual_type) override; + std::string + GetFunctionPointerDefaultAsString(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 +180,11 @@ class ConverterRefCount final : public Converter { const char *GetPointerDerefSuffix(clang::QualType pointee_type); const char *GetPointerDerefPrefix(clang::QualType pointee_type) override; + std::string GetFnTypeString(const clang::FunctionProtoType *proto); + 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/lib.rs b/libcc2rs/src/lib.rs index 42eb411..9b7b96e 100644 --- a/libcc2rs/src/lib.rs +++ b/libcc2rs/src/lib.rs @@ -4,6 +4,13 @@ mod reinterpret; pub use reinterpret::ByteRepr; +#[macro_export] +macro_rules! fn_ptr { + ($f:expr, $ty:ty) => { + $crate::Ptr::from_fn($f as $ty, $f as *const () as usize) + }; +} + mod rc; pub use rc::*; diff --git a/libcc2rs/src/rc.rs b/libcc2rs/src/rc.rs index eb197ee..a9b87eb 100644 --- a/libcc2rs/src/rc.rs +++ b/libcc2rs/src/rc.rs @@ -26,6 +26,32 @@ enum PtrKind { HeapArray(Weak>>), Vec(Weak>>), Reinterpreted(Rc), + Fn(Rc), +} + +struct FnPtrAlloc { + addr: usize, +} + +impl OriginalAlloc for FnPtrAlloc { + fn address(&self) -> usize { + self.addr + } + fn read_bytes(&self, _: usize, _: &mut [u8]) { + panic!("fn pointer"); + } + fn write_bytes(&self, _: usize, _: &[u8]) { + panic!("fn pointer"); + } + fn total_byte_len(&self) -> usize { + panic!("fn pointer"); + } +} + +#[derive(Clone)] +pub struct FnState { + alloc: Rc, + stack: Vec>>, } pub enum StrongPtr { @@ -80,6 +106,7 @@ impl fmt::Debug for PtrKind { PtrKind::Reinterpreted(ref data) => { write!(f, "Reinterpreted(0x{:x})", data.address()) } + PtrKind::Fn(ref state) => write!(f, "Fn(0x{:x})", state.alloc.address()), } } } @@ -94,6 +121,7 @@ impl Clone for PtrKind { PtrKind::StackArray(ref weak) => PtrKind::StackArray(weak.clone()), PtrKind::HeapArray(ref weak) => PtrKind::HeapArray(weak.clone()), PtrKind::Reinterpreted(ref data) => PtrKind::Reinterpreted(Rc::clone(data)), + PtrKind::Fn(ref state) => PtrKind::Fn(Rc::clone(state)), } } } @@ -106,6 +134,7 @@ impl PtrKind { PtrKind::Vec(w) => w.as_ptr() as usize, PtrKind::StackArray(w) | PtrKind::HeapArray(w) => w.as_ptr() as usize, PtrKind::Reinterpreted(ref data) => data.address(), + PtrKind::Fn(ref state) => state.alloc.address(), } } } @@ -269,6 +298,7 @@ impl Ptr { let step = std::mem::size_of::(); (data.total_byte_len() - self.offset % step) / step } + PtrKind::Fn(_) => 1, } } @@ -332,6 +362,7 @@ impl Ptr { byte_offset: self.offset, cell: RefCell::new(None), }, + PtrKind::Fn(_) => panic!("fn pointer"), } } @@ -358,6 +389,7 @@ impl Ptr { value.to_bytes(&mut buf); data.write_bytes(self.offset, &buf); } + PtrKind::Fn(_) => panic!("fn pointer"), } } @@ -398,6 +430,7 @@ impl Ptr { self.byte_offset(), ), PtrKind::Reinterpreted(ref data) => (Rc::clone(data), self.offset), + PtrKind::Fn(_) => panic!("fn pointer: use cast_fn instead"), }; Ptr { @@ -438,6 +471,7 @@ impl Ptr { data.write_bytes(self.offset, &buf); ret } + PtrKind::Fn(_) => panic!("fn pointer"), } } @@ -471,6 +505,7 @@ impl Ptr { data.write_bytes(self.offset, &buf); ret } + PtrKind::Fn(_) => panic!("fn pointer"), } } } @@ -497,6 +532,7 @@ impl Ptr { data.read_bytes(self.offset, &mut buf); T::from_bytes(&buf) } + PtrKind::Fn(_) => panic!("fn pointer"), } } } @@ -529,6 +565,7 @@ impl Ptr { PtrKind::Reinterpreted(..) => { panic!("sorting not supported for reinterpreted pointers") } + PtrKind::Fn(_) => panic!("fn pointer"), } } } @@ -582,6 +619,7 @@ impl Ptr { PtrKind::Reinterpreted(..) => { panic!("sorting not supported for reinterpreted pointers") } + PtrKind::Fn(_) => panic!("fn pointer"), } } } @@ -830,6 +868,7 @@ impl ToOwnedOption for Ptr { PtrKind::Vec(_) => panic!("Can't own a vector"), PtrKind::HeapArray(_) => panic!("Can't own an array variable as single"), PtrKind::Reinterpreted(..) => panic!("Can't own a reinterpreted pointer"), + PtrKind::Fn(_) => panic!("fn pointer"), } } } @@ -856,6 +895,7 @@ impl ToOwnedOption> for Ptr { PtrKind::Vec(_) => panic!("Can't own a vector"), PtrKind::HeapSingle(_) => panic!("Can't own a single variable as an array"), PtrKind::Reinterpreted(..) => panic!("Can't own a reinterpreted pointer"), + PtrKind::Fn(_) => panic!("fn pointer"), } } } @@ -871,6 +911,7 @@ impl fmt::Debug for Ptr { PtrKind::Vec(w) => (Weak::as_ptr(w) as usize) .wrapping_add(self.offset.wrapping_mul(std::mem::size_of::())), PtrKind::Reinterpreted(ref data) => data.address().wrapping_add(self.offset), + PtrKind::Fn(ref state) => state.alloc.address(), }; write!(f, "0x{:x}", addr) } @@ -967,6 +1008,7 @@ impl Ptr { data.read_bytes(start, &mut buf); buf } + PtrKind::Fn(_) => panic!("fn pointer"), } } @@ -1004,6 +1046,70 @@ impl Ptr { } } +impl Ptr { + pub fn from_fn(f: T, addr: usize) -> Self { + Ptr { + offset: 0, + kind: PtrKind::Fn(Rc::new(FnState { + alloc: Rc::new(FnPtrAlloc { addr }), + stack: vec![Some(Rc::new(f))], + })), + } + } + + pub fn cast_fn(&self, adapter: Option) -> Ptr { + let state = match &self.kind { + PtrKind::Fn(ref state) => state, + _ => panic!("not a fn pointer"), + }; + + let target_id = TypeId::of::(); + + for (i, entry) in state.stack.iter().enumerate() { + if let Some(ref rc) = entry { + if (*rc).as_ref().type_id() == target_id { + return Ptr { + offset: 0, + kind: PtrKind::Fn(Rc::new(FnState { + alloc: Rc::clone(&state.alloc), + stack: state.stack[..=i].to_vec(), + })), + }; + } + } + } + + let mut new_stack = state.stack.clone(); + new_stack.push(adapter.map(|a| Rc::new(a) as Rc)); + + Ptr { + offset: 0, + kind: PtrKind::Fn(Rc::new(FnState { + alloc: Rc::clone(&state.alloc), + stack: new_stack, + })), + } + } + + pub fn call_fn(&self) -> T + where + T: Copy + 'static, + { + let state = match &self.kind { + PtrKind::Fn(ref state) => state, + _ => panic!("not a fn pointer"), + }; + + let entry = state.stack.last().expect("empty fn pointer stack"); + match entry { + Some(ref rc) => *rc + .downcast_ref::() + .expect("ub: fn pointer type mismatch"), + None => panic!("ub: calling through incompatible fn pointer type"), + } + } +} + trait ErasedPtr: std::any::Any { fn pointee_type_id(&self) -> std::any::TypeId; fn memcpy(&self, src: &dyn ErasedPtr, len: usize); diff --git a/libcc2rs/src/reinterpret.rs b/libcc2rs/src/reinterpret.rs index 7bef816..1949501 100644 --- a/libcc2rs/src/reinterpret.rs +++ b/libcc2rs/src/reinterpret.rs @@ -64,6 +64,24 @@ impl ByteRepr for std::rc::Rc {} impl ByteRepr for std::cell::RefCell {} impl ByteRepr for Box<[T]> {} impl ByteRepr for Box {} + +macro_rules! impl_byterepr_fn { + ($($name:ident),*) => { + impl ByteRepr for fn($($name),*) -> R {} + }; +} + +impl_byterepr_fn!(); +impl_byterepr_fn!(A); +impl_byterepr_fn!(A, B); +impl_byterepr_fn!(A, B, C); +impl_byterepr_fn!(A, B, C, D); +impl_byterepr_fn!(A, B, C, D, E); +impl_byterepr_fn!(A, B, C, D, E, F); +impl_byterepr_fn!(A, B, C, D, E, F, G); +impl_byterepr_fn!(A, B, C, D, E, F, G, H); +impl_byterepr_fn!(A, B, C, D, E, F, G, H, I); +impl_byterepr_fn!(A, B, C, D, E, F, G, H, I, J); impl ByteRepr for *const T {} impl ByteRepr for *mut T {} impl ByteRepr for (A, B) {} diff --git a/tests/unit/fn_ptr_cast.cpp b/tests/unit/fn_ptr_cast.cpp index d9fc7ba..d825b05 100644 --- a/tests/unit/fn_ptr_cast.cpp +++ b/tests/unit/fn_ptr_cast.cpp @@ -36,9 +36,21 @@ void test_void_ptr_to_fn() { 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/out/refcount/fn_ptr.rs b/tests/unit/out/refcount/fn_ptr.rs index 77a3f29..f63e1ee 100644 --- a/tests/unit/out/refcount/fn_ptr.rs +++ b/tests/unit/out/refcount/fn_ptr.rs @@ -11,34 +11,34 @@ 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_: Option i32>, pi: Ptr) -> i32 { - let fn_: Value i32>> = Rc::new(RefCell::new(fn_)); +pub fn foo_1(fn_: Ptr 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()).unwrap()(_arg0) + (*fn_.borrow()).call_fn()(_arg0) }); } pub fn main() { std::process::exit(main_0()); } fn main_0() -> i32 { - let fn_: Value i32>> = Rc::new(RefCell::new(None)); - assert!((*fn_.borrow()).is_none()); + let fn_: Value i32>> = Rc::new(RefCell::new(Ptr::null())); + assert!((*fn_.borrow()).is_null()); assert!({ let _lhs = (*fn_.borrow()).clone(); - _lhs != Some(my_foo_0 as _) + _lhs != fn_ptr!(my_foo_0, fn(AnyPtr) -> i32) }); - (*fn_.borrow_mut()) = Some(my_foo_0 as _); - assert!(!((*fn_.borrow()).is_none())); + (*fn_.borrow_mut()) = fn_ptr!(my_foo_0, fn(AnyPtr) -> i32); + assert!(!((*fn_.borrow()).is_null())); assert!({ let _lhs = (*fn_.borrow()).clone(); - _lhs == Some(my_foo_0 as _) + _lhs == fn_ptr!(my_foo_0, fn(AnyPtr) -> i32) }); let a: Value = Rc::new(RefCell::new(10)); assert!({ let _lhs = ({ - let _fn: Option i32> = (*fn_.borrow()).clone(); + let _fn: Ptr i32> = (*fn_.borrow()).clone(); let _pi: Ptr = (a.as_pointer()); foo_1(_fn, _pi) }); diff --git a/tests/unit/out/refcount/fn_ptr_array.rs b/tests/unit/out/refcount/fn_ptr_array.rs index 3323c92..da29926 100644 --- a/tests/unit/out/refcount/fn_ptr_array.rs +++ b/tests/unit/out/refcount/fn_ptr_array.rs @@ -26,34 +26,34 @@ pub fn main() { std::process::exit(main_0()); } fn main_0() -> i32 { - let ops: Value i32>]>> = Rc::new(RefCell::new(Box::new([ - Some(add_0 as _), - Some(sub_1 as _), - Some(mul_2 as _), + let ops: Value i32>]>> = Rc::new(RefCell::new(Box::new([ + fn_ptr!(add_0, fn(i32, i32) -> i32), + fn_ptr!(sub_1, fn(i32, i32) -> i32), + fn_ptr!(mul_2, fn(i32, i32) -> i32), ]))); assert!( (({ let _arg0: i32 = 2; let _arg1: i32 = 3; - ((*ops.borrow())[(0) as usize]).unwrap()(_arg0, _arg1) + (*ops.borrow())[(0) as usize].call_fn()(_arg0, _arg1) }) == 5) ); assert!( (({ let _arg0: i32 = 7; let _arg1: i32 = 4; - ((*ops.borrow())[(1) as usize]).unwrap()(_arg0, _arg1) + (*ops.borrow())[(1) as usize].call_fn()(_arg0, _arg1) }) == 3) ); assert!( (({ let _arg0: i32 = 6; let _arg1: i32 = 5; - ((*ops.borrow())[(2) as usize]).unwrap()(_arg0, _arg1) + (*ops.borrow())[(2) as usize].call_fn()(_arg0, _arg1) }) == 30) ); - assert!(!(((*ops.borrow())[(0) as usize]).is_none())); - assert!(((*ops.borrow())[(0) as usize] == Some(add_0 as _))); - assert!(((*ops.borrow())[(0) as usize] != Some(sub_1 as _))); + assert!(!(((*ops.borrow())[(0) as usize]).is_null())); + assert!(((*ops.borrow())[(0) as usize] == fn_ptr!(add_0, fn(i32, i32) -> i32))); + assert!(((*ops.borrow())[(0) as usize] != fn_ptr!(sub_1, fn(i32, i32) -> i32))); return 0; } diff --git a/tests/unit/out/refcount/fn_ptr_as_condition.rs b/tests/unit/out/refcount/fn_ptr_as_condition.rs index 5547185..af8e24c 100644 --- a/tests/unit/out/refcount/fn_ptr_as_condition.rs +++ b/tests/unit/out/refcount/fn_ptr_as_condition.rs @@ -15,13 +15,13 @@ pub fn double_it_0(x: Ptr) { __ptr.write(__tmp) }; } -pub fn maybe_call_1(cb: Option)>, x: Ptr) { - let cb: Value)>> = Rc::new(RefCell::new(cb)); +pub fn maybe_call_1(cb: Ptr)>, x: Ptr) { + let cb: Value)>> = Rc::new(RefCell::new(cb)); let x: Value> = Rc::new(RefCell::new(x)); - if !(*cb.borrow()).is_none() { + if !(*cb.borrow()).is_null() { ({ let _arg0: Ptr = (*x.borrow()).clone(); - (*cb.borrow()).unwrap()(_arg0) + (*cb.borrow()).call_fn()(_arg0) }); } } @@ -31,27 +31,27 @@ pub fn main() { fn main_0() -> i32 { let a: Value = Rc::new(RefCell::new(5)); ({ - let _cb: Option)> = Some(double_it_0 as _); + let _cb: Ptr)> = fn_ptr!(double_it_0, fn(Ptr::)); 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: Option)> = None; + let _cb: Ptr)> = Ptr::null(); let _x: Ptr = (b.as_pointer()); maybe_call_1(_cb, _x) }); assert!(((*b.borrow()) == 5)); - let fn_: Value)>> = Rc::new(RefCell::new(None)); - if !!(*fn_.borrow()).is_none() { - (*fn_.borrow_mut()) = (Some(double_it_0 as _)).clone(); + let fn_: Value)>> = Rc::new(RefCell::new(Ptr::null())); + if !!(*fn_.borrow()).is_null() { + (*fn_.borrow_mut()) = (fn_ptr!(double_it_0, fn(Ptr::))).clone(); } let c: Value = Rc::new(RefCell::new(3)); - if !(*fn_.borrow()).is_none() { + if !(*fn_.borrow()).is_null() { ({ let _arg0: Ptr = (c.as_pointer()); - (*fn_.borrow()).unwrap()(_arg0) + (*fn_.borrow()).call_fn()(_arg0) }); } assert!(((*c.borrow()) == 6)); diff --git a/tests/unit/out/refcount/fn_ptr_cast.rs b/tests/unit/out/refcount/fn_ptr_cast.rs index cb0f77d..c3893d7 100644 --- a/tests/unit/out/refcount/fn_ptr_cast.rs +++ b/tests/unit/out/refcount/fn_ptr_cast.rs @@ -12,24 +12,25 @@ pub fn double_it_0(x: i32) -> i32 { return ((*x.borrow()) * 2); } pub fn test_roundtrip_1() { - let fn_: Value i32>> = Rc::new(RefCell::new(Some(double_it_0 as _))); + let fn_: Value i32>> = + Rc::new(RefCell::new(fn_ptr!(double_it_0, fn(i32) -> i32))); assert!( (({ let _arg0: i32 = 5; - (*fn_.borrow()).unwrap()(_arg0) + (*fn_.borrow()).call_fn()(_arg0) }) == 10) ); - let gfn: Value> = Rc::new(RefCell::new( - ((*fn_.borrow()).to_strong().as_pointer() as Value>).clone(), + let gfn: Value> = Rc::new(RefCell::new( + ((*fn_.borrow()).cast_fn::(None)).clone(), )); - assert!(!((*gfn.borrow()).is_none())); - let fn2: Value i32>> = Rc::new(RefCell::new( - ((*gfn.borrow()).to_strong().as_pointer() as Value i32>>).clone(), + assert!(!((*gfn.borrow()).is_null())); + let fn2: Value i32>> = Rc::new(RefCell::new( + ((*gfn.borrow()).cast_fn:: i32>(None)).clone(), )); assert!( (({ let _arg0: i32 = 5; - (*fn2.borrow()).unwrap()(_arg0) + (*fn2.borrow()).call_fn()(_arg0) }) == 10) ); assert!({ @@ -38,17 +39,18 @@ pub fn test_roundtrip_1() { }); } pub fn test_double_cast_2() { - let fn_: Value i32>> = Rc::new(RefCell::new(Some(double_it_0 as _))); - let fn2: Value i32>> = Rc::new(RefCell::new( - (((*fn_.borrow()).to_strong().as_pointer() as Value>) - .to_strong() - .as_pointer() as Value i32>>) - .clone(), + let fn_: Value i32>> = + Rc::new(RefCell::new(fn_ptr!(double_it_0, fn(i32) -> i32))); + let fn2: Value i32>> = Rc::new(RefCell::new( + ((*fn_.borrow()) + .cast_fn::(None) + .cast_fn:: i32>(None)) + .clone(), )); assert!( (({ let _arg0: i32 = 5; - (*fn2.borrow()).unwrap()(_arg0) + (*fn2.borrow()).call_fn()(_arg0) }) == 10) ); assert!({ @@ -71,21 +73,45 @@ impl Clone for Command { 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()) = - (Some(double_it_0 as _).to_strong().as_pointer() as AnyPtr); - let fn_: Value i32>> = Rc::new(RefCell::new( + (*(*cmd.borrow()).data.borrow_mut()) = fn_ptr!(double_it_0, fn(i32) -> i32).to_any(); + let fn_: Value i32>> = Rc::new(RefCell::new( ((*(*cmd.borrow()).data.borrow()) - .cast::() - .expect("ub:wrong type")) + .cast:: i32>() + .expect("ub:wrong fn type")) .clone(), )); assert!( (({ let _arg0: i32 = 5; - (*fn_.borrow()).unwrap()(_arg0) + (*fn_.borrow()).call_fn()(_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( + fn_ptr!(add_offset_4, fn(Ptr::, i32) -> i32).cast_fn:: 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()).call_fn()(_arg0, _arg1) + }), + )); + assert!(((*result.borrow()) == 142)); +} pub fn main() { std::process::exit(main_0()); } @@ -93,5 +119,6 @@ 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 index 6cc940a..fa323e1 100644 --- a/tests/unit/out/refcount/fn_ptr_conditional.rs +++ b/tests/unit/out/refcount/fn_ptr_conditional.rs @@ -19,30 +19,29 @@ pub fn identity_2(x: i32) -> i32 { let x: Value = Rc::new(RefCell::new(x)); return (*x.borrow()); } -pub fn pick_3(mode: i32) -> Option i32> { +pub fn pick_3(mode: i32) -> Ptr i32> { let mode: Value = Rc::new(RefCell::new(mode)); return if ((*mode.borrow()) > 0) { - Some(inc_0 as _) + fn_ptr!(inc_0, fn(i32) -> i32) } else { if ((*mode.borrow()) < 0) { - Some(dec_1 as _) + fn_ptr!(dec_1, fn(i32) -> i32) } else { - Some(identity_2 as _) + fn_ptr!(identity_2, fn(i32) -> i32) } }; } -pub fn apply_4(fn_: Option i32>, x: i32) -> i32 { - let fn_: Value i32>> = Rc::new(RefCell::new(fn_)); +pub fn apply_4(fn_: Ptr 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_none() { - (*fn_.borrow()).clone() - } else { - Some(identity_2 as _) - })); + let actual: Value i32>> = Rc::new(RefCell::new(if !(*fn_.borrow()).is_null() { + (*fn_.borrow()).clone() + } else { + fn_ptr!(identity_2, fn(i32) -> i32) + })); return ({ let _arg0: i32 = (*x.borrow()); - (*actual.borrow()).unwrap()(_arg0) + (*actual.borrow()).call_fn()(_arg0) }); } pub fn main() { @@ -56,7 +55,7 @@ fn main_0() -> i32 { let _mode: i32 = 1; pick_3(_mode) }) - .unwrap()(_arg0) + .call_fn()(_arg0) }) == 11) ); assert!( @@ -66,7 +65,7 @@ fn main_0() -> i32 { let _mode: i32 = -1_i32; pick_3(_mode) }) - .unwrap()(_arg0) + .call_fn()(_arg0) }) == 9) ); assert!( @@ -76,19 +75,19 @@ fn main_0() -> i32 { let _mode: i32 = 0; pick_3(_mode) }) - .unwrap()(_arg0) + .call_fn()(_arg0) }) == 10) ); assert!( (({ - let _fn: Option i32> = Some(inc_0 as _); + let _fn: Ptr i32> = fn_ptr!(inc_0, fn(i32) -> i32); let _x: i32 = 5; apply_4(_fn, _x) }) == 6) ); assert!( (({ - let _fn: Option i32> = None; + let _fn: Ptr i32> = Ptr::null(); let _x: i32 = 5; apply_4(_fn, _x) }) == 5) diff --git a/tests/unit/out/refcount/fn_ptr_default_arg.rs b/tests/unit/out/refcount/fn_ptr_default_arg.rs index 68af5d9..41961ea 100644 --- a/tests/unit/out/refcount/fn_ptr_default_arg.rs +++ b/tests/unit/out/refcount/fn_ptr_default_arg.rs @@ -11,13 +11,13 @@ 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 { +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(None))); - if !(*fn_.borrow()).is_none() { + let fn_: Value i32>> = Rc::new(RefCell::new(fn_.unwrap_or(Ptr::null()))); + if !(*fn_.borrow()).is_null() { return ({ let _arg0: i32 = (*x.borrow()); - (*fn_.borrow()).unwrap()(_arg0) + (*fn_.borrow()).call_fn()(_arg0) }); } return (*x.borrow()); @@ -29,32 +29,35 @@ fn main_0() -> i32 { assert!( (({ let _x: i32 = 5; - let _fn: Option i32> = Default::default(); + let _fn: Ptr i32> = Default::default(); apply_1(_x, Some(_fn)) }) == 5) ); assert!( (({ let _x: i32 = 5; - let _fn: Option i32> = None; + let _fn: Ptr i32> = Ptr::null(); apply_1(_x, Some(_fn)) }) == 5) ); assert!( (({ let _x: i32 = 5; - let _fn: Option i32> = Some(identity_0 as _); + let _fn: Ptr i32> = fn_ptr!(identity_0, fn(i32) -> i32); apply_1(_x, Some(_fn)) }) == 5) ); - let negate: Value i32>> = Rc::new(RefCell::new(Some(|x: i32| { - let x: Value = Rc::new(RefCell::new(x)); - return -(*x.borrow()); - }))); + let negate: Value i32>> = Rc::new(RefCell::new(Ptr::from_fn( + (|x: i32| { + let x: Value = Rc::new(RefCell::new(x)); + return -(*x.borrow()); + }) as fn(i32) -> i32, + 0, + ))); assert!( (({ let _x: i32 = 5; - let _fn: Option i32> = (*negate.borrow()).clone(); + let _fn: Ptr i32> = (*negate.borrow()).clone(); apply_1(_x, Some(_fn)) }) == -5_i32) ); diff --git a/tests/unit/out/refcount/fn_ptr_global.rs b/tests/unit/out/refcount/fn_ptr_global.rs index c7bf056..3830360 100644 --- a/tests/unit/out/refcount/fn_ptr_global.rs +++ b/tests/unit/out/refcount/fn_ptr_global.rs @@ -16,18 +16,18 @@ pub fn triple_it_1(x: i32) -> i32 { return ((*x.borrow()) * 3); } thread_local!( - pub static g_op: Value i32>> = Rc::new(RefCell::new(None)); + pub static g_op: Value i32>> = Rc::new(RefCell::new(Ptr::null())); ); -pub fn set_op_2(fn_: Option i32>) { - let fn_: Value i32>> = Rc::new(RefCell::new(fn_)); +pub fn set_op_2(fn_: Ptr 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_none() { + if !(*g_op.with(Value::clone).borrow()).is_null() { return ({ let _arg0: i32 = (*x.borrow()); - (*g_op.with(Value::clone).borrow()).unwrap()(_arg0) + (*g_op.with(Value::clone).borrow()).call_fn()(_arg0) }); } return (*x.borrow()); @@ -43,13 +43,13 @@ fn main_0() -> i32 { }) == 5) ); ({ - let _fn: Option i32> = Some(double_it_0 as _); + let _fn: Ptr i32> = fn_ptr!(double_it_0, fn(i32) -> i32); set_op_2(_fn) }); - assert!(!((*g_op.with(Value::clone).borrow()).is_none())); + assert!(!((*g_op.with(Value::clone).borrow()).is_null())); assert!({ let _lhs = (*g_op.with(Value::clone).borrow()).clone(); - _lhs == Some(double_it_0 as _) + _lhs == fn_ptr!(double_it_0, fn(i32) -> i32) }); assert!( (({ @@ -58,12 +58,12 @@ fn main_0() -> i32 { }) == 10) ); ({ - let _fn: Option i32> = Some(triple_it_1 as _); + let _fn: Ptr i32> = fn_ptr!(triple_it_1, fn(i32) -> i32); set_op_2(_fn) }); assert!({ let _lhs = (*g_op.with(Value::clone).borrow()).clone(); - _lhs == Some(triple_it_1 as _) + _lhs == fn_ptr!(triple_it_1, fn(i32) -> i32) }); assert!( (({ @@ -72,10 +72,10 @@ fn main_0() -> i32 { }) == 15) ); ({ - let _fn: Option i32> = None; + let _fn: Ptr i32> = Ptr::null(); set_op_2(_fn) }); - assert!((*g_op.with(Value::clone).borrow()).is_none()); + assert!((*g_op.with(Value::clone).borrow()).is_null()); assert!( (({ let _x: i32 = 5; diff --git a/tests/unit/out/refcount/fn_ptr_reassign.rs b/tests/unit/out/refcount/fn_ptr_reassign.rs index 98f6def..7675e66 100644 --- a/tests/unit/out/refcount/fn_ptr_reassign.rs +++ b/tests/unit/out/refcount/fn_ptr_reassign.rs @@ -26,39 +26,40 @@ pub fn main() { std::process::exit(main_0()); } fn main_0() -> i32 { - let fn_: Value i32>> = Rc::new(RefCell::new(Some(add_0 as _))); + let fn_: Value i32>> = + Rc::new(RefCell::new(fn_ptr!(add_0, fn(i32, i32) -> i32))); assert!( (({ let _arg0: i32 = 3; let _arg1: i32 = 4; - (*fn_.borrow()).unwrap()(_arg0, _arg1) + (*fn_.borrow()).call_fn()(_arg0, _arg1) }) == 7) ); - (*fn_.borrow_mut()) = Some(sub_1 as _); + (*fn_.borrow_mut()) = fn_ptr!(sub_1, fn(i32, i32) -> i32); assert!( (({ let _arg0: i32 = 10; let _arg1: i32 = 3; - (*fn_.borrow()).unwrap()(_arg0, _arg1) + (*fn_.borrow()).call_fn()(_arg0, _arg1) }) == 7) ); - (*fn_.borrow_mut()) = Some(mul_2 as _); + (*fn_.borrow_mut()) = fn_ptr!(mul_2, fn(i32, i32) -> i32); assert!( (({ let _arg0: i32 = 6; let _arg1: i32 = 7; - (*fn_.borrow()).unwrap()(_arg0, _arg1) + (*fn_.borrow()).call_fn()(_arg0, _arg1) }) == 42) ); - (*fn_.borrow_mut()) = None; - assert!((*fn_.borrow()).is_none()); - (*fn_.borrow_mut()) = Some(add_0 as _); - assert!(!((*fn_.borrow()).is_none())); + (*fn_.borrow_mut()) = Ptr::null(); + assert!((*fn_.borrow()).is_null()); + (*fn_.borrow_mut()) = fn_ptr!(add_0, fn(i32, i32) -> i32); + assert!(!((*fn_.borrow()).is_null())); assert!( (({ let _arg0: i32 = 1; let _arg1: i32 = 1; - (*fn_.borrow()).unwrap()(_arg0, _arg1) + (*fn_.borrow()).call_fn()(_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 index 9dead5c..2b9621f 100644 --- a/tests/unit/out/refcount/fn_ptr_return.rs +++ b/tests/unit/out/refcount/fn_ptr_return.rs @@ -15,35 +15,35 @@ 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) -> Option i32> { +pub fn pick_2(choose_inc: i32) -> Ptr i32> { let choose_inc: Value = Rc::new(RefCell::new(choose_inc)); if ((*choose_inc.borrow()) != 0) { - return Some(inc_0 as _); + return fn_ptr!(inc_0, fn(i32) -> i32); } - return Some(dec_1 as _); + return fn_ptr!(dec_1, fn(i32) -> i32); } pub fn main() { std::process::exit(main_0()); } fn main_0() -> i32 { - let f: Value i32>> = Rc::new(RefCell::new( + let f: Value i32>> = Rc::new(RefCell::new( ({ let _choose_inc: i32 = 1; pick_2(_choose_inc) }), )); - assert!(!((*f.borrow()).is_none())); + assert!(!((*f.borrow()).is_null())); assert!({ let _lhs = (*f.borrow()).clone(); - _lhs == Some(inc_0 as _) + _lhs == fn_ptr!(inc_0, fn(i32) -> i32) }); assert!( (({ let _arg0: i32 = 10; - (*f.borrow()).unwrap()(_arg0) + (*f.borrow()).call_fn()(_arg0) }) == 11) ); - let g: Value i32>> = Rc::new(RefCell::new( + let g: Value i32>> = Rc::new(RefCell::new( ({ let _choose_inc: i32 = 0; pick_2(_choose_inc) @@ -51,12 +51,12 @@ fn main_0() -> i32 { )); assert!({ let _lhs = (*g.borrow()).clone(); - _lhs == Some(dec_1 as _) + _lhs == fn_ptr!(dec_1, fn(i32) -> i32) }); assert!( (({ let _arg0: i32 = 10; - (*g.borrow()).unwrap()(_arg0) + (*g.borrow()).call_fn()(_arg0) }) == 9) ); assert!({ diff --git a/tests/unit/out/refcount/fn_ptr_struct.rs b/tests/unit/out/refcount/fn_ptr_struct.rs index 433b3f4..74d0c63 100644 --- a/tests/unit/out/refcount/fn_ptr_struct.rs +++ b/tests/unit/out/refcount/fn_ptr_struct.rs @@ -10,7 +10,7 @@ use std::rc::{Rc, Weak}; #[derive()] pub struct Handler { pub tag: Value, - pub cb: Value i32>>, + pub cb: Value i32>>, } impl Clone for Handler { fn clone(&self) -> Self { @@ -25,7 +25,7 @@ impl Default for Handler { fn default() -> Self { Handler { tag: >::default(), - cb: Rc::new(RefCell::new(None)), + cb: Rc::new(RefCell::new(Ptr::null())), } } } @@ -44,30 +44,30 @@ pub fn main() { fn main_0() -> i32 { let h1: Value = Rc::new(RefCell::new(Handler { tag: Rc::new(RefCell::new(1)), - cb: Rc::new(RefCell::new(Some(double_it_0 as _))), + cb: Rc::new(RefCell::new(fn_ptr!(double_it_0, fn(i32) -> i32))), })); let h2: Value = Rc::new(RefCell::new(Handler { tag: Rc::new(RefCell::new(2)), - cb: Rc::new(RefCell::new(Some(negate_1 as _))), + cb: Rc::new(RefCell::new(fn_ptr!(negate_1, fn(i32) -> i32))), })); - assert!(!((*(*h1.borrow()).cb.borrow()).is_none())); + assert!(!((*(*h1.borrow()).cb.borrow()).is_null())); assert!( (({ let _arg0: i32 = 5; - (*(*h1.borrow()).cb.borrow()).unwrap()(_arg0) + (*(*h1.borrow()).cb.borrow()).call_fn()(_arg0) }) == 10) ); assert!( (({ let _arg0: i32 = 7; - (*(*h2.borrow()).cb.borrow()).unwrap()(_arg0) + (*(*h2.borrow()).cb.borrow()).call_fn()(_arg0) }) == -7_i32) ); - (*(*h1.borrow()).cb.borrow_mut()) = Some(negate_1 as _); + (*(*h1.borrow()).cb.borrow_mut()) = fn_ptr!(negate_1, fn(i32) -> i32); assert!( (({ let _arg0: i32 = 3; - (*(*h1.borrow()).cb.borrow()).unwrap()(_arg0) + (*(*h1.borrow()).cb.borrow()).call_fn()(_arg0) }) == -3_i32) ); assert!({ diff --git a/tests/unit/out/refcount/fn_ptr_void_return.rs b/tests/unit/out/refcount/fn_ptr_void_return.rs index 9c2011b..316439a 100644 --- a/tests/unit/out/refcount/fn_ptr_void_return.rs +++ b/tests/unit/out/refcount/fn_ptr_void_return.rs @@ -16,12 +16,12 @@ pub fn zero_out_1(x: Ptr) { let x: Value> = Rc::new(RefCell::new(x)); (*x.borrow()).write(0); } -pub fn run_2(fn_: Option)>, x: Ptr) { - let fn_: Value)>> = Rc::new(RefCell::new(fn_)); +pub fn run_2(fn_: Ptr)>, 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()).unwrap()(_arg0) + (*fn_.borrow()).call_fn()(_arg0) }); } pub fn main() { @@ -30,23 +30,23 @@ pub fn main() { fn main_0() -> i32 { let a: Value = Rc::new(RefCell::new(42)); ({ - let _fn: Option)> = Some(negate_0 as _); + let _fn: Ptr)> = fn_ptr!(negate_0, fn(Ptr::)); let _x: Ptr = (a.as_pointer()); run_2(_fn, _x) }); assert!(((*a.borrow()) == -42_i32)); ({ - let _fn: Option)> = Some(zero_out_1 as _); + let _fn: Ptr)> = fn_ptr!(zero_out_1, fn(Ptr::)); let _x: Ptr = (a.as_pointer()); run_2(_fn, _x) }); assert!(((*a.borrow()) == 0)); - let fn_: Value)>> = Rc::new(RefCell::new(Some(negate_0 as _))); - assert!(!((*fn_.borrow()).is_none())); + let fn_: Value)>> = Rc::new(RefCell::new(fn_ptr!(negate_0, fn(Ptr::)))); + assert!(!((*fn_.borrow()).is_null())); let b: Value = Rc::new(RefCell::new(10)); ({ let _arg0: Ptr = (b.as_pointer()); - (*fn_.borrow()).unwrap()(_arg0) + (*fn_.borrow()).call_fn()(_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 index a9128c9..3ec0683 100644 --- a/tests/unit/out/refcount/fn_ptr_vtable.rs +++ b/tests/unit/out/refcount/fn_ptr_vtable.rs @@ -9,9 +9,9 @@ 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>, + pub create: Value AnyPtr>>, + pub get: Value i32>>, + pub destroy: Value>, } impl Clone for Vtable { fn clone(&self) -> Self { @@ -26,9 +26,9 @@ impl Clone for Vtable { impl Default for Vtable { fn default() -> Self { Vtable { - create: Rc::new(RefCell::new(None)), - get: Rc::new(RefCell::new(None)), - destroy: Rc::new(RefCell::new(None)), + create: Rc::new(RefCell::new(Ptr::null())), + get: Rc::new(RefCell::new(Ptr::null())), + destroy: Rc::new(RefCell::new(Ptr::null())), } } } @@ -54,31 +54,33 @@ pub fn main() { } fn main_0() -> i32 { let vt: Value = Rc::new(RefCell::new(Vtable { - create: Rc::new(RefCell::new((Some(int_create_0 as _)).clone())), - get: Rc::new(RefCell::new(Some(int_get_1 as _))), - destroy: Rc::new(RefCell::new(Some(int_destroy_2 as _))), + create: Rc::new(RefCell::new( + (fn_ptr!(int_create_0, fn(i32) -> AnyPtr)).clone(), + )), + get: Rc::new(RefCell::new(fn_ptr!(int_get_1, fn(AnyPtr) -> i32))), + destroy: Rc::new(RefCell::new(fn_ptr!(int_destroy_2, fn(AnyPtr)))), })); - assert!(!((*(*vt.borrow()).create.borrow()).is_none())); - assert!(!((*(*vt.borrow()).get.borrow()).is_none())); - assert!(!((*(*vt.borrow()).destroy.borrow()).is_none())); + 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()).unwrap()(_arg0) + (*(*vt.borrow()).create.borrow()).call_fn()(_arg0) }), )); assert!( (({ let _arg0: AnyPtr = (*obj.borrow()).clone(); - (*(*vt.borrow()).get.borrow()).unwrap()(_arg0) + (*(*vt.borrow()).get.borrow()).call_fn()(_arg0) }) == 42) ); ({ let _arg0: AnyPtr = (*obj.borrow()).clone(); - (*(*vt.borrow()).destroy.borrow()).unwrap()(_arg0) + (*(*vt.borrow()).destroy.borrow()).call_fn()(_arg0) }); assert!(((*storage.with(Value::clone).borrow()) == 0)); - (*(*vt.borrow()).get.borrow_mut()) = None; - assert!((*(*vt.borrow()).get.borrow()).is_none()); + (*(*vt.borrow()).get.borrow_mut()) = Ptr::null(); + assert!((*(*vt.borrow()).get.borrow()).is_null()); return 0; } diff --git a/tests/unit/out/refcount/no_direct_callee.rs b/tests/unit/out/refcount/no_direct_callee.rs index 33d09c6..5bd650b 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_: Option bool>) -> i32 { - let fn_: Value bool>> = Rc::new(RefCell::new(fn_)); - if !({ (*fn_.borrow()).unwrap()() }) { +pub fn test_1(fn_: Ptr bool>) -> i32 { + let fn_: Value bool>> = Rc::new(RefCell::new(fn_)); + if !({ (*fn_.borrow()).call_fn()() }) { return 1; } return 0; @@ -22,7 +22,7 @@ pub fn main() { } fn main_0() -> i32 { return ({ - let _fn: Option bool> = Some(test1_0 as _); + let _fn: Ptr bool> = fn_ptr!(test1_0, fn() -> bool); test_1(_fn) }); } diff --git a/tests/unit/out/unsafe/fn_ptr_cast.rs b/tests/unit/out/unsafe/fn_ptr_cast.rs index c4eee5e..e5ebf48 100644 --- a/tests/unit/out/unsafe/fn_ptr_cast.rs +++ b/tests/unit/out/unsafe/fn_ptr_cast.rs @@ -63,6 +63,24 @@ pub unsafe fn test_void_ptr_to_fn_3() { }) == (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 as _)); + 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); @@ -72,5 +90,6 @@ 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; } From a5d65f6e5d6ac40081bcb337cd8717e2fc66f122 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Tue, 14 Apr 2026 20:18:09 +0100 Subject: [PATCH 15/35] Move PtrKind::Fn into FnPtr --- .../converter/models/converter_refcount.cpp | 16 +- libcc2rs/src/fn_ptr.rs | 164 ++++++++++++++++++ libcc2rs/src/lib.rs | 14 +- libcc2rs/src/rc.rs | 110 +----------- tests/unit/out/refcount/fn_ptr.rs | 10 +- tests/unit/out/refcount/fn_ptr_array.rs | 8 +- .../unit/out/refcount/fn_ptr_as_condition.rs | 14 +- tests/unit/out/refcount/fn_ptr_cast.rs | 37 ++-- tests/unit/out/refcount/fn_ptr_conditional.rs | 29 ++-- tests/unit/out/refcount/fn_ptr_default_arg.rs | 20 +-- tests/unit/out/refcount/fn_ptr_global.rs | 14 +- tests/unit/out/refcount/fn_ptr_reassign.rs | 12 +- tests/unit/out/refcount/fn_ptr_return.rs | 10 +- tests/unit/out/refcount/fn_ptr_struct.rs | 10 +- tests/unit/out/refcount/fn_ptr_void_return.rs | 14 +- tests/unit/out/refcount/fn_ptr_vtable.rs | 20 +-- tests/unit/out/refcount/no_direct_callee.rs | 8 +- 17 files changed, 290 insertions(+), 220 deletions(-) create mode 100644 libcc2rs/src/fn_ptr.rs diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index d4637eb..19b2fdf 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -230,7 +230,7 @@ ConverterRefCount::GetFnTypeString(const clang::FunctionProtoType *proto) { bool ConverterRefCount::VisitPointerType(clang::PointerType *type) { if (auto proto = type->getPointeeType()->getAs()) { - StrCat(std::format("Ptr<{}>", GetFnTypeString(proto))); + StrCat(std::format("FnPtr<{}>", GetFnTypeString(proto))); return false; } @@ -1017,7 +1017,7 @@ bool ConverterRefCount::VisitImplicitCastExpr(clang::ImplicitCastExpr *expr) { if (expr->getCastKind() == clang::CastKind::CK_NullToPointer && expr->getType()->isFunctionPointerType()) { - StrCat("Ptr::null()"); + StrCat("FnPtr::null()"); computed_expr_type_ = ComputedExprType::FreshPointer; return false; } @@ -1027,12 +1027,12 @@ bool ConverterRefCount::VisitImplicitCastExpr(clang::ImplicitCastExpr *expr) { void ConverterRefCount::EmitFnPtrCall(clang::Expr *callee) { Convert(callee); - StrCat(".call_fn()"); + StrCat(".call()"); } std::string ConverterRefCount::GetFunctionPointerDefaultAsString( clang::QualType qual_type) { - return "Ptr::null()"; + return "FnPtr::null()"; } void ConverterRefCount::ConvertEqualsNullPtr(clang::Expr *expr) { @@ -1066,7 +1066,7 @@ bool ConverterRefCount::VisitFunctionPointerCast( } } - StrCat(std::format("{}.cast_fn::<{}>({})", ToString(expr->getSubExpr()), + StrCat(std::format("{}.cast::<{}>({})", ToString(expr->getSubExpr()), fn_type, adapter)); } else if (expr->getSubExpr()->getType()->isFunctionPointerType() || expr->getType()->isVoidPointerType()) { @@ -1077,7 +1077,7 @@ bool ConverterRefCount::VisitFunctionPointerCast( auto target_proto = expr->getType()->getPointeeType()->getAs(); auto fn_type = GetFnTypeString(target_proto); - StrCat(std::format("{}.cast::<{}>().expect(\"ub:wrong fn type\")", + StrCat(std::format("{}.cast_fn::<{}>().expect(\"ub:wrong fn type\")", ToString(expr->getSubExpr()), fn_type)); } else { assert(0 && "Unhandled function pointer cast"); @@ -1614,10 +1614,10 @@ void ConverterRefCount::ConvertVarInit(clang::QualType qual_type, Buffer buf(*this); PushConversionKind push(*this, ConversionKind::Unboxed); if (qual_type->isFunctionPointerType() && lambda->capture_size() == 0) { - StrCat(std::format("Ptr::from_fn((")); + StrCat("fn_ptr_anon!(("); VisitLambdaExpr(lambda); StrCat(std::format( - ") as {}, 0)", + "), {})", GetFnTypeString(qual_type->getPointeeType() ->getAs()))); } else { diff --git a/libcc2rs/src/fn_ptr.rs b/libcc2rs/src/fn_ptr.rs new file mode 100644 index 0000000..e2d9f6a --- /dev/null +++ b/libcc2rs/src/fn_ptr.rs @@ -0,0 +1,164 @@ +// 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::rc::Rc; + +use crate::rc::{AnyPtr, ErasedPtr}; +use crate::reinterpret::ByteRepr; + +#[derive(Clone)] +pub(crate) struct FnState { + addr: usize, + cast_history: Vec>>, +} + +pub struct FnPtr { + state: Option>, + // FnPtr does not use T, hence wrap in PhantomData + _marker: PhantomData, +} + +impl FnPtr { + #[inline] + pub fn null() -> Self { + FnPtr { + state: None, + _marker: PhantomData, + } + } + + #[inline] + pub fn is_null(&self) -> bool { + self.state.is_none() + } +} + +impl FnPtr { + pub fn new(f: T, addr: usize) -> Self { + FnPtr { + state: Some(Rc::new(FnState { + addr, + cast_history: vec![Some(Rc::new(f))], + })), + _marker: PhantomData, + } + } + + pub fn cast(&self, adapter: Option) -> FnPtr { + let state = self.state.as_ref().expect("ub: null fn pointer cast"); + + for (i, entry) in state.cast_history.iter().enumerate() { + if let Some(ref rc) = entry { + if (*rc).as_ref().type_id() == TypeId::of::() { + return FnPtr { + state: Some(Rc::new(FnState { + addr: state.addr, + cast_history: state.cast_history[..=i].to_vec(), + })), + _marker: PhantomData, + }; + } + } + } + + let mut new_stack = state.cast_history.clone(); + new_stack.push(adapter.map(|a| Rc::new(a) as Rc)); + + FnPtr { + state: Some(Rc::new(FnState { + addr: state.addr, + cast_history: new_stack, + })), + _marker: PhantomData, + } + } + + pub fn call(&self) -> T + where + T: Copy, + { + let state = self.state.as_ref().expect("ub: null fn pointer call"); + let entry = state + .cast_history + .last() + .expect("empty fn pointer cast_history"); + match entry { + Some(rc) => *rc + .downcast_ref::() + .expect("ub: fn pointer type mismatch"), + None => panic!("ub: calling through incompatible fn pointer type"), + } + } +} + +impl Clone for FnPtr { + fn clone(&self) -> Self { + FnPtr { + state: self.state.clone(), + _marker: PhantomData, + } + } +} + +impl Default for FnPtr { + fn default() -> Self { + Self::null() + } +} + +impl PartialEq for FnPtr { + fn eq(&self, other: &Self) -> bool { + match (&self.state, &other.state) { + (None, None) => true, + (Some(a), Some(b)) => a.addr == b.addr, + _ => false, + } + } +} + +impl Eq for FnPtr {} + +impl std::fmt::Debug for FnPtr { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match &self.state { + None => write!(f, "FnPtr(null)"), + Some(s) => write!(f, "FnPtr(0x{:x})", s.addr), + } + } +} + +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) + } +} + +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 9b7b96e..998280f 100644 --- a/libcc2rs/src/lib.rs +++ b/libcc2rs/src/lib.rs @@ -7,13 +7,25 @@ pub use reinterpret::ByteRepr; #[macro_export] macro_rules! fn_ptr { ($f:expr, $ty:ty) => { - $crate::Ptr::from_fn($f as $ty, $f as *const () as usize) + $crate::FnPtr::new($f as $ty, $f as *const () as usize) + }; +} + +// Lambda: no stable address, use 0. TODO: assign unique addr per lambda site so distinct +// lambdas don't compare equal. +#[macro_export] +macro_rules! fn_ptr_anon { + ($f:expr, $ty:ty) => { + $crate::FnPtr::new($f as $ty, 0) }; } 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 a9b87eb..3b8fbe1 100644 --- a/libcc2rs/src/rc.rs +++ b/libcc2rs/src/rc.rs @@ -26,32 +26,6 @@ enum PtrKind { HeapArray(Weak>>), Vec(Weak>>), Reinterpreted(Rc), - Fn(Rc), -} - -struct FnPtrAlloc { - addr: usize, -} - -impl OriginalAlloc for FnPtrAlloc { - fn address(&self) -> usize { - self.addr - } - fn read_bytes(&self, _: usize, _: &mut [u8]) { - panic!("fn pointer"); - } - fn write_bytes(&self, _: usize, _: &[u8]) { - panic!("fn pointer"); - } - fn total_byte_len(&self) -> usize { - panic!("fn pointer"); - } -} - -#[derive(Clone)] -pub struct FnState { - alloc: Rc, - stack: Vec>>, } pub enum StrongPtr { @@ -106,7 +80,6 @@ impl fmt::Debug for PtrKind { PtrKind::Reinterpreted(ref data) => { write!(f, "Reinterpreted(0x{:x})", data.address()) } - PtrKind::Fn(ref state) => write!(f, "Fn(0x{:x})", state.alloc.address()), } } } @@ -121,7 +94,6 @@ impl Clone for PtrKind { PtrKind::StackArray(ref weak) => PtrKind::StackArray(weak.clone()), PtrKind::HeapArray(ref weak) => PtrKind::HeapArray(weak.clone()), PtrKind::Reinterpreted(ref data) => PtrKind::Reinterpreted(Rc::clone(data)), - PtrKind::Fn(ref state) => PtrKind::Fn(Rc::clone(state)), } } } @@ -134,7 +106,6 @@ impl PtrKind { PtrKind::Vec(w) => w.as_ptr() as usize, PtrKind::StackArray(w) | PtrKind::HeapArray(w) => w.as_ptr() as usize, PtrKind::Reinterpreted(ref data) => data.address(), - PtrKind::Fn(ref state) => state.alloc.address(), } } } @@ -298,7 +269,6 @@ impl Ptr { let step = std::mem::size_of::(); (data.total_byte_len() - self.offset % step) / step } - PtrKind::Fn(_) => 1, } } @@ -362,7 +332,6 @@ impl Ptr { byte_offset: self.offset, cell: RefCell::new(None), }, - PtrKind::Fn(_) => panic!("fn pointer"), } } @@ -389,7 +358,6 @@ impl Ptr { value.to_bytes(&mut buf); data.write_bytes(self.offset, &buf); } - PtrKind::Fn(_) => panic!("fn pointer"), } } @@ -430,7 +398,6 @@ impl Ptr { self.byte_offset(), ), PtrKind::Reinterpreted(ref data) => (Rc::clone(data), self.offset), - PtrKind::Fn(_) => panic!("fn pointer: use cast_fn instead"), }; Ptr { @@ -471,7 +438,6 @@ impl Ptr { data.write_bytes(self.offset, &buf); ret } - PtrKind::Fn(_) => panic!("fn pointer"), } } @@ -505,7 +471,6 @@ impl Ptr { data.write_bytes(self.offset, &buf); ret } - PtrKind::Fn(_) => panic!("fn pointer"), } } } @@ -532,7 +497,6 @@ impl Ptr { data.read_bytes(self.offset, &mut buf); T::from_bytes(&buf) } - PtrKind::Fn(_) => panic!("fn pointer"), } } } @@ -565,7 +529,6 @@ impl Ptr { PtrKind::Reinterpreted(..) => { panic!("sorting not supported for reinterpreted pointers") } - PtrKind::Fn(_) => panic!("fn pointer"), } } } @@ -619,7 +582,6 @@ impl Ptr { PtrKind::Reinterpreted(..) => { panic!("sorting not supported for reinterpreted pointers") } - PtrKind::Fn(_) => panic!("fn pointer"), } } } @@ -868,7 +830,6 @@ impl ToOwnedOption for Ptr { PtrKind::Vec(_) => panic!("Can't own a vector"), PtrKind::HeapArray(_) => panic!("Can't own an array variable as single"), PtrKind::Reinterpreted(..) => panic!("Can't own a reinterpreted pointer"), - PtrKind::Fn(_) => panic!("fn pointer"), } } } @@ -895,7 +856,6 @@ impl ToOwnedOption> for Ptr { PtrKind::Vec(_) => panic!("Can't own a vector"), PtrKind::HeapSingle(_) => panic!("Can't own a single variable as an array"), PtrKind::Reinterpreted(..) => panic!("Can't own a reinterpreted pointer"), - PtrKind::Fn(_) => panic!("fn pointer"), } } } @@ -911,7 +871,6 @@ impl fmt::Debug for Ptr { PtrKind::Vec(w) => (Weak::as_ptr(w) as usize) .wrapping_add(self.offset.wrapping_mul(std::mem::size_of::())), PtrKind::Reinterpreted(ref data) => data.address().wrapping_add(self.offset), - PtrKind::Fn(ref state) => state.alloc.address(), }; write!(f, "0x{:x}", addr) } @@ -1008,7 +967,6 @@ impl Ptr { data.read_bytes(start, &mut buf); buf } - PtrKind::Fn(_) => panic!("fn pointer"), } } @@ -1046,71 +1004,7 @@ impl Ptr { } } -impl Ptr { - pub fn from_fn(f: T, addr: usize) -> Self { - Ptr { - offset: 0, - kind: PtrKind::Fn(Rc::new(FnState { - alloc: Rc::new(FnPtrAlloc { addr }), - stack: vec![Some(Rc::new(f))], - })), - } - } - - pub fn cast_fn(&self, adapter: Option) -> Ptr { - let state = match &self.kind { - PtrKind::Fn(ref state) => state, - _ => panic!("not a fn pointer"), - }; - - let target_id = TypeId::of::(); - - for (i, entry) in state.stack.iter().enumerate() { - if let Some(ref rc) = entry { - if (*rc).as_ref().type_id() == target_id { - return Ptr { - offset: 0, - kind: PtrKind::Fn(Rc::new(FnState { - alloc: Rc::clone(&state.alloc), - stack: state.stack[..=i].to_vec(), - })), - }; - } - } - } - - let mut new_stack = state.stack.clone(); - new_stack.push(adapter.map(|a| Rc::new(a) as Rc)); - - Ptr { - offset: 0, - kind: PtrKind::Fn(Rc::new(FnState { - alloc: Rc::clone(&state.alloc), - stack: new_stack, - })), - } - } - - pub fn call_fn(&self) -> T - where - T: Copy + 'static, - { - let state = match &self.kind { - PtrKind::Fn(ref state) => state, - _ => panic!("not a fn pointer"), - }; - - let entry = state.stack.last().expect("empty fn pointer stack"); - match entry { - Some(ref rc) => *rc - .downcast_ref::() - .expect("ub: fn pointer type mismatch"), - None => panic!("ub: calling through incompatible fn pointer type"), - } - } -} - -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; @@ -1180,7 +1074,7 @@ where #[derive(Clone)] pub struct AnyPtr { - ptr: Rc, + pub(crate) ptr: Rc, } impl Ptr { diff --git a/tests/unit/out/refcount/fn_ptr.rs b/tests/unit/out/refcount/fn_ptr.rs index f63e1ee..0ef5625 100644 --- a/tests/unit/out/refcount/fn_ptr.rs +++ b/tests/unit/out/refcount/fn_ptr.rs @@ -11,19 +11,19 @@ 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_: Ptr i32>, pi: Ptr) -> i32 { - let fn_: Value i32>> = Rc::new(RefCell::new(fn_)); +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()).call_fn()(_arg0) + (*fn_.borrow()).call()(_arg0) }); } pub fn main() { std::process::exit(main_0()); } fn main_0() -> i32 { - let fn_: Value i32>> = Rc::new(RefCell::new(Ptr::null())); + let fn_: Value i32>> = Rc::new(RefCell::new(FnPtr::null())); assert!((*fn_.borrow()).is_null()); assert!({ let _lhs = (*fn_.borrow()).clone(); @@ -38,7 +38,7 @@ fn main_0() -> i32 { let a: Value = Rc::new(RefCell::new(10)); assert!({ let _lhs = ({ - let _fn: Ptr i32> = (*fn_.borrow()).clone(); + let _fn: FnPtr i32> = (*fn_.borrow()).clone(); let _pi: Ptr = (a.as_pointer()); foo_1(_fn, _pi) }); diff --git a/tests/unit/out/refcount/fn_ptr_array.rs b/tests/unit/out/refcount/fn_ptr_array.rs index da29926..8e1d5fc 100644 --- a/tests/unit/out/refcount/fn_ptr_array.rs +++ b/tests/unit/out/refcount/fn_ptr_array.rs @@ -26,7 +26,7 @@ pub fn main() { std::process::exit(main_0()); } fn main_0() -> i32 { - let ops: Value i32>]>> = Rc::new(RefCell::new(Box::new([ + let ops: Value i32>]>> = Rc::new(RefCell::new(Box::new([ fn_ptr!(add_0, fn(i32, i32) -> i32), fn_ptr!(sub_1, fn(i32, i32) -> i32), fn_ptr!(mul_2, fn(i32, i32) -> i32), @@ -35,21 +35,21 @@ fn main_0() -> i32 { (({ let _arg0: i32 = 2; let _arg1: i32 = 3; - (*ops.borrow())[(0) as usize].call_fn()(_arg0, _arg1) + (*ops.borrow())[(0) as usize].call()(_arg0, _arg1) }) == 5) ); assert!( (({ let _arg0: i32 = 7; let _arg1: i32 = 4; - (*ops.borrow())[(1) as usize].call_fn()(_arg0, _arg1) + (*ops.borrow())[(1) as usize].call()(_arg0, _arg1) }) == 3) ); assert!( (({ let _arg0: i32 = 6; let _arg1: i32 = 5; - (*ops.borrow())[(2) as usize].call_fn()(_arg0, _arg1) + (*ops.borrow())[(2) as usize].call()(_arg0, _arg1) }) == 30) ); assert!(!(((*ops.borrow())[(0) as usize]).is_null())); diff --git a/tests/unit/out/refcount/fn_ptr_as_condition.rs b/tests/unit/out/refcount/fn_ptr_as_condition.rs index af8e24c..c6ffacf 100644 --- a/tests/unit/out/refcount/fn_ptr_as_condition.rs +++ b/tests/unit/out/refcount/fn_ptr_as_condition.rs @@ -15,13 +15,13 @@ pub fn double_it_0(x: Ptr) { __ptr.write(__tmp) }; } -pub fn maybe_call_1(cb: Ptr)>, x: Ptr) { - let cb: Value)>> = Rc::new(RefCell::new(cb)); +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()).call_fn()(_arg0) + (*cb.borrow()).call()(_arg0) }); } } @@ -31,19 +31,19 @@ pub fn main() { fn main_0() -> i32 { let a: Value = Rc::new(RefCell::new(5)); ({ - let _cb: Ptr)> = fn_ptr!(double_it_0, fn(Ptr::)); + let _cb: FnPtr)> = fn_ptr!(double_it_0, fn(Ptr::)); 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: Ptr)> = Ptr::null(); + 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(Ptr::null())); + let fn_: Value)>> = Rc::new(RefCell::new(FnPtr::null())); if !!(*fn_.borrow()).is_null() { (*fn_.borrow_mut()) = (fn_ptr!(double_it_0, fn(Ptr::))).clone(); } @@ -51,7 +51,7 @@ fn main_0() -> i32 { if !(*fn_.borrow()).is_null() { ({ let _arg0: Ptr = (c.as_pointer()); - (*fn_.borrow()).call_fn()(_arg0) + (*fn_.borrow()).call()(_arg0) }); } assert!(((*c.borrow()) == 6)); diff --git a/tests/unit/out/refcount/fn_ptr_cast.rs b/tests/unit/out/refcount/fn_ptr_cast.rs index c3893d7..c33b2bd 100644 --- a/tests/unit/out/refcount/fn_ptr_cast.rs +++ b/tests/unit/out/refcount/fn_ptr_cast.rs @@ -12,25 +12,24 @@ pub fn double_it_0(x: i32) -> i32 { return ((*x.borrow()) * 2); } pub fn test_roundtrip_1() { - let fn_: Value i32>> = + let fn_: Value i32>> = Rc::new(RefCell::new(fn_ptr!(double_it_0, fn(i32) -> i32))); assert!( (({ let _arg0: i32 = 5; - (*fn_.borrow()).call_fn()(_arg0) + (*fn_.borrow()).call()(_arg0) }) == 10) ); - let gfn: Value> = Rc::new(RefCell::new( - ((*fn_.borrow()).cast_fn::(None)).clone(), - )); + 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_fn:: i32>(None)).clone(), + let fn2: Value i32>> = Rc::new(RefCell::new( + ((*gfn.borrow()).cast:: i32>(None)).clone(), )); assert!( (({ let _arg0: i32 = 5; - (*fn2.borrow()).call_fn()(_arg0) + (*fn2.borrow()).call()(_arg0) }) == 10) ); assert!({ @@ -39,18 +38,18 @@ pub fn test_roundtrip_1() { }); } pub fn test_double_cast_2() { - let fn_: Value i32>> = + let fn_: Value i32>> = Rc::new(RefCell::new(fn_ptr!(double_it_0, fn(i32) -> i32))); - let fn2: Value i32>> = Rc::new(RefCell::new( + let fn2: Value i32>> = Rc::new(RefCell::new( ((*fn_.borrow()) - .cast_fn::(None) - .cast_fn:: i32>(None)) + .cast::(None) + .cast:: i32>(None)) .clone(), )); assert!( (({ let _arg0: i32 = 5; - (*fn2.borrow()).call_fn()(_arg0) + (*fn2.borrow()).call()(_arg0) }) == 10) ); assert!({ @@ -74,16 +73,16 @@ 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()) = fn_ptr!(double_it_0, fn(i32) -> i32).to_any(); - let fn_: Value i32>> = Rc::new(RefCell::new( + let fn_: Value i32>> = Rc::new(RefCell::new( ((*(*cmd.borrow()).data.borrow()) - .cast:: i32>() + .cast_fn:: i32>() .expect("ub:wrong fn type")) .clone(), )); assert!( (({ let _arg0: i32 = 5; - (*fn_.borrow()).call_fn()(_arg0) + (*fn_.borrow()).call()(_arg0) }) == 10) ); } @@ -96,8 +95,8 @@ pub fn add_offset_4(base: Ptr, offset: i32) -> i32 { }; } pub fn test_call_through_cast_5() { - let gfn: Value i32>> = Rc::new(RefCell::new( - fn_ptr!(add_offset_4, fn(Ptr::, i32) -> i32).cast_fn:: i32>(Some( + let gfn: Value i32>> = Rc::new(RefCell::new( + fn_ptr!(add_offset_4, fn(Ptr::, i32) -> i32).cast:: i32>(Some( (|a0: AnyPtr, a1: i32| -> i32 { add_offset_4(a0.cast::().unwrap(), a1) }) as fn(AnyPtr, i32) -> i32, )), @@ -107,7 +106,7 @@ pub fn test_call_through_cast_5() { ({ let _arg0: AnyPtr = ((val.as_pointer()) as Ptr).to_any(); let _arg1: i32 = 42; - (*gfn.borrow()).call_fn()(_arg0, _arg1) + (*gfn.borrow()).call()(_arg0, _arg1) }), )); assert!(((*result.borrow()) == 142)); diff --git a/tests/unit/out/refcount/fn_ptr_conditional.rs b/tests/unit/out/refcount/fn_ptr_conditional.rs index fa323e1..c6e577a 100644 --- a/tests/unit/out/refcount/fn_ptr_conditional.rs +++ b/tests/unit/out/refcount/fn_ptr_conditional.rs @@ -19,7 +19,7 @@ pub fn identity_2(x: i32) -> i32 { let x: Value = Rc::new(RefCell::new(x)); return (*x.borrow()); } -pub fn pick_3(mode: i32) -> Ptr i32> { +pub fn pick_3(mode: i32) -> FnPtr i32> { let mode: Value = Rc::new(RefCell::new(mode)); return if ((*mode.borrow()) > 0) { fn_ptr!(inc_0, fn(i32) -> i32) @@ -31,17 +31,18 @@ pub fn pick_3(mode: i32) -> Ptr i32> { } }; } -pub fn apply_4(fn_: Ptr i32>, x: i32) -> i32 { - let fn_: Value i32>> = Rc::new(RefCell::new(fn_)); +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 { - fn_ptr!(identity_2, fn(i32) -> i32) - })); + let actual: Value i32>> = + Rc::new(RefCell::new(if !(*fn_.borrow()).is_null() { + (*fn_.borrow()).clone() + } else { + fn_ptr!(identity_2, fn(i32) -> i32) + })); return ({ let _arg0: i32 = (*x.borrow()); - (*actual.borrow()).call_fn()(_arg0) + (*actual.borrow()).call()(_arg0) }); } pub fn main() { @@ -55,7 +56,7 @@ fn main_0() -> i32 { let _mode: i32 = 1; pick_3(_mode) }) - .call_fn()(_arg0) + .call()(_arg0) }) == 11) ); assert!( @@ -65,7 +66,7 @@ fn main_0() -> i32 { let _mode: i32 = -1_i32; pick_3(_mode) }) - .call_fn()(_arg0) + .call()(_arg0) }) == 9) ); assert!( @@ -75,19 +76,19 @@ fn main_0() -> i32 { let _mode: i32 = 0; pick_3(_mode) }) - .call_fn()(_arg0) + .call()(_arg0) }) == 10) ); assert!( (({ - let _fn: Ptr i32> = fn_ptr!(inc_0, fn(i32) -> i32); + let _fn: FnPtr i32> = fn_ptr!(inc_0, fn(i32) -> i32); let _x: i32 = 5; apply_4(_fn, _x) }) == 6) ); assert!( (({ - let _fn: Ptr i32> = Ptr::null(); + let _fn: FnPtr i32> = FnPtr::null(); let _x: i32 = 5; apply_4(_fn, _x) }) == 5) diff --git a/tests/unit/out/refcount/fn_ptr_default_arg.rs b/tests/unit/out/refcount/fn_ptr_default_arg.rs index 41961ea..6c6ab79 100644 --- a/tests/unit/out/refcount/fn_ptr_default_arg.rs +++ b/tests/unit/out/refcount/fn_ptr_default_arg.rs @@ -11,13 +11,13 @@ 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 { +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(Ptr::null()))); + 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()).call_fn()(_arg0) + (*fn_.borrow()).call()(_arg0) }); } return (*x.borrow()); @@ -29,35 +29,35 @@ fn main_0() -> i32 { assert!( (({ let _x: i32 = 5; - let _fn: Ptr i32> = Default::default(); + let _fn: FnPtr i32> = Default::default(); apply_1(_x, Some(_fn)) }) == 5) ); assert!( (({ let _x: i32 = 5; - let _fn: Ptr i32> = Ptr::null(); + let _fn: FnPtr i32> = FnPtr::null(); apply_1(_x, Some(_fn)) }) == 5) ); assert!( (({ let _x: i32 = 5; - let _fn: Ptr i32> = fn_ptr!(identity_0, fn(i32) -> i32); + let _fn: FnPtr i32> = fn_ptr!(identity_0, fn(i32) -> i32); apply_1(_x, Some(_fn)) }) == 5) ); - let negate: Value i32>> = Rc::new(RefCell::new(Ptr::from_fn( + let negate: Value i32>> = Rc::new(RefCell::new(fn_ptr_anon!( (|x: i32| { let x: Value = Rc::new(RefCell::new(x)); return -(*x.borrow()); - }) as fn(i32) -> i32, - 0, + }), + fn(i32) -> i32 ))); assert!( (({ let _x: i32 = 5; - let _fn: Ptr i32> = (*negate.borrow()).clone(); + let _fn: FnPtr i32> = (*negate.borrow()).clone(); apply_1(_x, Some(_fn)) }) == -5_i32) ); diff --git a/tests/unit/out/refcount/fn_ptr_global.rs b/tests/unit/out/refcount/fn_ptr_global.rs index 3830360..af0dca9 100644 --- a/tests/unit/out/refcount/fn_ptr_global.rs +++ b/tests/unit/out/refcount/fn_ptr_global.rs @@ -16,10 +16,10 @@ pub fn triple_it_1(x: i32) -> i32 { return ((*x.borrow()) * 3); } thread_local!( - pub static g_op: Value i32>> = Rc::new(RefCell::new(Ptr::null())); + pub static g_op: Value i32>> = Rc::new(RefCell::new(FnPtr::null())); ); -pub fn set_op_2(fn_: Ptr i32>) { - let fn_: Value i32>> = Rc::new(RefCell::new(fn_)); +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 { @@ -27,7 +27,7 @@ pub fn call_op_3(x: i32) -> i32 { if !(*g_op.with(Value::clone).borrow()).is_null() { return ({ let _arg0: i32 = (*x.borrow()); - (*g_op.with(Value::clone).borrow()).call_fn()(_arg0) + (*g_op.with(Value::clone).borrow()).call()(_arg0) }); } return (*x.borrow()); @@ -43,7 +43,7 @@ fn main_0() -> i32 { }) == 5) ); ({ - let _fn: Ptr i32> = fn_ptr!(double_it_0, fn(i32) -> i32); + let _fn: FnPtr i32> = fn_ptr!(double_it_0, fn(i32) -> i32); set_op_2(_fn) }); assert!(!((*g_op.with(Value::clone).borrow()).is_null())); @@ -58,7 +58,7 @@ fn main_0() -> i32 { }) == 10) ); ({ - let _fn: Ptr i32> = fn_ptr!(triple_it_1, fn(i32) -> i32); + let _fn: FnPtr i32> = fn_ptr!(triple_it_1, fn(i32) -> i32); set_op_2(_fn) }); assert!({ @@ -72,7 +72,7 @@ fn main_0() -> i32 { }) == 15) ); ({ - let _fn: Ptr i32> = Ptr::null(); + let _fn: FnPtr i32> = FnPtr::null(); set_op_2(_fn) }); assert!((*g_op.with(Value::clone).borrow()).is_null()); diff --git a/tests/unit/out/refcount/fn_ptr_reassign.rs b/tests/unit/out/refcount/fn_ptr_reassign.rs index 7675e66..123abbe 100644 --- a/tests/unit/out/refcount/fn_ptr_reassign.rs +++ b/tests/unit/out/refcount/fn_ptr_reassign.rs @@ -26,13 +26,13 @@ pub fn main() { std::process::exit(main_0()); } fn main_0() -> i32 { - let fn_: Value i32>> = + let fn_: Value i32>> = Rc::new(RefCell::new(fn_ptr!(add_0, fn(i32, i32) -> i32))); assert!( (({ let _arg0: i32 = 3; let _arg1: i32 = 4; - (*fn_.borrow()).call_fn()(_arg0, _arg1) + (*fn_.borrow()).call()(_arg0, _arg1) }) == 7) ); (*fn_.borrow_mut()) = fn_ptr!(sub_1, fn(i32, i32) -> i32); @@ -40,7 +40,7 @@ fn main_0() -> i32 { (({ let _arg0: i32 = 10; let _arg1: i32 = 3; - (*fn_.borrow()).call_fn()(_arg0, _arg1) + (*fn_.borrow()).call()(_arg0, _arg1) }) == 7) ); (*fn_.borrow_mut()) = fn_ptr!(mul_2, fn(i32, i32) -> i32); @@ -48,10 +48,10 @@ fn main_0() -> i32 { (({ let _arg0: i32 = 6; let _arg1: i32 = 7; - (*fn_.borrow()).call_fn()(_arg0, _arg1) + (*fn_.borrow()).call()(_arg0, _arg1) }) == 42) ); - (*fn_.borrow_mut()) = Ptr::null(); + (*fn_.borrow_mut()) = FnPtr::null(); assert!((*fn_.borrow()).is_null()); (*fn_.borrow_mut()) = fn_ptr!(add_0, fn(i32, i32) -> i32); assert!(!((*fn_.borrow()).is_null())); @@ -59,7 +59,7 @@ fn main_0() -> i32 { (({ let _arg0: i32 = 1; let _arg1: i32 = 1; - (*fn_.borrow()).call_fn()(_arg0, _arg1) + (*fn_.borrow()).call()(_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 index 2b9621f..4368149 100644 --- a/tests/unit/out/refcount/fn_ptr_return.rs +++ b/tests/unit/out/refcount/fn_ptr_return.rs @@ -15,7 +15,7 @@ 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) -> Ptr i32> { +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 fn_ptr!(inc_0, fn(i32) -> i32); @@ -26,7 +26,7 @@ pub fn main() { std::process::exit(main_0()); } fn main_0() -> i32 { - let f: Value i32>> = Rc::new(RefCell::new( + let f: Value i32>> = Rc::new(RefCell::new( ({ let _choose_inc: i32 = 1; pick_2(_choose_inc) @@ -40,10 +40,10 @@ fn main_0() -> i32 { assert!( (({ let _arg0: i32 = 10; - (*f.borrow()).call_fn()(_arg0) + (*f.borrow()).call()(_arg0) }) == 11) ); - let g: Value i32>> = Rc::new(RefCell::new( + let g: Value i32>> = Rc::new(RefCell::new( ({ let _choose_inc: i32 = 0; pick_2(_choose_inc) @@ -56,7 +56,7 @@ fn main_0() -> i32 { assert!( (({ let _arg0: i32 = 10; - (*g.borrow()).call_fn()(_arg0) + (*g.borrow()).call()(_arg0) }) == 9) ); assert!({ diff --git a/tests/unit/out/refcount/fn_ptr_struct.rs b/tests/unit/out/refcount/fn_ptr_struct.rs index 74d0c63..777a60e 100644 --- a/tests/unit/out/refcount/fn_ptr_struct.rs +++ b/tests/unit/out/refcount/fn_ptr_struct.rs @@ -10,7 +10,7 @@ use std::rc::{Rc, Weak}; #[derive()] pub struct Handler { pub tag: Value, - pub cb: Value i32>>, + pub cb: Value i32>>, } impl Clone for Handler { fn clone(&self) -> Self { @@ -25,7 +25,7 @@ impl Default for Handler { fn default() -> Self { Handler { tag: >::default(), - cb: Rc::new(RefCell::new(Ptr::null())), + cb: Rc::new(RefCell::new(FnPtr::null())), } } } @@ -54,20 +54,20 @@ fn main_0() -> i32 { assert!( (({ let _arg0: i32 = 5; - (*(*h1.borrow()).cb.borrow()).call_fn()(_arg0) + (*(*h1.borrow()).cb.borrow()).call()(_arg0) }) == 10) ); assert!( (({ let _arg0: i32 = 7; - (*(*h2.borrow()).cb.borrow()).call_fn()(_arg0) + (*(*h2.borrow()).cb.borrow()).call()(_arg0) }) == -7_i32) ); (*(*h1.borrow()).cb.borrow_mut()) = fn_ptr!(negate_1, fn(i32) -> i32); assert!( (({ let _arg0: i32 = 3; - (*(*h1.borrow()).cb.borrow()).call_fn()(_arg0) + (*(*h1.borrow()).cb.borrow()).call()(_arg0) }) == -3_i32) ); assert!({ diff --git a/tests/unit/out/refcount/fn_ptr_void_return.rs b/tests/unit/out/refcount/fn_ptr_void_return.rs index 316439a..69fd6b1 100644 --- a/tests/unit/out/refcount/fn_ptr_void_return.rs +++ b/tests/unit/out/refcount/fn_ptr_void_return.rs @@ -16,12 +16,12 @@ pub fn zero_out_1(x: Ptr) { let x: Value> = Rc::new(RefCell::new(x)); (*x.borrow()).write(0); } -pub fn run_2(fn_: Ptr)>, x: Ptr) { - let fn_: Value)>> = Rc::new(RefCell::new(fn_)); +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()).call_fn()(_arg0) + (*fn_.borrow()).call()(_arg0) }); } pub fn main() { @@ -30,23 +30,23 @@ pub fn main() { fn main_0() -> i32 { let a: Value = Rc::new(RefCell::new(42)); ({ - let _fn: Ptr)> = fn_ptr!(negate_0, fn(Ptr::)); + let _fn: FnPtr)> = fn_ptr!(negate_0, fn(Ptr::)); let _x: Ptr = (a.as_pointer()); run_2(_fn, _x) }); assert!(((*a.borrow()) == -42_i32)); ({ - let _fn: Ptr)> = fn_ptr!(zero_out_1, fn(Ptr::)); + let _fn: FnPtr)> = fn_ptr!(zero_out_1, fn(Ptr::)); let _x: Ptr = (a.as_pointer()); run_2(_fn, _x) }); assert!(((*a.borrow()) == 0)); - let fn_: Value)>> = Rc::new(RefCell::new(fn_ptr!(negate_0, fn(Ptr::)))); + let fn_: Value)>> = Rc::new(RefCell::new(fn_ptr!(negate_0, fn(Ptr::)))); assert!(!((*fn_.borrow()).is_null())); let b: Value = Rc::new(RefCell::new(10)); ({ let _arg0: Ptr = (b.as_pointer()); - (*fn_.borrow()).call_fn()(_arg0) + (*fn_.borrow()).call()(_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 index 3ec0683..7b94350 100644 --- a/tests/unit/out/refcount/fn_ptr_vtable.rs +++ b/tests/unit/out/refcount/fn_ptr_vtable.rs @@ -9,9 +9,9 @@ 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>, + pub create: Value AnyPtr>>, + pub get: Value i32>>, + pub destroy: Value>, } impl Clone for Vtable { fn clone(&self) -> Self { @@ -26,9 +26,9 @@ impl Clone for Vtable { impl Default for Vtable { fn default() -> Self { Vtable { - create: Rc::new(RefCell::new(Ptr::null())), - get: Rc::new(RefCell::new(Ptr::null())), - destroy: Rc::new(RefCell::new(Ptr::null())), + create: Rc::new(RefCell::new(FnPtr::null())), + get: Rc::new(RefCell::new(FnPtr::null())), + destroy: Rc::new(RefCell::new(FnPtr::null())), } } } @@ -66,21 +66,21 @@ fn main_0() -> i32 { let obj: Value = Rc::new(RefCell::new( ({ let _arg0: i32 = 42; - (*(*vt.borrow()).create.borrow()).call_fn()(_arg0) + (*(*vt.borrow()).create.borrow()).call()(_arg0) }), )); assert!( (({ let _arg0: AnyPtr = (*obj.borrow()).clone(); - (*(*vt.borrow()).get.borrow()).call_fn()(_arg0) + (*(*vt.borrow()).get.borrow()).call()(_arg0) }) == 42) ); ({ let _arg0: AnyPtr = (*obj.borrow()).clone(); - (*(*vt.borrow()).destroy.borrow()).call_fn()(_arg0) + (*(*vt.borrow()).destroy.borrow()).call()(_arg0) }); assert!(((*storage.with(Value::clone).borrow()) == 0)); - (*(*vt.borrow()).get.borrow_mut()) = Ptr::null(); + (*(*vt.borrow()).get.borrow_mut()) = FnPtr::null(); assert!((*(*vt.borrow()).get.borrow()).is_null()); return 0; } diff --git a/tests/unit/out/refcount/no_direct_callee.rs b/tests/unit/out/refcount/no_direct_callee.rs index 5bd650b..192ee3e 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_: Ptr bool>) -> i32 { - let fn_: Value bool>> = Rc::new(RefCell::new(fn_)); - if !({ (*fn_.borrow()).call_fn()() }) { +pub fn test_1(fn_: FnPtr bool>) -> i32 { + let fn_: Value bool>> = Rc::new(RefCell::new(fn_)); + if !({ (*fn_.borrow()).call()() }) { return 1; } return 0; @@ -22,7 +22,7 @@ pub fn main() { } fn main_0() -> i32 { return ({ - let _fn: Ptr bool> = fn_ptr!(test1_0, fn() -> bool); + let _fn: FnPtr bool> = fn_ptr!(test1_0, fn() -> bool); test_1(_fn) }); } From 01e9e9f0dfe2e5f53656f41ce638b24677085d2c Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 15 Apr 2026 09:55:02 +0100 Subject: [PATCH 16/35] Fix signature of fread and fwrite Also make the rules public so that generated code can reference them. --- rules/stdio/tgt_refcount.rs | 4 ++-- rules/stdio/tgt_unsafe.rs | 14 ++++++++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/rules/stdio/tgt_refcount.rs b/rules/stdio/tgt_refcount.rs index ea7174f..a36d31a 100644 --- a/rules/stdio/tgt_refcount.rs +++ b/rules/stdio/tgt_refcount.rs @@ -55,7 +55,7 @@ fn f4(a0: &mut ::std::fs::File, a1: i64, a2: i32) -> i32 { } } -fn f5(a0: AnyPtr, a1: u64, a2: u64, a3: Ptr<::std::fs::File>) -> u64 { +pub fn f5(a0: AnyPtr, a1: u64, a2: u64, a3: Ptr<::std::fs::File>) -> u64 { let total = a1.saturating_mul(a2) as usize; let mut dst = a0 .cast::() @@ -92,7 +92,7 @@ fn f5(a0: AnyPtr, a1: u64, a2: u64, a3: Ptr<::std::fs::File>) -> u64 { (read_bytes / a1 as usize) as u64 } -fn f6(a0: AnyPtr, a1: u64, a2: u64, a3: Ptr<::std::fs::File>) -> u64 { +pub fn f6(a0: AnyPtr, a1: u64, a2: u64, a3: Ptr<::std::fs::File>) -> u64 { let total = a1.saturating_mul(a2) as usize; let mut src = a0 .cast::() diff --git a/rules/stdio/tgt_unsafe.rs b/rules/stdio/tgt_unsafe.rs index adc0565..ae324d5 100644 --- a/rules/stdio/tgt_unsafe.rs +++ b/rules/stdio/tgt_unsafe.rs @@ -65,7 +65,12 @@ unsafe fn f4(a0: *mut ::std::fs::File, a1: i64, a2: i32) -> i32 { } } -unsafe fn f5(a0: *mut u8, a1: u64, a2: u64, a3: *mut ::std::fs::File) -> u64 { +pub unsafe fn f5( + a0: *mut ::libc::c_void, + a1: u64, + a2: u64, + a3: *mut ::std::fs::File, +) -> u64 { let total = a1.saturating_mul(a2) as usize; let mut dst = a0 as *mut u8; @@ -97,7 +102,12 @@ unsafe fn f5(a0: *mut u8, a1: u64, a2: u64, a3: *mut ::std::fs::File) -> u64 { (read_bytes / a1 as usize) as u64 } -unsafe fn f6(a0: *mut u8, a1: u64, a2: u64, a3: *mut ::std::fs::File) -> u64 { +pub unsafe fn f6( + a0: *const ::libc::c_void, + a1: u64, + a2: u64, + a3: *mut ::std::fs::File, +) -> u64 { let total = a1.saturating_mul(a2) as usize; let mut src = a0 as *mut u8; From e3a69afb5bad442dfe87fae0c4e9e96c4caef64a Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 15 Apr 2026 10:03:21 +0100 Subject: [PATCH 17/35] Add name and module in ExprTgt --- cpp2rust/converter/translation_rule.cpp | 4 ++++ cpp2rust/converter/translation_rule.h | 2 ++ 2 files changed, 6 insertions(+) diff --git a/cpp2rust/converter/translation_rule.cpp b/cpp2rust/converter/translation_rule.cpp index 6350a21..5f124de 100644 --- a/cpp2rust/converter/translation_rule.cpp +++ b/cpp2rust/converter/translation_rule.cpp @@ -320,6 +320,7 @@ RuleMap LoadTgtFromIR(const std::filesystem::path &json_path) { Rule rule; if (name[0] == 'f') { rule.tgt = ParseExprTgtJSON(*obj); + std::get(rule.tgt).name = name; std::get(rule.tgt).validate(json_path.string() + ":" + name); } else if (name[0] == 't') { rule.tgt = ParseTypeTgtJSON(*obj); @@ -484,6 +485,9 @@ std::vector Load(const std::filesystem::path &path, Model model) { } for (auto &[name, src_rule] : src_rules) { rules.at(name).src = std::move(src_rule.src); + if (auto *expr_tgt = std::get_if(&rules.at(name).tgt)) { + expr_tgt->module = dir.filename().string(); + } } std::vector result; diff --git a/cpp2rust/converter/translation_rule.h b/cpp2rust/converter/translation_rule.h index 566dd90..2d63c8f 100644 --- a/cpp2rust/converter/translation_rule.h +++ b/cpp2rust/converter/translation_rule.h @@ -61,6 +61,8 @@ struct TypeInfo { }; struct ExprTgt { + std::string name; + std::string module; std::unordered_map params; // "a0" -> TypeInfo TypeInfo return_type; std::unordered_map> From e30fef097e98f6ef6ad1d3527b115c78a9f6f6b4 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 15 Apr 2026 10:44:28 +0100 Subject: [PATCH 18/35] Use rule function name in AddrOf context --- cpp2rust/converter/converter.cpp | 26 ++++++++++++++++--- cpp2rust/converter/converter.h | 4 +++ .../converter/models/converter_refcount.cpp | 25 +++++++++++------- .../converter/models/converter_refcount.h | 2 ++ 4 files changed, 44 insertions(+), 13 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 1fdc402..112a26e 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -1381,6 +1381,25 @@ void Converter::EmitFnPtrCall(clang::Expr *callee) { StrCat(").unwrap()"); } +void Converter::EmitFnAsValue(const clang::FunctionDecl *fn_decl) { + StrCat(std::format("Some({} as _)", Mapper::GetFnRefName(fn_decl))); +} + +std::string Converter::GetPointeeRustType(clang::QualType ptr_type) { + auto pointee = ptr_type->getPointeeType(); + if (pointee->isIntegerType()) { + return ToString(pointee); + } + auto str = ToString(ptr_type); + while (!str.empty() && std::isspace(str.back())) { + str.pop_back(); + } + if (str.starts_with("Ptr<") && str.ends_with(">")) { + return str.substr(4, str.size() - 5); + } + return ToString(pointee); +} + void Converter::ConvertGenericCallExpr(clang::CallExpr *expr) { clang::Expr *callee = expr->getCallee(); auto convert_param_ty = [&](clang::QualType param_type, clang::Expr *expr) { @@ -2000,7 +2019,8 @@ std::string Converter::ConvertDeclRefExpr(clang::DeclRefExpr *expr) { } auto *decl = expr->getDecl(); - if (Mapper::Contains(expr)) { + if (!(clang::isa(decl) && isAddrOf()) && + Mapper::Contains(expr)) { return GetMappedAsString(expr); } else if (auto *function = decl->getAsFunction()) { if (auto method = clang::dyn_cast(function)) { @@ -2037,9 +2057,9 @@ bool Converter::VisitDeclRefExpr(clang::DeclRefExpr *expr) { return false; } - if (clang::isa(decl)) { + if (auto *fn_decl = clang::dyn_cast(decl)) { if (isAddrOf()) { - StrCat(std::format("Some({} as _)", str)); + EmitFnAsValue(fn_decl); return false; } } diff --git a/cpp2rust/converter/converter.h b/cpp2rust/converter/converter.h index faf340c..7494a99 100644 --- a/cpp2rust/converter/converter.h +++ b/cpp2rust/converter/converter.h @@ -201,6 +201,10 @@ class Converter : public clang::RecursiveASTVisitor { virtual void EmitFnPtrCall(clang::Expr *callee); + virtual void EmitFnAsValue(const clang::FunctionDecl *fn_decl); + + std::string GetPointeeRustType(clang::QualType ptr_type); + virtual void ConvertPrintf(clang::CallExpr *expr); void ConvertVAArgCall(clang::CallExpr *expr); diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index 19b2fdf..b11e159 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -192,7 +192,7 @@ std::string ConverterRefCount::BuildFnAdapter( closure += "{ "; // Build adapter body: src_fn(convert(a0), convert(a1), ...) - closure += GetNamedDeclAsString(src_fn->getCanonicalDecl()) + "("; + closure += Mapper::GetFnRefName(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); @@ -200,7 +200,7 @@ std::string ConverterRefCount::BuildFnAdapter( closure += std::format("a{}", i); } else if (src_pty->isPointerType() && tgt_pty->isVoidPointerType()) { closure += std::format("a{}.cast::<{}>().unwrap()", i, - ToString(src_pty->getPointeeType())); + GetPointeeRustType(src_pty)); } else if (src_pty->isVoidPointerType() && tgt_pty->isPointerType()) { closure += std::format("a{}.to_any()", i); } else { @@ -622,19 +622,18 @@ bool ConverterRefCount::VisitDeclRefExpr(clang::DeclRefExpr *expr) { } } - if (Mapper::Contains(expr)) { + auto str = ConvertDeclRefExpr(expr); + auto decl = expr->getDecl(); + + if (!(clang::isa(decl) && isAddrOf()) && + Mapper::Contains(expr)) { StrCat(GetMappedAsString(expr)); return false; } - auto str = ConvertDeclRefExpr(expr); - auto decl = expr->getDecl(); - - if (clang::isa(decl)) { + if (auto *fn_decl = clang::dyn_cast(decl)) { if (isAddrOf()) { - auto proto = decl->getType()->getAs(); - auto fn_type = GetFnTypeString(proto); - StrCat(std::format("fn_ptr!({}, {})", str, fn_type)); + EmitFnAsValue(fn_decl); } else { StrCat(str); } @@ -1030,6 +1029,12 @@ void ConverterRefCount::EmitFnPtrCall(clang::Expr *callee) { StrCat(".call()"); } +void ConverterRefCount::EmitFnAsValue(const clang::FunctionDecl *fn_decl) { + StrCat(std::format( + "fn_ptr!({}, {})", Mapper::GetFnRefName(fn_decl), + GetFnTypeString(fn_decl->getType()->getAs()))); +} + std::string ConverterRefCount::GetFunctionPointerDefaultAsString( clang::QualType qual_type) { return "FnPtr::null()"; diff --git a/cpp2rust/converter/models/converter_refcount.h b/cpp2rust/converter/models/converter_refcount.h index cc9cc6e..cb9f3d8 100644 --- a/cpp2rust/converter/models/converter_refcount.h +++ b/cpp2rust/converter/models/converter_refcount.h @@ -61,6 +61,8 @@ class ConverterRefCount final : public Converter { void EmitFnPtrCall(clang::Expr *callee) override; + void EmitFnAsValue(const clang::FunctionDecl *fn_decl) override; + bool VisitCallExpr(clang::CallExpr *expr) override; bool VisitStringLiteral(clang::StringLiteral *expr) override; From 133e94f0af66c648bbcf05a3c8138a64d458bb02 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 15 Apr 2026 11:07:30 +0100 Subject: [PATCH 19/35] Check name and module are never empty --- cpp2rust/converter/translation_rule.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cpp2rust/converter/translation_rule.cpp b/cpp2rust/converter/translation_rule.cpp index 5f124de..2adaa07 100644 --- a/cpp2rust/converter/translation_rule.cpp +++ b/cpp2rust/converter/translation_rule.cpp @@ -321,7 +321,6 @@ RuleMap LoadTgtFromIR(const std::filesystem::path &json_path) { if (name[0] == 'f') { rule.tgt = ParseExprTgtJSON(*obj); std::get(rule.tgt).name = name; - std::get(rule.tgt).validate(json_path.string() + ":" + name); } else if (name[0] == 't') { rule.tgt = ParseTypeTgtJSON(*obj); } else { @@ -463,6 +462,8 @@ void ExprTgt::validate(const std::string &context) const { ValidateConsecutiveKeys(params, 'a', 0, context + " params"); ValidateConsecutiveKeys(generics, 'T', 1, context + " generics"); assert(!body.empty() && "ExprTgt body must not be empty"); + assert(!name.empty() && "ExprTgt name must not be empty"); + assert(!module.empty() && "ExprTgt module must not be empty"); } std::vector Load(const std::filesystem::path &path, Model model) { @@ -493,6 +494,9 @@ std::vector Load(const std::filesystem::path &path, Model model) { std::vector result; for (auto &[name, rule] : rules) { assert(!rule.src.empty() && "Rule loaded from IR but has no src"); + if (auto *expr_tgt = std::get_if(&rule.tgt)) { + expr_tgt->validate(path.string() + ":" + name); + } result.push_back(std::move(rule)); } return result; From 25b203fcfd6dbef25d8a788d4d8bba35bffe64c6 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 15 Apr 2026 11:12:54 +0100 Subject: [PATCH 20/35] Get fully qualified name of translation rule --- cpp2rust/converter/mapper.cpp | 27 +++++++++++++++++++++++++++ cpp2rust/converter/mapper.h | 1 + 2 files changed, 28 insertions(+) diff --git a/cpp2rust/converter/mapper.cpp b/cpp2rust/converter/mapper.cpp index 478e3c5..8ba1d59 100644 --- a/cpp2rust/converter/mapper.cpp +++ b/cpp2rust/converter/mapper.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -560,6 +561,17 @@ std::string normalizeTranslationRule(std::string rule) { return rule; } +std::string GetRulePathForFunction(const clang::FunctionDecl *decl, + const std::string &model_suffix) { + assert(decl); + auto it = exprs_.find(ToString(decl)); + if (it == exprs_.end()) { + return ""; + } + auto &tgt = it->second; + return std::format("rules::{}_{}::{}", tgt.module, model_suffix, tgt.name); +} + } // namespace bool Contains(clang::QualType qual_type) { @@ -575,6 +587,21 @@ const TranslationRule::ExprTgt *GetExprTgt(const clang::Expr *expr) { return nullptr; } +std::string GetFnRefName(const clang::FunctionDecl *decl) { + assert(decl); + if (model_ == Model::kRefCount) { + auto refcount_path = GetRulePathForFunction(decl, "tgt_refcount"); + if (!refcount_path.empty()) { + return refcount_path; + } + } + auto unsafe_path = GetRulePathForFunction(decl, "tgt_unsafe"); + if (!unsafe_path.empty()) { + return unsafe_path; + } + return GetNamedDeclAsString(decl->getCanonicalDecl()); +} + std::string InstantiateTemplate(const clang::Expr *expr, const std::string &text) { auto it = search(expr); diff --git a/cpp2rust/converter/mapper.h b/cpp2rust/converter/mapper.h index 14de180..c8ed73f 100644 --- a/cpp2rust/converter/mapper.h +++ b/cpp2rust/converter/mapper.h @@ -19,6 +19,7 @@ bool Contains(const clang::Expr *expr); std::string Map(clang::QualType qual_type); const TranslationRule::ExprTgt *GetExprTgt(const clang::Expr *expr); +std::string GetFnRefName(const clang::FunctionDecl *decl); std::string InstantiateTemplate(const clang::Expr *expr, const std::string &text); bool ReturnsPointer(const clang::Expr *expr); From 9cfda12bee003327cb7be379d98a29614e8308ff Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 15 Apr 2026 11:13:48 +0100 Subject: [PATCH 21/35] Update output of fn_ptr_stdlib_compare --- tests/unit/fn_ptr_stdlib_compare.cpp | 22 ++------- .../out/refcount/fn_ptr_stdlib_compare.rs | 49 +++++++++++++++++++ .../unit/out/unsafe/fn_ptr_stdlib_compare.rs | 33 +++++++++++++ 3 files changed, 86 insertions(+), 18 deletions(-) create mode 100644 tests/unit/out/refcount/fn_ptr_stdlib_compare.rs create mode 100644 tests/unit/out/unsafe/fn_ptr_stdlib_compare.rs diff --git a/tests/unit/fn_ptr_stdlib_compare.cpp b/tests/unit/fn_ptr_stdlib_compare.cpp index e2ca1c3..a71581c 100644 --- a/tests/unit/fn_ptr_stdlib_compare.cpp +++ b/tests/unit/fn_ptr_stdlib_compare.cpp @@ -3,30 +3,16 @@ #include typedef size_t (*read_fn)(void *, size_t, size_t, FILE *); -typedef void (*free_fn)(void *); -typedef void *(*malloc_fn)(size_t); + +typedef size_t (*read_alternative_fn)(char *, size_t, size_t, void *); int main() { read_fn rfn = fread; assert(rfn == fread); assert(rfn != nullptr); - free_fn ffn = free; - assert(ffn == free); - assert(ffn != nullptr); - - malloc_fn mfn = malloc; - assert(mfn == malloc); - assert(mfn != nullptr); - - // Reassign and compare - read_fn rfn2 = fread; - assert(rfn == rfn2); - - free_fn ffn2 = nullptr; - assert(ffn != ffn2); - ffn2 = free; - assert(ffn == ffn2); + read_alternative_fn rfn2 = (read_alternative_fn)fread; + assert(rfn == (read_fn)rfn2); return 0; } diff --git a/tests/unit/out/refcount/fn_ptr_stdlib_compare.rs b/tests/unit/out/refcount/fn_ptr_stdlib_compare.rs new file mode 100644 index 0000000..5c10309 --- /dev/null +++ b/tests/unit/out/refcount/fn_ptr_stdlib_compare.rs @@ -0,0 +1,49 @@ +extern crate libcc2rs; +use libcc2rs::*; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::io::prelude::*; +use std::io::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 rfn: Value) -> u64>> = + Rc::new(RefCell::new(fn_ptr!( + rules::stdio_tgt_refcount::f5, + fn(AnyPtr, u64, u64, Ptr<::std::fs::File>) -> u64 + ))); + assert!({ + let _lhs = (*rfn.borrow()).clone(); + _lhs == fn_ptr!( + rules::stdio_tgt_refcount::f5, + fn(AnyPtr, u64, u64, Ptr<::std::fs::File>) -> u64 + ) + }); + assert!(!((*rfn.borrow()).is_null())); + let rfn2: Value, u64, u64, AnyPtr) -> u64>> = Rc::new(RefCell::new( + fn_ptr!( + rules::stdio_tgt_refcount::f5, + fn(AnyPtr, u64, u64, Ptr<::std::fs::File>) -> u64 + ) + .cast::, u64, u64, AnyPtr) -> u64>(Some( + (|a0: Ptr, a1: u64, a2: u64, a3: AnyPtr| -> u64 { + rules::stdio_tgt_refcount::f5( + a0.to_any(), + a1, + a2, + a3.cast::<::std::fs::File>().unwrap(), + ) + }) as fn(Ptr, u64, u64, AnyPtr) -> u64, + )), + )); + assert!({ + let _lhs = (*rfn.borrow()).clone(); + _lhs == ((*rfn2.borrow()).cast::) -> u64>(None)) + .clone() + }); + return 0; +} diff --git a/tests/unit/out/unsafe/fn_ptr_stdlib_compare.rs b/tests/unit/out/unsafe/fn_ptr_stdlib_compare.rs new file mode 100644 index 0000000..cf09b6b --- /dev/null +++ b/tests/unit/out/unsafe/fn_ptr_stdlib_compare.rs @@ -0,0 +1,33 @@ +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 rfn: Option u64> = + Some(rules::stdio_tgt_unsafe::f5 as _); + assert!(((rfn) == (Some(rules::stdio_tgt_unsafe::f5 as _)))); + assert!(!((rfn).is_none())); + let mut rfn2: Option u64> = + std::mem::transmute::< + Option u64>, + Option u64>, + >(Some(rules::stdio_tgt_unsafe::f5 as _)); + assert!( + ((rfn) + == (std::mem::transmute::< + Option u64>, + Option u64>, + >(rfn2))) + ); + return 0; +} From 06b73fdfab9c536df076be2a2074b11bf1eb72ca Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 15 Apr 2026 11:45:44 +0100 Subject: [PATCH 22/35] Change to deafult with suffix --- cpp2rust/converter/converter.cpp | 4 ++-- tests/benchmarks/out/unsafe/bfs.rs | 6 +++--- tests/ub/out/unsafe/ub10.rs | 2 +- tests/ub/out/unsafe/ub14.rs | 2 +- tests/ub/out/unsafe/ub15.rs | 2 +- tests/ub/out/unsafe/ub16.rs | 2 +- tests/ub/out/unsafe/ub20.rs | 2 +- tests/ub/out/unsafe/ub9.rs | 2 +- tests/unit/out/unsafe/06_new_array.rs | 3 +-- tests/unit/out/unsafe/clone_vs_move.rs | 4 ++-- tests/unit/out/unsafe/default.rs | 2 +- tests/unit/out/unsafe/fn_ptr_struct.rs | 2 +- tests/unit/out/unsafe/fn_ptr_vtable.rs | 2 +- tests/unit/out/unsafe/init.rs | 2 +- tests/unit/out/unsafe/init_list.rs | 4 ++-- tests/unit/out/unsafe/memset.rs | 2 +- tests/unit/out/unsafe/new_alloc_array.rs | 2 +- tests/unit/out/unsafe/new_array.rs | 2 +- tests/unit/out/unsafe/new_array_var_size.rs | 10 +++------- tests/unit/out/unsafe/pointer_call_offset.rs | 2 +- tests/unit/out/unsafe/random.rs | 6 +++--- tests/unit/out/unsafe/reinterpret_cast_large_array.rs | 2 +- tests/unit/out/unsafe/reinterpret_cast_new_array.rs | 2 +- tests/unit/out/unsafe/stdcopy.rs | 2 +- tests/unit/out/unsafe/swap_extended.rs | 2 +- tests/unit/out/unsafe/unique_ptr.rs | 4 ++-- tests/unit/out/unsafe/vector2.rs | 2 +- 27 files changed, 37 insertions(+), 42 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 112a26e..8586ffa 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -2733,11 +2733,11 @@ std::string Converter::GetDefaultAsStringFallback(clang::QualType qual_type) { } if (qual_type->isIntegerType()) { - return std::format("0 as {}", ToString(qual_type)); + return std::format("0_{}", ToString(qual_type)); } if (qual_type->isFloatingType()) { - return std::format("0.0 as {}", ToString(qual_type)); + return std::format("0.0_{}", ToString(qual_type)); } return std::format("<{}>::default()", ToString(qual_type)); diff --git a/tests/benchmarks/out/unsafe/bfs.rs b/tests/benchmarks/out/unsafe/bfs.rs index ae9be6f..3a114e2 100644 --- a/tests/benchmarks/out/unsafe/bfs.rs +++ b/tests/benchmarks/out/unsafe/bfs.rs @@ -62,7 +62,7 @@ pub unsafe fn BFS_0(graph: *const Graph, mut start_vertex: u32) -> *mut u32 { let mut Q: Queue = Queue { elems: Box::leak( (0..((*graph).V as u64)) - .map(|_| ::default()) + .map(|_| 0 as u32) .collect::>(), ) .as_mut_ptr(), @@ -72,13 +72,13 @@ pub unsafe fn BFS_0(graph: *const Graph, mut start_vertex: u32) -> *mut u32 { }; let mut visited: *mut bool = Box::leak( (0..((*graph).V as u64)) - .map(|_| ::default()) + .map(|_| false) .collect::>(), ) .as_mut_ptr(); let mut pred: *mut u32 = Box::leak( (0..((*graph).V as u64)) - .map(|_| ::default()) + .map(|_| 0 as u32) .collect::>(), ) .as_mut_ptr(); diff --git a/tests/ub/out/unsafe/ub10.rs b/tests/ub/out/unsafe/ub10.rs index e60c673..f684d12 100644 --- a/tests/ub/out/unsafe/ub10.rs +++ b/tests/ub/out/unsafe/ub10.rs @@ -14,7 +14,7 @@ pub fn main() { } unsafe fn main_0() -> i32 { let mut arr: *mut i32 = - Box::leak((0..10_u64).map(|_| 0 as i32).collect::>()).as_mut_ptr(); + Box::leak((0..10_u64).map(|_| 0_i32).collect::>()).as_mut_ptr(); let mut ptr: *mut i32 = arr.offset((1) as isize); let mut out: i32 = (*ptr); diff --git a/tests/ub/out/unsafe/ub14.rs b/tests/ub/out/unsafe/ub14.rs index 7a21361..61c8958 100644 --- a/tests/ub/out/unsafe/ub14.rs +++ b/tests/ub/out/unsafe/ub14.rs @@ -14,7 +14,7 @@ pub fn main() { } unsafe fn main_0() -> i32 { let mut arr1: *mut i32 = - Box::leak((0..100_u64).map(|_| 0 as i32).collect::>()).as_mut_ptr(); + Box::leak((0..100_u64).map(|_| 0_i32).collect::>()).as_mut_ptr(); (*arr1.offset((100) as isize)) = 1; ::std::mem::drop(Box::from_raw(::std::slice::from_raw_parts_mut( diff --git a/tests/ub/out/unsafe/ub15.rs b/tests/ub/out/unsafe/ub15.rs index b7ed844..669d188 100644 --- a/tests/ub/out/unsafe/ub15.rs +++ b/tests/ub/out/unsafe/ub15.rs @@ -14,7 +14,7 @@ pub fn main() { } unsafe fn main_0() -> i32 { let mut arr: *mut i32 = - Box::leak((0..15_u64).map(|_| 0 as i32).collect::>()).as_mut_ptr(); + Box::leak((0..15_u64).map(|_| 0_i32).collect::>()).as_mut_ptr(); let mut ptr: *mut i32 = arr.offset((15) as isize); let mut out: i32 = (*ptr); diff --git a/tests/ub/out/unsafe/ub16.rs b/tests/ub/out/unsafe/ub16.rs index b558d41..a4c801e 100644 --- a/tests/ub/out/unsafe/ub16.rs +++ b/tests/ub/out/unsafe/ub16.rs @@ -17,7 +17,7 @@ pub fn main() { } unsafe fn main_0() -> i32 { let mut p1: *mut i32 = - Box::leak((0..10_u64).map(|_| 0 as i32).collect::>()).as_mut_ptr(); + Box::leak((0..10_u64).map(|_| 0_i32).collect::>()).as_mut_ptr(); let mut out: i32 = (*(unsafe { let _a: *mut i32 = (&mut (*p1.offset((1) as isize)) as *mut i32); foo_0(_a) diff --git a/tests/ub/out/unsafe/ub20.rs b/tests/ub/out/unsafe/ub20.rs index b57376f..053b353 100644 --- a/tests/ub/out/unsafe/ub20.rs +++ b/tests/ub/out/unsafe/ub20.rs @@ -17,7 +17,7 @@ pub fn main() { } unsafe fn main_0() -> i32 { let mut x: *mut i32 = - Box::leak((0..10_u64).map(|_| 0 as i32).collect::>()).as_mut_ptr(); + Box::leak((0..10_u64).map(|_| 0_i32).collect::>()).as_mut_ptr(); (unsafe { let _single: *mut i32 = x; foo_0(_single) diff --git a/tests/ub/out/unsafe/ub9.rs b/tests/ub/out/unsafe/ub9.rs index f8206b7..8f57418 100644 --- a/tests/ub/out/unsafe/ub9.rs +++ b/tests/ub/out/unsafe/ub9.rs @@ -14,7 +14,7 @@ pub fn main() { } unsafe fn main_0() -> i32 { let mut arr: *mut i32 = - Box::leak((0..10_u64).map(|_| 0 as i32).collect::>()).as_mut_ptr(); + Box::leak((0..10_u64).map(|_| 0_i32).collect::>()).as_mut_ptr(); let mut out: i32 = (*arr.offset((10) as isize)); ::std::mem::drop(Box::from_raw(::std::slice::from_raw_parts_mut( diff --git a/tests/unit/out/unsafe/06_new_array.rs b/tests/unit/out/unsafe/06_new_array.rs index fdc11d3..d7bb799 100644 --- a/tests/unit/out/unsafe/06_new_array.rs +++ b/tests/unit/out/unsafe/06_new_array.rs @@ -13,8 +13,7 @@ pub fn main() { } } unsafe fn main_0() -> i32 { - let mut e: *mut i32 = - Box::leak((0..2_u64).map(|_| 0 as i32).collect::>()).as_mut_ptr(); + let mut e: *mut i32 = Box::leak((0..2_u64).map(|_| 0_i32).collect::>()).as_mut_ptr(); (*e.offset((0) as isize)) = 6; (*e.offset((1) as isize)) = 7; diff --git a/tests/unit/out/unsafe/clone_vs_move.rs b/tests/unit/out/unsafe/clone_vs_move.rs index 065ba07..d0fcde2 100644 --- a/tests/unit/out/unsafe/clone_vs_move.rs +++ b/tests/unit/out/unsafe/clone_vs_move.rs @@ -22,10 +22,10 @@ pub struct Foo { impl Default for Foo { fn default() -> Self { Foo { - x: 0 as i32, + x: 0_i32, y: <*mut i32>::default(), z: Default::default(), - a: [0 as i32; 3], + a: [0_i32; 3], bar: ::default(), } } diff --git a/tests/unit/out/unsafe/default.rs b/tests/unit/out/unsafe/default.rs index 990bf33..952ccd8 100644 --- a/tests/unit/out/unsafe/default.rs +++ b/tests/unit/out/unsafe/default.rs @@ -22,7 +22,7 @@ impl Default for Pointers { x2: Default::default(), x3: [Default::default(); 5], x4: [Default::default(); 10], - x5: 0 as i32, + x5: 0_i32, } } } diff --git a/tests/unit/out/unsafe/fn_ptr_struct.rs b/tests/unit/out/unsafe/fn_ptr_struct.rs index fc5a107..277b226 100644 --- a/tests/unit/out/unsafe/fn_ptr_struct.rs +++ b/tests/unit/out/unsafe/fn_ptr_struct.rs @@ -15,7 +15,7 @@ pub struct Handler { impl Default for Handler { fn default() -> Self { Handler { - tag: 0 as i32, + tag: 0_i32, cb: None, } } diff --git a/tests/unit/out/unsafe/fn_ptr_vtable.rs b/tests/unit/out/unsafe/fn_ptr_vtable.rs index 677cceb..9829808 100644 --- a/tests/unit/out/unsafe/fn_ptr_vtable.rs +++ b/tests/unit/out/unsafe/fn_ptr_vtable.rs @@ -22,7 +22,7 @@ impl Default for Vtable { } } } -pub static mut storage: i32 = 0 as i32; +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); diff --git a/tests/unit/out/unsafe/init.rs b/tests/unit/out/unsafe/init.rs index e767538..5e61576 100644 --- a/tests/unit/out/unsafe/init.rs +++ b/tests/unit/out/unsafe/init.rs @@ -20,7 +20,7 @@ pub fn main() { } } unsafe fn main_0() -> i32 { - let mut x: i32 = 0 as i32; + let mut x: i32 = 0_i32; let mut p: *mut i32 = Default::default(); let g: *mut i32 = &mut x as *mut i32; let mut q: *mut i32 = (&mut x as *mut i32); diff --git a/tests/unit/out/unsafe/init_list.rs b/tests/unit/out/unsafe/init_list.rs index 1d5e27e..1f6a2b5 100644 --- a/tests/unit/out/unsafe/init_list.rs +++ b/tests/unit/out/unsafe/init_list.rs @@ -15,9 +15,9 @@ pub fn main() { } unsafe fn main_0() -> i32 { let mut i1: i32 = 3; - let mut i2: i32 = 0 as i32; + let mut i2: i32 = 0_i32; let mut carr1: [i32; 2] = [1, 2]; - let mut carr2: [i32; 3] = [1, 0 as i32, 0 as i32]; + let mut carr2: [i32; 3] = [1, 0_i32, 0_i32]; let mut arr: Vec = vec![1, 2, 3]; let mut vec_: Vec = vec![1, 2, 3]; (unsafe { diff --git a/tests/unit/out/unsafe/memset.rs b/tests/unit/out/unsafe/memset.rs index 26eb5e6..284f976 100644 --- a/tests/unit/out/unsafe/memset.rs +++ b/tests/unit/out/unsafe/memset.rs @@ -15,7 +15,7 @@ pub fn main() { unsafe fn main_0() -> i32 { let N: i32 = 3; let mut arr: *mut i32 = - Box::leak((0..(N as u64)).map(|_| 0 as i32).collect::>()).as_mut_ptr(); + Box::leak((0..(N as u64)).map(|_| 0_i32).collect::>()).as_mut_ptr(); { let byte_0 = (arr as *mut i32 as *mut ::libc::c_void) as *mut u8; for offset in 0..(::std::mem::size_of::() as u64 as u64).wrapping_mul((N as u64)) { diff --git a/tests/unit/out/unsafe/new_alloc_array.rs b/tests/unit/out/unsafe/new_alloc_array.rs index 5a83f05..1814e52 100644 --- a/tests/unit/out/unsafe/new_alloc_array.rs +++ b/tests/unit/out/unsafe/new_alloc_array.rs @@ -14,7 +14,7 @@ pub fn main() { } unsafe fn main_0() -> i32 { let mut array: *mut i32 = - Box::leak((0..100_u64).map(|_| 0 as i32).collect::>()).as_mut_ptr(); + Box::leak((0..100_u64).map(|_| 0_i32).collect::>()).as_mut_ptr(); { let byte_0 = (array as *mut i32 as *mut ::libc::c_void) as *mut u8; for offset in 0..(::std::mem::size_of::() as u64 as u64).wrapping_mul(100_u64) { diff --git a/tests/unit/out/unsafe/new_array.rs b/tests/unit/out/unsafe/new_array.rs index b73aea8..514fc12 100644 --- a/tests/unit/out/unsafe/new_array.rs +++ b/tests/unit/out/unsafe/new_array.rs @@ -14,7 +14,7 @@ pub fn main() { } unsafe fn main_0() -> i32 { let mut array: *mut i32 = - Box::leak((0..100_u64).map(|_| 0 as i32).collect::>()).as_mut_ptr(); + Box::leak((0..100_u64).map(|_| 0_i32).collect::>()).as_mut_ptr(); ::std::mem::drop(Box::from_raw(::std::slice::from_raw_parts_mut( array, diff --git a/tests/unit/out/unsafe/new_array_var_size.rs b/tests/unit/out/unsafe/new_array_var_size.rs index ff403a2..f9be614 100644 --- a/tests/unit/out/unsafe/new_array_var_size.rs +++ b/tests/unit/out/unsafe/new_array_var_size.rs @@ -15,19 +15,15 @@ pub fn main() { unsafe fn main_0() -> i32 { let mut N: i32 = 5; let mut A: *mut i32 = - Box::leak((0..(N as u64)).map(|_| 0 as i32).collect::>()).as_mut_ptr(); + Box::leak((0..(N as u64)).map(|_| 0_i32).collect::>()).as_mut_ptr(); ::std::mem::drop(Box::from_raw(::std::slice::from_raw_parts_mut( A, libcc2rs::malloc_usable_size(A as *mut ::libc::c_void) / ::std::mem::size_of::(), ))); let N2: *mut i32 = &mut N as *mut i32; - let mut A2: *mut i32 = Box::leak( - (0..((*N2) as u64)) - .map(|_| 0 as i32) - .collect::>(), - ) - .as_mut_ptr(); + let mut A2: *mut i32 = + Box::leak((0..((*N2) as u64)).map(|_| 0_i32).collect::>()).as_mut_ptr(); ::std::mem::drop(Box::from_raw(::std::slice::from_raw_parts_mut( A2, diff --git a/tests/unit/out/unsafe/pointer_call_offset.rs b/tests/unit/out/unsafe/pointer_call_offset.rs index 8d9472e..76f2a3d 100644 --- a/tests/unit/out/unsafe/pointer_call_offset.rs +++ b/tests/unit/out/unsafe/pointer_call_offset.rs @@ -17,7 +17,7 @@ pub fn main() { } unsafe fn main_0() -> i32 { let mut p1: *mut i32 = - Box::leak((0..10_u64).map(|_| 0 as i32).collect::>()).as_mut_ptr(); + Box::leak((0..10_u64).map(|_| 0_i32).collect::>()).as_mut_ptr(); let mut i: u32 = 0_u32; 'loop_: while ((i) < (10_u32)) { (*p1.offset((i) as isize)) = (i as i32); diff --git a/tests/unit/out/unsafe/random.rs b/tests/unit/out/unsafe/random.rs index 82133af..05efa2b 100644 --- a/tests/unit/out/unsafe/random.rs +++ b/tests/unit/out/unsafe/random.rs @@ -40,9 +40,9 @@ impl Pair { impl Default for Pair { fn default() -> Self { Pair { - x: 0 as i32, - y: 0 as i32, - a: [0 as i32; 5], + x: 0_i32, + y: 0_i32, + a: [0_i32; 5], r: <*mut i32>::default(), p: Default::default(), pair: Default::default(), diff --git a/tests/unit/out/unsafe/reinterpret_cast_large_array.rs b/tests/unit/out/unsafe/reinterpret_cast_large_array.rs index 5344c2b..d3e0fd8 100644 --- a/tests/unit/out/unsafe/reinterpret_cast_large_array.rs +++ b/tests/unit/out/unsafe/reinterpret_cast_large_array.rs @@ -15,7 +15,7 @@ pub fn main() { unsafe fn main_0() -> i32 { let N: i32 = 10000; let mut arr: *mut u32 = - Box::leak((0..(N as u64)).map(|_| 0 as u32).collect::>()).as_mut_ptr(); + Box::leak((0..(N as u64)).map(|_| 0_u32).collect::>()).as_mut_ptr(); let mut i: i32 = 0; 'loop_: while ((i) < (N)) { (*arr.offset((i) as isize)) = 0_u32; diff --git a/tests/unit/out/unsafe/reinterpret_cast_new_array.rs b/tests/unit/out/unsafe/reinterpret_cast_new_array.rs index f4e567b..3a71d5b 100644 --- a/tests/unit/out/unsafe/reinterpret_cast_new_array.rs +++ b/tests/unit/out/unsafe/reinterpret_cast_new_array.rs @@ -14,7 +14,7 @@ pub fn main() { } unsafe fn main_0() -> i32 { let mut arr: *mut u32 = - Box::leak((0..2_u64).map(|_| 0 as u32).collect::>()).as_mut_ptr(); + Box::leak((0..2_u64).map(|_| 0_u32).collect::>()).as_mut_ptr(); (*arr.offset((0) as isize)) = 67305985_u32; (*arr.offset((1) as isize)) = 134678021_u32; let mut bytes: *mut u8 = (arr as *mut u8); diff --git a/tests/unit/out/unsafe/stdcopy.rs b/tests/unit/out/unsafe/stdcopy.rs index 706e5fb..15c5809 100644 --- a/tests/unit/out/unsafe/stdcopy.rs +++ b/tests/unit/out/unsafe/stdcopy.rs @@ -14,7 +14,7 @@ pub fn main() { } unsafe fn main_0() -> i32 { let mut input: [i32; 3] = [1, 2, 3]; - let mut output: [i32; 3] = [0 as i32; 3]; + let mut output: [i32; 3] = [0_i32; 3]; { let mut outptr = output.as_mut_ptr().clone(); let mut curr = input.as_mut_ptr().clone(); diff --git a/tests/unit/out/unsafe/swap_extended.rs b/tests/unit/out/unsafe/swap_extended.rs index 8aae96c..d1e3a3b 100644 --- a/tests/unit/out/unsafe/swap_extended.rs +++ b/tests/unit/out/unsafe/swap_extended.rs @@ -94,7 +94,7 @@ unsafe fn main_0() -> i32 { (*h), ); ::std::mem::drop(Box::from_raw(h)); - let mut i: *mut i32 = Box::leak(Box::new([7, 8, 0 as i32])).as_mut_ptr(); + let mut i: *mut i32 = Box::leak(Box::new([7, 8, 0_i32])).as_mut_ptr(); write!( std::fs::File::from_raw_fd( std::io::stdout() diff --git a/tests/unit/out/unsafe/unique_ptr.rs b/tests/unit/out/unsafe/unique_ptr.rs index a94bb75..73a1a4b 100644 --- a/tests/unit/out/unsafe/unique_ptr.rs +++ b/tests/unit/out/unsafe/unique_ptr.rs @@ -72,7 +72,7 @@ pub unsafe fn Consume_1(mut safe_ptr: Option>) -> i32 { pub unsafe fn RndStuff_2() { let mut x1: Option> = None; let mut x2: Option> = Some(Box::from_raw(Box::leak( - (0..100_u64).map(|_| 0 as i32).collect::>(), + (0..100_u64).map(|_| 0_i32).collect::>(), ))); let mut i: i32 = 0; 'loop_: while ((i) < (100)) { @@ -80,7 +80,7 @@ pub unsafe fn RndStuff_2() { i.prefix_inc(); } x2 = Some(Box::from_raw(Box::leak( - (0..200_u64).map(|_| 0 as i32).collect::>(), + (0..200_u64).map(|_| 0_i32).collect::>(), ))); let mut i: i32 = 0; 'loop_: while ((i) < (200)) { diff --git a/tests/unit/out/unsafe/vector2.rs b/tests/unit/out/unsafe/vector2.rs index 640b762..dd5b4d4 100644 --- a/tests/unit/out/unsafe/vector2.rs +++ b/tests/unit/out/unsafe/vector2.rs @@ -9,7 +9,7 @@ use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; use std::rc::Rc; pub unsafe fn fn_0(v: *mut Vec, mut v3: Vec) { (*v).push(20); - let mut x: i32 = 0 as i32; + let mut x: i32 = 0_i32; let mut v2: Vec = Vec::new(); let mut v4: *mut Vec = (&mut v3 as *mut Vec); v2.push(0); From 942bde3faddc1d0a0285bc76983ae833fccc237f Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 15 Apr 2026 11:45:54 +0100 Subject: [PATCH 23/35] Make rules public --- rules/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/rules/src/lib.rs b/rules/src/lib.rs index 9efa064..44df340 100644 --- a/rules/src/lib.rs +++ b/rules/src/lib.rs @@ -3,3 +3,4 @@ #![allow(warnings)] mod modules; +pub use modules::*; From 03e7ab77396bad0563c853f245e4f16e1682245c Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 15 Apr 2026 11:46:04 +0100 Subject: [PATCH 24/35] cargo-fmt --- rules/stdio/tgt_unsafe.rs | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/rules/stdio/tgt_unsafe.rs b/rules/stdio/tgt_unsafe.rs index ae324d5..d0bf882 100644 --- a/rules/stdio/tgt_unsafe.rs +++ b/rules/stdio/tgt_unsafe.rs @@ -65,12 +65,7 @@ unsafe fn f4(a0: *mut ::std::fs::File, a1: i64, a2: i32) -> i32 { } } -pub unsafe fn f5( - a0: *mut ::libc::c_void, - a1: u64, - a2: u64, - a3: *mut ::std::fs::File, -) -> u64 { +pub unsafe fn f5(a0: *mut ::libc::c_void, a1: u64, a2: u64, a3: *mut ::std::fs::File) -> u64 { let total = a1.saturating_mul(a2) as usize; let mut dst = a0 as *mut u8; @@ -102,12 +97,7 @@ pub unsafe fn f5( (read_bytes / a1 as usize) as u64 } -pub unsafe fn f6( - a0: *const ::libc::c_void, - a1: u64, - a2: u64, - a3: *mut ::std::fs::File, -) -> u64 { +pub unsafe fn f6(a0: *const ::libc::c_void, a1: u64, a2: u64, a3: *mut ::std::fs::File) -> u64 { let total = a1.saturating_mul(a2) as usize; let mut src = a0 as *mut u8; From a2e1c1a93f05f56fb7fcc12e4a34211db359882d Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 15 Apr 2026 11:49:58 +0100 Subject: [PATCH 25/35] Delete unused Cargo.toml --- tests/benchmarks/out/unsafe/bfs.rs | 4 ++-- tests/unit/Cargo.toml | 14 -------------- 2 files changed, 2 insertions(+), 16 deletions(-) delete mode 100644 tests/unit/Cargo.toml diff --git a/tests/benchmarks/out/unsafe/bfs.rs b/tests/benchmarks/out/unsafe/bfs.rs index 3a114e2..956d754 100644 --- a/tests/benchmarks/out/unsafe/bfs.rs +++ b/tests/benchmarks/out/unsafe/bfs.rs @@ -62,7 +62,7 @@ pub unsafe fn BFS_0(graph: *const Graph, mut start_vertex: u32) -> *mut u32 { let mut Q: Queue = Queue { elems: Box::leak( (0..((*graph).V as u64)) - .map(|_| 0 as u32) + .map(|_| 0_u32) .collect::>(), ) .as_mut_ptr(), @@ -78,7 +78,7 @@ pub unsafe fn BFS_0(graph: *const Graph, mut start_vertex: u32) -> *mut u32 { .as_mut_ptr(); let mut pred: *mut u32 = Box::leak( (0..((*graph).V as u64)) - .map(|_| 0 as u32) + .map(|_| 0_u32) .collect::>(), ) .as_mut_ptr(); diff --git a/tests/unit/Cargo.toml b/tests/unit/Cargo.toml deleted file mode 100644 index a8618fe..0000000 --- a/tests/unit/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -name = "rs" -version = "0.1.0" -edition = "2021" - -[dependencies] -libc = "0.2.153" -libcc2rs = { path = "../../../libcc2rs" } - -# Any project that uses rust-analyzer with the rustc_private -# crates must set [package.metadata.rust-analyzer] rustc_private=true to use it. - -[package.metadata.rust-analyzer] -rustc_private=true From 1c1ab7d3a783e248080e3425d2cb6027f4879bc5 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 15 Apr 2026 13:28:58 +0100 Subject: [PATCH 26/35] Use prebuilt rules and libcc2rs targets --- tests/lit/lit/formats/Cpp2RustTest.py | 36 +++++++++++++++++++-------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/tests/lit/lit/formats/Cpp2RustTest.py b/tests/lit/lit/formats/Cpp2RustTest.py index 292eedc..5fafe0c 100644 --- a/tests/lit/lit/formats/Cpp2RustTest.py +++ b/tests/lit/lit/formats/Cpp2RustTest.py @@ -7,21 +7,29 @@ import difflib, os, re, shutil, random import tomli -def read_rust_version(): - toolchain_path = os.path.join(os.path.dirname(__file__), - '../../../../libcc2rs/rust-toolchain.toml') - with open(toolchain_path, 'rb') as f: - return tomli.load(f)['toolchain']['channel'] - class Cpp2RustTest(TestFormat): def __init__(self): self.regex_xfail = re.compile(r"//\s*XFAIL:\s*(.*)") self.regex_panic = re.compile(r"//\s*panic\s*(?::\s*(.*))?$", re.MULTILINE) self.regex_nocompile = re.compile(r"//\s*no-compile\s*(?::\s*(.*))?$", re.MULTILINE) self.regex_nondet_result = re.compile(r"//\s*nondet-result\s*(?::\s*(.*))?$", re.MULTILINE) - self.rust_version = read_rust_version() + self.rust_version = self.readRustVersion() os.environ['RUSTFLAGS'] = '-Awarnings -A dangerous-implicit-autorefs' + def readRustVersion(self): + toolchain_path = os.path.join(os.path.dirname(__file__), + '../../../../libcc2rs/rust-toolchain.toml') + with open(toolchain_path, 'rb') as f: + return tomli.load(f)['toolchain']['channel'] + + def cargoEnv(self): + return dict(os.environ, CARGO_TARGET_DIR=os.path.abspath(self.sharedTargetDir())) + + def sharedTargetDir(self): + return os.path.abspath(os.path.join( + os.path.dirname(__file__), + '../../../../build/tmp/cargo-target')) + def updateExpected(self, generated, expected_path): os.makedirs(os.path.dirname(expected_path), exist_ok=True) with open(expected_path, 'w') as f: @@ -120,24 +128,32 @@ def fail(str, code = fail_code): fromfile='expected', tofile='generated')) return fail('different output\n' + diff) + pkg_name = "test_" + re.sub(r'[^a-zA-Z0-9_]', '_', + os.path.basename(tmp_dir)) + # Check if we can compile the rust file with open(tmp_dir + "/rust-toolchain.toml", 'w') as f: f.write(f'[toolchain]\nchannel = "{self.rust_version}"\n') with open(tmp_dir + "/Cargo.toml", 'w') as f: f.write(f""" [package] -name = "test" +name = "{pkg_name}" version = "0.1.0" edition = "2021" rust-version = "{self.rust_version}" +[[bin]] +name = "{pkg_name}" +path = "src/main.rs" + [dependencies] libc = "0.2.169" libcc2rs = {{ path = "../../../libcc2rs" }} +rules = {{ path = "../../../rules" }} """) cmd = ['cargo', 'build', '--release', '--quiet'] - _, err, returncode = lit.util.executeCommand(cmd, tmp_dir) + _, err, returncode = lit.util.executeCommand(cmd, tmp_dir, env=self.cargoEnv()) if should_not_compile: if returncode != 0: shutil.rmtree(tmp_dir, True) @@ -146,7 +162,7 @@ def fail(str, code = fail_code): if returncode != 0: return fail('cargo failed\n' + err) - rust_bin = tmp_dir + "/target/release/test" + rust_bin = os.path.join(self.sharedTargetDir(), "release", pkg_name) if not skip_run: if should_panic: From 840863d017b5c03d7fe563e4cd04ec858fe7f485 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 15 Apr 2026 13:47:21 +0100 Subject: [PATCH 27/35] Implement Deref for FnPtr --- cpp2rust/converter/converter.cpp | 1 - .../converter/models/converter_refcount.cpp | 7 +++---- libcc2rs/src/fn_ptr.rs | 12 +++++++----- tests/unit/out/refcount/fn_ptr.rs | 2 +- tests/unit/out/refcount/fn_ptr_array.rs | 6 +++--- tests/unit/out/refcount/fn_ptr_as_condition.rs | 4 ++-- tests/unit/out/refcount/fn_ptr_cast.rs | 10 +++++----- tests/unit/out/refcount/fn_ptr_conditional.rs | 17 +++++++---------- tests/unit/out/refcount/fn_ptr_default_arg.rs | 2 +- tests/unit/out/refcount/fn_ptr_global.rs | 2 +- tests/unit/out/refcount/fn_ptr_reassign.rs | 8 ++++---- tests/unit/out/refcount/fn_ptr_return.rs | 4 ++-- tests/unit/out/refcount/fn_ptr_struct.rs | 6 +++--- tests/unit/out/refcount/fn_ptr_void_return.rs | 4 ++-- tests/unit/out/refcount/fn_ptr_vtable.rs | 6 +++--- tests/unit/out/refcount/no_direct_callee.rs | 2 +- 16 files changed, 45 insertions(+), 48 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 8586ffa..e8e638a 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -131,7 +131,6 @@ bool Converter::VisitRecordType(clang::RecordType *type) { if (auto lambda = clang::dyn_cast(decl)) { if (lambda->isLambda()) { if (in_function_formals_) { - // Function parameters can't use `_`. Emit `impl Fn(args) -> ret`. auto call_op = lambda->getLambdaCallOperator(); StrCat("impl Fn("); for (auto p : call_op->parameters()) { diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index b11e159..bf3160a 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -180,10 +180,8 @@ std::string ConverterRefCount::BuildFnAdapter( // Build adapter signature: |a0: T0, a1: T1, ...| -> Tr std::string closure = "(|"; for (unsigned i = 0; i < target_proto->getNumParams(); ++i) { - if (i > 0) - closure += ", "; closure += - std::format("a{}: {}", i, ToString(target_proto->getParamType(i))); + std::format("a{}: {},", i, ToString(target_proto->getParamType(i))); } closure += "|"; if (!target_proto->getReturnType()->isVoidType()) { @@ -1025,8 +1023,9 @@ bool ConverterRefCount::VisitImplicitCastExpr(clang::ImplicitCastExpr *expr) { } void ConverterRefCount::EmitFnPtrCall(clang::Expr *callee) { + StrCat("(*"); Convert(callee); - StrCat(".call()"); + StrCat(")"); } void ConverterRefCount::EmitFnAsValue(const clang::FunctionDecl *fn_decl) { diff --git a/libcc2rs/src/fn_ptr.rs b/libcc2rs/src/fn_ptr.rs index e2d9f6a..63d0c86 100644 --- a/libcc2rs/src/fn_ptr.rs +++ b/libcc2rs/src/fn_ptr.rs @@ -3,6 +3,7 @@ use std::any::{Any, TypeId}; use std::marker::PhantomData; +use std::ops::Deref; use std::rc::Rc; use crate::rc::{AnyPtr, ErasedPtr}; @@ -75,17 +76,18 @@ impl FnPtr { } } - pub fn call(&self) -> T - where - T: Copy, - { +} + +impl Deref for FnPtr { + type Target = T; + fn deref(&self) -> &T { let state = self.state.as_ref().expect("ub: null fn pointer call"); let entry = state .cast_history .last() .expect("empty fn pointer cast_history"); match entry { - Some(rc) => *rc + Some(rc) => rc .downcast_ref::() .expect("ub: fn pointer type mismatch"), None => panic!("ub: calling through incompatible fn pointer type"), diff --git a/tests/unit/out/refcount/fn_ptr.rs b/tests/unit/out/refcount/fn_ptr.rs index 0ef5625..34753e3 100644 --- a/tests/unit/out/refcount/fn_ptr.rs +++ b/tests/unit/out/refcount/fn_ptr.rs @@ -16,7 +16,7 @@ pub fn foo_1(fn_: FnPtr i32>, pi: Ptr) -> i32 { let pi: Value> = Rc::new(RefCell::new(pi)); return ({ let _arg0: AnyPtr = ((*pi.borrow()).clone() as Ptr).to_any(); - (*fn_.borrow()).call()(_arg0) + (*(*fn_.borrow()))(_arg0) }); } pub fn main() { diff --git a/tests/unit/out/refcount/fn_ptr_array.rs b/tests/unit/out/refcount/fn_ptr_array.rs index 8e1d5fc..e524cc7 100644 --- a/tests/unit/out/refcount/fn_ptr_array.rs +++ b/tests/unit/out/refcount/fn_ptr_array.rs @@ -35,21 +35,21 @@ fn main_0() -> i32 { (({ let _arg0: i32 = 2; let _arg1: i32 = 3; - (*ops.borrow())[(0) as usize].call()(_arg0, _arg1) + (*(*ops.borrow())[(0) as usize])(_arg0, _arg1) }) == 5) ); assert!( (({ let _arg0: i32 = 7; let _arg1: i32 = 4; - (*ops.borrow())[(1) as usize].call()(_arg0, _arg1) + (*(*ops.borrow())[(1) as usize])(_arg0, _arg1) }) == 3) ); assert!( (({ let _arg0: i32 = 6; let _arg1: i32 = 5; - (*ops.borrow())[(2) as usize].call()(_arg0, _arg1) + (*(*ops.borrow())[(2) as usize])(_arg0, _arg1) }) == 30) ); assert!(!(((*ops.borrow())[(0) as usize]).is_null())); diff --git a/tests/unit/out/refcount/fn_ptr_as_condition.rs b/tests/unit/out/refcount/fn_ptr_as_condition.rs index c6ffacf..5afb76c 100644 --- a/tests/unit/out/refcount/fn_ptr_as_condition.rs +++ b/tests/unit/out/refcount/fn_ptr_as_condition.rs @@ -21,7 +21,7 @@ pub fn maybe_call_1(cb: FnPtr)>, x: Ptr) { if !(*cb.borrow()).is_null() { ({ let _arg0: Ptr = (*x.borrow()).clone(); - (*cb.borrow()).call()(_arg0) + (*(*cb.borrow()))(_arg0) }); } } @@ -51,7 +51,7 @@ fn main_0() -> i32 { if !(*fn_.borrow()).is_null() { ({ let _arg0: Ptr = (c.as_pointer()); - (*fn_.borrow()).call()(_arg0) + (*(*fn_.borrow()))(_arg0) }); } assert!(((*c.borrow()) == 6)); diff --git a/tests/unit/out/refcount/fn_ptr_cast.rs b/tests/unit/out/refcount/fn_ptr_cast.rs index c33b2bd..400cf44 100644 --- a/tests/unit/out/refcount/fn_ptr_cast.rs +++ b/tests/unit/out/refcount/fn_ptr_cast.rs @@ -17,7 +17,7 @@ pub fn test_roundtrip_1() { assert!( (({ let _arg0: i32 = 5; - (*fn_.borrow()).call()(_arg0) + (*(*fn_.borrow()))(_arg0) }) == 10) ); let gfn: Value> = @@ -29,7 +29,7 @@ pub fn test_roundtrip_1() { assert!( (({ let _arg0: i32 = 5; - (*fn2.borrow()).call()(_arg0) + (*(*fn2.borrow()))(_arg0) }) == 10) ); assert!({ @@ -49,7 +49,7 @@ pub fn test_double_cast_2() { assert!( (({ let _arg0: i32 = 5; - (*fn2.borrow()).call()(_arg0) + (*(*fn2.borrow()))(_arg0) }) == 10) ); assert!({ @@ -82,7 +82,7 @@ pub fn test_void_ptr_to_fn_3() { assert!( (({ let _arg0: i32 = 5; - (*fn_.borrow()).call()(_arg0) + (*(*fn_.borrow()))(_arg0) }) == 10) ); } @@ -106,7 +106,7 @@ pub fn test_call_through_cast_5() { ({ let _arg0: AnyPtr = ((val.as_pointer()) as Ptr).to_any(); let _arg1: i32 = 42; - (*gfn.borrow()).call()(_arg0, _arg1) + (*(*gfn.borrow()))(_arg0, _arg1) }), )); assert!(((*result.borrow()) == 142)); diff --git a/tests/unit/out/refcount/fn_ptr_conditional.rs b/tests/unit/out/refcount/fn_ptr_conditional.rs index c6e577a..8868479 100644 --- a/tests/unit/out/refcount/fn_ptr_conditional.rs +++ b/tests/unit/out/refcount/fn_ptr_conditional.rs @@ -42,7 +42,7 @@ pub fn apply_4(fn_: FnPtr i32>, x: i32) -> i32 { })); return ({ let _arg0: i32 = (*x.borrow()); - (*actual.borrow()).call()(_arg0) + (*(*actual.borrow()))(_arg0) }); } pub fn main() { @@ -52,31 +52,28 @@ fn main_0() -> i32 { assert!( (({ let _arg0: i32 = 10; - ({ + (*({ let _mode: i32 = 1; pick_3(_mode) - }) - .call()(_arg0) + }))(_arg0) }) == 11) ); assert!( (({ let _arg0: i32 = 10; - ({ + (*({ let _mode: i32 = -1_i32; pick_3(_mode) - }) - .call()(_arg0) + }))(_arg0) }) == 9) ); assert!( (({ let _arg0: i32 = 10; - ({ + (*({ let _mode: i32 = 0; pick_3(_mode) - }) - .call()(_arg0) + }))(_arg0) }) == 10) ); assert!( diff --git a/tests/unit/out/refcount/fn_ptr_default_arg.rs b/tests/unit/out/refcount/fn_ptr_default_arg.rs index 6c6ab79..26b8d9b 100644 --- a/tests/unit/out/refcount/fn_ptr_default_arg.rs +++ b/tests/unit/out/refcount/fn_ptr_default_arg.rs @@ -17,7 +17,7 @@ pub fn apply_1(x: i32, fn_: Option i32>>) -> i32 { if !(*fn_.borrow()).is_null() { return ({ let _arg0: i32 = (*x.borrow()); - (*fn_.borrow()).call()(_arg0) + (*(*fn_.borrow()))(_arg0) }); } return (*x.borrow()); diff --git a/tests/unit/out/refcount/fn_ptr_global.rs b/tests/unit/out/refcount/fn_ptr_global.rs index af0dca9..94b7d34 100644 --- a/tests/unit/out/refcount/fn_ptr_global.rs +++ b/tests/unit/out/refcount/fn_ptr_global.rs @@ -27,7 +27,7 @@ pub fn call_op_3(x: i32) -> i32 { if !(*g_op.with(Value::clone).borrow()).is_null() { return ({ let _arg0: i32 = (*x.borrow()); - (*g_op.with(Value::clone).borrow()).call()(_arg0) + (*(*g_op.with(Value::clone).borrow()))(_arg0) }); } return (*x.borrow()); diff --git a/tests/unit/out/refcount/fn_ptr_reassign.rs b/tests/unit/out/refcount/fn_ptr_reassign.rs index 123abbe..c8c47f6 100644 --- a/tests/unit/out/refcount/fn_ptr_reassign.rs +++ b/tests/unit/out/refcount/fn_ptr_reassign.rs @@ -32,7 +32,7 @@ fn main_0() -> i32 { (({ let _arg0: i32 = 3; let _arg1: i32 = 4; - (*fn_.borrow()).call()(_arg0, _arg1) + (*(*fn_.borrow()))(_arg0, _arg1) }) == 7) ); (*fn_.borrow_mut()) = fn_ptr!(sub_1, fn(i32, i32) -> i32); @@ -40,7 +40,7 @@ fn main_0() -> i32 { (({ let _arg0: i32 = 10; let _arg1: i32 = 3; - (*fn_.borrow()).call()(_arg0, _arg1) + (*(*fn_.borrow()))(_arg0, _arg1) }) == 7) ); (*fn_.borrow_mut()) = fn_ptr!(mul_2, fn(i32, i32) -> i32); @@ -48,7 +48,7 @@ fn main_0() -> i32 { (({ let _arg0: i32 = 6; let _arg1: i32 = 7; - (*fn_.borrow()).call()(_arg0, _arg1) + (*(*fn_.borrow()))(_arg0, _arg1) }) == 42) ); (*fn_.borrow_mut()) = FnPtr::null(); @@ -59,7 +59,7 @@ fn main_0() -> i32 { (({ let _arg0: i32 = 1; let _arg1: i32 = 1; - (*fn_.borrow()).call()(_arg0, _arg1) + (*(*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 index 4368149..b80f7c1 100644 --- a/tests/unit/out/refcount/fn_ptr_return.rs +++ b/tests/unit/out/refcount/fn_ptr_return.rs @@ -40,7 +40,7 @@ fn main_0() -> i32 { assert!( (({ let _arg0: i32 = 10; - (*f.borrow()).call()(_arg0) + (*(*f.borrow()))(_arg0) }) == 11) ); let g: Value i32>> = Rc::new(RefCell::new( @@ -56,7 +56,7 @@ fn main_0() -> i32 { assert!( (({ let _arg0: i32 = 10; - (*g.borrow()).call()(_arg0) + (*(*g.borrow()))(_arg0) }) == 9) ); assert!({ diff --git a/tests/unit/out/refcount/fn_ptr_struct.rs b/tests/unit/out/refcount/fn_ptr_struct.rs index 777a60e..0d34f1d 100644 --- a/tests/unit/out/refcount/fn_ptr_struct.rs +++ b/tests/unit/out/refcount/fn_ptr_struct.rs @@ -54,20 +54,20 @@ fn main_0() -> i32 { assert!( (({ let _arg0: i32 = 5; - (*(*h1.borrow()).cb.borrow()).call()(_arg0) + (*(*(*h1.borrow()).cb.borrow()))(_arg0) }) == 10) ); assert!( (({ let _arg0: i32 = 7; - (*(*h2.borrow()).cb.borrow()).call()(_arg0) + (*(*(*h2.borrow()).cb.borrow()))(_arg0) }) == -7_i32) ); (*(*h1.borrow()).cb.borrow_mut()) = fn_ptr!(negate_1, fn(i32) -> i32); assert!( (({ let _arg0: i32 = 3; - (*(*h1.borrow()).cb.borrow()).call()(_arg0) + (*(*(*h1.borrow()).cb.borrow()))(_arg0) }) == -3_i32) ); assert!({ diff --git a/tests/unit/out/refcount/fn_ptr_void_return.rs b/tests/unit/out/refcount/fn_ptr_void_return.rs index 69fd6b1..dc49639 100644 --- a/tests/unit/out/refcount/fn_ptr_void_return.rs +++ b/tests/unit/out/refcount/fn_ptr_void_return.rs @@ -21,7 +21,7 @@ pub fn run_2(fn_: FnPtr)>, x: Ptr) { let x: Value> = Rc::new(RefCell::new(x)); ({ let _arg0: Ptr = (*x.borrow()).clone(); - (*fn_.borrow()).call()(_arg0) + (*(*fn_.borrow()))(_arg0) }); } pub fn main() { @@ -46,7 +46,7 @@ fn main_0() -> i32 { let b: Value = Rc::new(RefCell::new(10)); ({ let _arg0: Ptr = (b.as_pointer()); - (*fn_.borrow()).call()(_arg0) + (*(*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 index 7b94350..b8e80be 100644 --- a/tests/unit/out/refcount/fn_ptr_vtable.rs +++ b/tests/unit/out/refcount/fn_ptr_vtable.rs @@ -66,18 +66,18 @@ fn main_0() -> i32 { let obj: Value = Rc::new(RefCell::new( ({ let _arg0: i32 = 42; - (*(*vt.borrow()).create.borrow()).call()(_arg0) + (*(*(*vt.borrow()).create.borrow()))(_arg0) }), )); assert!( (({ let _arg0: AnyPtr = (*obj.borrow()).clone(); - (*(*vt.borrow()).get.borrow()).call()(_arg0) + (*(*(*vt.borrow()).get.borrow()))(_arg0) }) == 42) ); ({ let _arg0: AnyPtr = (*obj.borrow()).clone(); - (*(*vt.borrow()).destroy.borrow()).call()(_arg0) + (*(*(*vt.borrow()).destroy.borrow()))(_arg0) }); assert!(((*storage.with(Value::clone).borrow()) == 0)); (*(*vt.borrow()).get.borrow_mut()) = FnPtr::null(); diff --git a/tests/unit/out/refcount/no_direct_callee.rs b/tests/unit/out/refcount/no_direct_callee.rs index 192ee3e..6b81f98 100644 --- a/tests/unit/out/refcount/no_direct_callee.rs +++ b/tests/unit/out/refcount/no_direct_callee.rs @@ -12,7 +12,7 @@ pub fn test1_0() -> bool { } pub fn test_1(fn_: FnPtr bool>) -> i32 { let fn_: Value bool>> = Rc::new(RefCell::new(fn_)); - if !({ (*fn_.borrow()).call()() }) { + if !({ (*(*fn_.borrow()))() }) { return 1; } return 0; From 3c1b9c7e41c59a815e9001f9a9928d1a6242f7d4 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 15 Apr 2026 13:48:37 +0100 Subject: [PATCH 28/35] Update rules IR --- libcc2rs/src/fn_ptr.rs | 1 - rules/stdio/ir_unsafe.json | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/libcc2rs/src/fn_ptr.rs b/libcc2rs/src/fn_ptr.rs index 63d0c86..0cef310 100644 --- a/libcc2rs/src/fn_ptr.rs +++ b/libcc2rs/src/fn_ptr.rs @@ -75,7 +75,6 @@ impl FnPtr { _marker: PhantomData, } } - } impl Deref for FnPtr { diff --git a/rules/stdio/ir_unsafe.json b/rules/stdio/ir_unsafe.json index 81d8f44..8b55e1c 100644 --- a/rules/stdio/ir_unsafe.json +++ b/rules/stdio/ir_unsafe.json @@ -618,7 +618,7 @@ "multi_statement": true, "params": { "a0": { - "type": "*mut u8", + "type": "*mut ::libc::c_void", "is_unsafe_pointer": true }, "a1": { @@ -797,7 +797,7 @@ "multi_statement": true, "params": { "a0": { - "type": "*mut u8", + "type": "*const ::libc::c_void", "is_unsafe_pointer": true }, "a1": { From e7fa221ca9c0149af83bd92587b246af081f3a56 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 15 Apr 2026 14:21:47 +0100 Subject: [PATCH 29/35] Remove unused fn ptr cast and fn_ptr_anon --- cpp2rust/converter/converter.cpp | 2 +- cpp2rust/converter/models/converter_refcount.cpp | 7 ++----- libcc2rs/src/fn_ptr.rs | 7 +++++++ libcc2rs/src/lib.rs | 16 ---------------- tests/unit/out/refcount/fn_ptr_default_arg.rs | 4 ++-- tests/unit/out/unsafe/fn_ptr.rs | 6 +++--- tests/unit/out/unsafe/fn_ptr_array.rs | 7 +++---- tests/unit/out/unsafe/fn_ptr_as_condition.rs | 4 ++-- tests/unit/out/unsafe/fn_ptr_cast.rs | 15 +++++++-------- tests/unit/out/unsafe/fn_ptr_conditional.rs | 10 +++++----- tests/unit/out/unsafe/fn_ptr_default_arg.rs | 2 +- tests/unit/out/unsafe/fn_ptr_global.rs | 8 ++++---- tests/unit/out/unsafe/fn_ptr_reassign.rs | 8 ++++---- tests/unit/out/unsafe/fn_ptr_return.rs | 8 ++++---- tests/unit/out/unsafe/fn_ptr_stdlib_compare.rs | 6 +++--- tests/unit/out/unsafe/fn_ptr_struct.rs | 6 +++--- tests/unit/out/unsafe/fn_ptr_void_return.rs | 6 +++--- tests/unit/out/unsafe/fn_ptr_vtable.rs | 6 +++--- tests/unit/out/unsafe/no_direct_callee.rs | 2 +- 19 files changed, 58 insertions(+), 72 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index e8e638a..0df813f 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -1381,7 +1381,7 @@ void Converter::EmitFnPtrCall(clang::Expr *callee) { } void Converter::EmitFnAsValue(const clang::FunctionDecl *fn_decl) { - StrCat(std::format("Some({} as _)", Mapper::GetFnRefName(fn_decl))); + StrCat(std::format("Some({})", Mapper::GetFnRefName(fn_decl))); } std::string Converter::GetPointeeRustType(clang::QualType ptr_type) { diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index bf3160a..d8b2b13 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -1618,12 +1618,9 @@ void ConverterRefCount::ConvertVarInit(clang::QualType qual_type, Buffer buf(*this); PushConversionKind push(*this, ConversionKind::Unboxed); if (qual_type->isFunctionPointerType() && lambda->capture_size() == 0) { - StrCat("fn_ptr_anon!(("); + StrCat("FnPtr::new(("); VisitLambdaExpr(lambda); - StrCat(std::format( - "), {})", - GetFnTypeString(qual_type->getPointeeType() - ->getAs()))); + StrCat("), 0)"); } else { VisitLambdaExpr(lambda); } diff --git a/libcc2rs/src/fn_ptr.rs b/libcc2rs/src/fn_ptr.rs index 0cef310..07a5f0d 100644 --- a/libcc2rs/src/fn_ptr.rs +++ b/libcc2rs/src/fn_ptr.rs @@ -1,6 +1,13 @@ // Copyright (c) 2022-present INESC-ID. // Distributed under the MIT license that can be found in the LICENSE file. +#[macro_export] +macro_rules! fn_ptr { + ($f:expr, $ty:ty) => { + $crate::FnPtr::new($f as $ty, $f as *const () as usize) + }; +} + use std::any::{Any, TypeId}; use std::marker::PhantomData; use std::ops::Deref; diff --git a/libcc2rs/src/lib.rs b/libcc2rs/src/lib.rs index 998280f..1271b94 100644 --- a/libcc2rs/src/lib.rs +++ b/libcc2rs/src/lib.rs @@ -4,22 +4,6 @@ mod reinterpret; pub use reinterpret::ByteRepr; -#[macro_export] -macro_rules! fn_ptr { - ($f:expr, $ty:ty) => { - $crate::FnPtr::new($f as $ty, $f as *const () as usize) - }; -} - -// Lambda: no stable address, use 0. TODO: assign unique addr per lambda site so distinct -// lambdas don't compare equal. -#[macro_export] -macro_rules! fn_ptr_anon { - ($f:expr, $ty:ty) => { - $crate::FnPtr::new($f as $ty, 0) - }; -} - mod rc; pub use rc::*; diff --git a/tests/unit/out/refcount/fn_ptr_default_arg.rs b/tests/unit/out/refcount/fn_ptr_default_arg.rs index 26b8d9b..0c598b6 100644 --- a/tests/unit/out/refcount/fn_ptr_default_arg.rs +++ b/tests/unit/out/refcount/fn_ptr_default_arg.rs @@ -47,12 +47,12 @@ fn main_0() -> i32 { apply_1(_x, Some(_fn)) }) == 5) ); - let negate: Value i32>> = Rc::new(RefCell::new(fn_ptr_anon!( + let negate: Value i32>> = Rc::new(RefCell::new(FnPtr::new( (|x: i32| { let x: Value = Rc::new(RefCell::new(x)); return -(*x.borrow()); }), - fn(i32) -> i32 + 0, ))); assert!( (({ diff --git a/tests/unit/out/unsafe/fn_ptr.rs b/tests/unit/out/unsafe/fn_ptr.rs index cc9d4ae..60ce303 100644 --- a/tests/unit/out/unsafe/fn_ptr.rs +++ b/tests/unit/out/unsafe/fn_ptr.rs @@ -27,10 +27,10 @@ pub fn main() { unsafe fn main_0() -> i32 { let mut fn_: Option i32> = None; assert!((fn_).is_none()); - assert!(((fn_) != (Some(my_foo_0 as _)))); - fn_ = Some(my_foo_0 as _); + assert!(((fn_) != (Some(my_foo_0)))); + fn_ = Some(my_foo_0); assert!(!((fn_).is_none())); - assert!(((fn_) == (Some(my_foo_0 as _)))); + assert!(((fn_) == (Some(my_foo_0)))); let mut a: i32 = 10; assert!( ((unsafe { diff --git a/tests/unit/out/unsafe/fn_ptr_array.rs b/tests/unit/out/unsafe/fn_ptr_array.rs index f69829e..1e22470 100644 --- a/tests/unit/out/unsafe/fn_ptr_array.rs +++ b/tests/unit/out/unsafe/fn_ptr_array.rs @@ -22,8 +22,7 @@ pub fn main() { } } unsafe fn main_0() -> i32 { - let mut ops: [Option i32>; 3] = - [Some(add_0 as _), Some(sub_1 as _), Some(mul_2 as _)]; + let mut ops: [Option i32>; 3] = [Some(add_0), Some(sub_1), Some(mul_2)]; assert!( ((unsafe { let _arg0: i32 = 2; @@ -46,7 +45,7 @@ unsafe fn main_0() -> i32 { }) == (30)) ); assert!(!((ops[(0) as usize]).is_none())); - assert!(((ops[(0) as usize]) == (Some(add_0 as _)))); - assert!(((ops[(0) as usize]) != (Some(sub_1 as _)))); + 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 index ce851f5..7669fb3 100644 --- a/tests/unit/out/unsafe/fn_ptr_as_condition.rs +++ b/tests/unit/out/unsafe/fn_ptr_as_condition.rs @@ -26,7 +26,7 @@ pub fn main() { unsafe fn main_0() -> i32 { let mut a: i32 = 5; (unsafe { - let _cb: Option = Some(double_it_0 as _); + let _cb: Option = Some(double_it_0); let _x: *mut i32 = (&mut a as *mut i32); maybe_call_1(_cb, _x) }); @@ -40,7 +40,7 @@ unsafe fn main_0() -> i32 { assert!(((b) == (5))); let mut fn_: Option = None; if !!(fn_).is_none() { - fn_ = Some(double_it_0 as _); + fn_ = Some(double_it_0); } let mut c: i32 = 3; if !(fn_).is_none() { diff --git a/tests/unit/out/unsafe/fn_ptr_cast.rs b/tests/unit/out/unsafe/fn_ptr_cast.rs index e5ebf48..9fce4e7 100644 --- a/tests/unit/out/unsafe/fn_ptr_cast.rs +++ b/tests/unit/out/unsafe/fn_ptr_cast.rs @@ -11,7 +11,7 @@ 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 as _); + let mut fn_: Option i32> = Some(double_it_0); assert!( ((unsafe { let _arg0: i32 = 5; @@ -32,7 +32,7 @@ pub unsafe fn test_roundtrip_1() { assert!(((fn2) == (fn_))); } pub unsafe fn test_double_cast_2() { - let mut fn_: Option i32> = Some(double_it_0 as _); + 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_), @@ -52,7 +52,7 @@ pub struct Command { 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 as _, + double_it_0, )); let mut fn_: Option i32> = std::mem::transmute::<*mut ::libc::c_void, Option i32>>(cmd.data); @@ -67,11 +67,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 as _)); + 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 = diff --git a/tests/unit/out/unsafe/fn_ptr_conditional.rs b/tests/unit/out/unsafe/fn_ptr_conditional.rs index adfad96..0694a0b 100644 --- a/tests/unit/out/unsafe/fn_ptr_conditional.rs +++ b/tests/unit/out/unsafe/fn_ptr_conditional.rs @@ -18,12 +18,12 @@ pub unsafe fn identity_2(mut x: i32) -> i32 { } pub unsafe fn pick_3(mut mode: i32) -> Option i32> { return if ((mode) > (0)) { - Some(inc_0 as _) + Some(inc_0) } else { if ((mode) < (0)) { - Some(dec_1 as _) + Some(dec_1) } else { - Some(identity_2 as _) + Some(identity_2) } }; } @@ -31,7 +31,7 @@ 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 as _) + Some(identity_2) }; return (unsafe { let _arg0: i32 = x; @@ -76,7 +76,7 @@ unsafe fn main_0() -> i32 { ); assert!( ((unsafe { - let _fn: Option i32> = Some(inc_0 as _); + let _fn: Option i32> = Some(inc_0); let _x: i32 = 5; apply_4(_fn, _x) }) == (6)) diff --git a/tests/unit/out/unsafe/fn_ptr_default_arg.rs b/tests/unit/out/unsafe/fn_ptr_default_arg.rs index 5decf93..86287ca 100644 --- a/tests/unit/out/unsafe/fn_ptr_default_arg.rs +++ b/tests/unit/out/unsafe/fn_ptr_default_arg.rs @@ -43,7 +43,7 @@ unsafe fn main_0() -> i32 { assert!( ((unsafe { let _x: i32 = 5; - let _fn: Option i32> = Some(identity_0 as _); + let _fn: Option i32> = Some(identity_0); apply_1(_x, Some(_fn)) }) == (5)) ); diff --git a/tests/unit/out/unsafe/fn_ptr_global.rs b/tests/unit/out/unsafe/fn_ptr_global.rs index d4ce4c2..21dc35b 100644 --- a/tests/unit/out/unsafe/fn_ptr_global.rs +++ b/tests/unit/out/unsafe/fn_ptr_global.rs @@ -39,11 +39,11 @@ unsafe fn main_0() -> i32 { }) == (5)) ); (unsafe { - let _fn: Option i32> = Some(double_it_0 as _); + let _fn: Option i32> = Some(double_it_0); set_op_2(_fn) }); assert!(!((g_op).is_none())); - assert!(((g_op) == (Some(double_it_0 as _)))); + assert!(((g_op) == (Some(double_it_0)))); assert!( ((unsafe { let _x: i32 = 5; @@ -51,10 +51,10 @@ unsafe fn main_0() -> i32 { }) == (10)) ); (unsafe { - let _fn: Option i32> = Some(triple_it_1 as _); + let _fn: Option i32> = Some(triple_it_1); set_op_2(_fn) }); - assert!(((g_op) == (Some(triple_it_1 as _)))); + assert!(((g_op) == (Some(triple_it_1)))); assert!( ((unsafe { let _x: i32 = 5; diff --git a/tests/unit/out/unsafe/fn_ptr_reassign.rs b/tests/unit/out/unsafe/fn_ptr_reassign.rs index 19ade02..08eed4b 100644 --- a/tests/unit/out/unsafe/fn_ptr_reassign.rs +++ b/tests/unit/out/unsafe/fn_ptr_reassign.rs @@ -22,7 +22,7 @@ pub fn main() { } } unsafe fn main_0() -> i32 { - let mut fn_: Option i32> = Some(add_0 as _); + let mut fn_: Option i32> = Some(add_0); assert!( ((unsafe { let _arg0: i32 = 3; @@ -30,7 +30,7 @@ unsafe fn main_0() -> i32 { (fn_).unwrap()(_arg0, _arg1) }) == (7)) ); - fn_ = Some(sub_1 as _); + fn_ = Some(sub_1); assert!( ((unsafe { let _arg0: i32 = 10; @@ -38,7 +38,7 @@ unsafe fn main_0() -> i32 { (fn_).unwrap()(_arg0, _arg1) }) == (7)) ); - fn_ = Some(mul_2 as _); + fn_ = Some(mul_2); assert!( ((unsafe { let _arg0: i32 = 6; @@ -48,7 +48,7 @@ unsafe fn main_0() -> i32 { ); fn_ = None; assert!((fn_).is_none()); - fn_ = Some(add_0 as _); + fn_ = Some(add_0); assert!(!((fn_).is_none())); assert!( ((unsafe { diff --git a/tests/unit/out/unsafe/fn_ptr_return.rs b/tests/unit/out/unsafe/fn_ptr_return.rs index 7e2e927..1cda282 100644 --- a/tests/unit/out/unsafe/fn_ptr_return.rs +++ b/tests/unit/out/unsafe/fn_ptr_return.rs @@ -15,9 +15,9 @@ pub unsafe fn dec_1(mut x: i32) -> i32 { } pub unsafe fn pick_2(mut choose_inc: i32) -> Option i32> { if (choose_inc != 0) { - return Some(inc_0 as _); + return Some(inc_0); } - return Some(dec_1 as _); + return Some(dec_1); } pub fn main() { unsafe { @@ -30,7 +30,7 @@ unsafe fn main_0() -> i32 { pick_2(_choose_inc) }); assert!(!((f).is_none())); - assert!(((f) == (Some(inc_0 as _)))); + assert!(((f) == (Some(inc_0)))); assert!( ((unsafe { let _arg0: i32 = 10; @@ -41,7 +41,7 @@ unsafe fn main_0() -> i32 { let _choose_inc: i32 = 0; pick_2(_choose_inc) }); - assert!(((g) == (Some(dec_1 as _)))); + assert!(((g) == (Some(dec_1)))); assert!( ((unsafe { let _arg0: i32 = 10; diff --git a/tests/unit/out/unsafe/fn_ptr_stdlib_compare.rs b/tests/unit/out/unsafe/fn_ptr_stdlib_compare.rs index cf09b6b..432cdf5 100644 --- a/tests/unit/out/unsafe/fn_ptr_stdlib_compare.rs +++ b/tests/unit/out/unsafe/fn_ptr_stdlib_compare.rs @@ -14,14 +14,14 @@ pub fn main() { } unsafe fn main_0() -> i32 { let mut rfn: Option u64> = - Some(rules::stdio_tgt_unsafe::f5 as _); - assert!(((rfn) == (Some(rules::stdio_tgt_unsafe::f5 as _)))); + Some(rules::stdio_tgt_unsafe::f5); + assert!(((rfn) == (Some(rules::stdio_tgt_unsafe::f5)))); assert!(!((rfn).is_none())); let mut rfn2: Option u64> = std::mem::transmute::< Option u64>, Option u64>, - >(Some(rules::stdio_tgt_unsafe::f5 as _)); + >(Some(rules::stdio_tgt_unsafe::f5)); assert!( ((rfn) == (std::mem::transmute::< diff --git a/tests/unit/out/unsafe/fn_ptr_struct.rs b/tests/unit/out/unsafe/fn_ptr_struct.rs index 277b226..ae9e3a7 100644 --- a/tests/unit/out/unsafe/fn_ptr_struct.rs +++ b/tests/unit/out/unsafe/fn_ptr_struct.rs @@ -34,11 +34,11 @@ pub fn main() { unsafe fn main_0() -> i32 { let mut h1: Handler = Handler { tag: 1, - cb: Some(double_it_0 as _), + cb: Some(double_it_0), }; let mut h2: Handler = Handler { tag: 2, - cb: Some(negate_1 as _), + cb: Some(negate_1), }; assert!(!((h1.cb).is_none())); assert!( @@ -53,7 +53,7 @@ unsafe fn main_0() -> i32 { (h2.cb).unwrap()(_arg0) }) == (-7_i32)) ); - (h1.cb) = Some(negate_1 as _); + (h1.cb) = Some(negate_1); assert!( ((unsafe { let _arg0: i32 = 3; diff --git a/tests/unit/out/unsafe/fn_ptr_void_return.rs b/tests/unit/out/unsafe/fn_ptr_void_return.rs index 00817f0..72ab341 100644 --- a/tests/unit/out/unsafe/fn_ptr_void_return.rs +++ b/tests/unit/out/unsafe/fn_ptr_void_return.rs @@ -27,18 +27,18 @@ pub fn main() { unsafe fn main_0() -> i32 { let mut a: i32 = 42; (unsafe { - let _fn: Option = Some(negate_0 as _); + 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 as _); + 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 as _); + let mut fn_: Option = Some(negate_0); assert!(!((fn_).is_none())); let mut b: i32 = 10; (unsafe { diff --git a/tests/unit/out/unsafe/fn_ptr_vtable.rs b/tests/unit/out/unsafe/fn_ptr_vtable.rs index 9829808..48e820e 100644 --- a/tests/unit/out/unsafe/fn_ptr_vtable.rs +++ b/tests/unit/out/unsafe/fn_ptr_vtable.rs @@ -40,9 +40,9 @@ pub fn main() { } unsafe fn main_0() -> i32 { let mut vt: Vtable = Vtable { - create: Some(int_create_0 as _), - get: Some(int_get_1 as _), - destroy: Some(int_destroy_2 as _), + 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())); diff --git a/tests/unit/out/unsafe/no_direct_callee.rs b/tests/unit/out/unsafe/no_direct_callee.rs index 1136da6..b4eac21 100644 --- a/tests/unit/out/unsafe/no_direct_callee.rs +++ b/tests/unit/out/unsafe/no_direct_callee.rs @@ -23,7 +23,7 @@ pub fn main() { } unsafe fn main_0() -> i32 { return (unsafe { - let _fn: Option bool> = Some(test1_0 as _); + let _fn: Option bool> = Some(test1_0); test_1(_fn) }); } From 0c1ebf9c65360bcd3028fe55d40d5bdf268e74cd Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 15 Apr 2026 14:24:44 +0100 Subject: [PATCH 30/35] Delete ByteRepr for fn pointers --- libcc2rs/src/reinterpret.rs | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/libcc2rs/src/reinterpret.rs b/libcc2rs/src/reinterpret.rs index 1949501..7bef816 100644 --- a/libcc2rs/src/reinterpret.rs +++ b/libcc2rs/src/reinterpret.rs @@ -64,24 +64,6 @@ impl ByteRepr for std::rc::Rc {} impl ByteRepr for std::cell::RefCell {} impl ByteRepr for Box<[T]> {} impl ByteRepr for Box {} - -macro_rules! impl_byterepr_fn { - ($($name:ident),*) => { - impl ByteRepr for fn($($name),*) -> R {} - }; -} - -impl_byterepr_fn!(); -impl_byterepr_fn!(A); -impl_byterepr_fn!(A, B); -impl_byterepr_fn!(A, B, C); -impl_byterepr_fn!(A, B, C, D); -impl_byterepr_fn!(A, B, C, D, E); -impl_byterepr_fn!(A, B, C, D, E, F); -impl_byterepr_fn!(A, B, C, D, E, F, G); -impl_byterepr_fn!(A, B, C, D, E, F, G, H); -impl_byterepr_fn!(A, B, C, D, E, F, G, H, I); -impl_byterepr_fn!(A, B, C, D, E, F, G, H, I, J); impl ByteRepr for *const T {} impl ByteRepr for *mut T {} impl ByteRepr for (A, B) {} From 60fd8c351d70a41d78008781c42a352b735f1f33 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 15 Apr 2026 14:51:01 +0100 Subject: [PATCH 31/35] Drop Clone trait from ErasedPtr --- libcc2rs/src/rc.rs | 30 ++++-------------------------- 1 file changed, 4 insertions(+), 26 deletions(-) diff --git a/libcc2rs/src/rc.rs b/libcc2rs/src/rc.rs index 3b8fbe1..a921407 100644 --- a/libcc2rs/src/rc.rs +++ b/libcc2rs/src/rc.rs @@ -1013,7 +1013,7 @@ pub(crate) trait ErasedPtr: std::any::Any { impl ErasedPtr for Ptr where - T: Clone + ByteRepr + 'static, + T: ByteRepr + 'static, Ptr: PartialEq, { fn pointee_type_id(&self) -> std::any::TypeId { @@ -1024,35 +1024,13 @@ where if self.pointee_type_id() != src.pointee_type_id() { panic!("memcpy: type mismatch"); } - let src_ptr = src .as_any() .downcast_ref::>() .expect("memcpy: downcast to Ptr failed"); - - let elem = std::mem::size_of::(); - - if len == elem { - self.write(src_ptr.read()); - return; - } - - if elem != 0 && len.is_multiple_of(elem) { - let mut dst = self.clone(); - let mut src_it = src_ptr.clone(); - for _ in 0..(len / elem) { - dst.write(src_it.read()); - dst += 1; - src_it += 1; - } - - return; - } - - panic!( - "memcpy: len {} not compatible with element size {}", - len, elem - ); + let dst_bytes: Ptr = self.reinterpret_cast(); + let src_bytes: Ptr = src_ptr.reinterpret_cast(); + dst_bytes.memcpy(&src_bytes, len); } fn as_any(&self) -> &dyn std::any::Any { From 81581df08296e8bdb681b710b7b0a00edb09afd1 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 15 Apr 2026 14:51:16 +0100 Subject: [PATCH 32/35] Allow casting between nullptr's of different types --- libcc2rs/src/rc.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libcc2rs/src/rc.rs b/libcc2rs/src/rc.rs index a921407..75c2606 100644 --- a/libcc2rs/src/rc.rs +++ b/libcc2rs/src/rc.rs @@ -1055,7 +1055,7 @@ pub struct AnyPtr { pub(crate) ptr: Rc, } -impl Ptr { +impl Ptr { pub fn to_any(&self) -> AnyPtr { AnyPtr { ptr: Rc::new(self.clone()), @@ -1071,6 +1071,11 @@ impl Default for AnyPtr { impl AnyPtr { pub fn cast(&self) -> Option> { + if let Some(p) = self.ptr.as_any().downcast_ref::>() { + if p.is_null() { + return Some(Ptr::::null()); + } + } self.ptr.as_any().downcast_ref::>().cloned() } From 82b9ed04f28d8d6b02b109c2fec20274b1224395 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 15 Apr 2026 14:58:15 +0100 Subject: [PATCH 33/35] Update output of fn_ptr_stdlib_compare --- tests/unit/fn_ptr_stdlib_compare.cpp | 19 +++++---- .../out/refcount/fn_ptr_stdlib_compare.rs | 40 ++++++++++++++++--- .../unit/out/unsafe/fn_ptr_stdlib_compare.rs | 34 +++++++++++++--- 3 files changed, 74 insertions(+), 19 deletions(-) diff --git a/tests/unit/fn_ptr_stdlib_compare.cpp b/tests/unit/fn_ptr_stdlib_compare.cpp index a71581c..6bb8b55 100644 --- a/tests/unit/fn_ptr_stdlib_compare.cpp +++ b/tests/unit/fn_ptr_stdlib_compare.cpp @@ -2,17 +2,22 @@ #include #include -typedef size_t (*read_fn)(void *, size_t, size_t, FILE *); +typedef size_t (*fread_t)(void *, size_t, size_t, FILE *); -typedef size_t (*read_alternative_fn)(char *, size_t, size_t, void *); +typedef size_t (*fread_alternative_t)(char *, size_t, size_t, void *); + +size_t my_alternative_fread(char *p, size_t n, size_t m, void *f) { return 22; } int main() { - read_fn rfn = fread; - assert(rfn == fread); - assert(rfn != nullptr); + fread_t fn1 = fread; + assert(fn1 == fread); + assert(fn1 != nullptr); + + fread_alternative_t fn2 = (fread_alternative_t)fread; + assert(fn1 == (fread_t)fn2); - read_alternative_fn rfn2 = (read_alternative_fn)fread; - assert(rfn == (read_fn)rfn2); + fread_t f3 = (fread_t)my_alternative_fread; + assert((*f3)(nullptr, 0, 0, nullptr) == 22); return 0; } diff --git a/tests/unit/out/refcount/fn_ptr_stdlib_compare.rs b/tests/unit/out/refcount/fn_ptr_stdlib_compare.rs index 5c10309..178f035 100644 --- a/tests/unit/out/refcount/fn_ptr_stdlib_compare.rs +++ b/tests/unit/out/refcount/fn_ptr_stdlib_compare.rs @@ -7,24 +7,31 @@ use std::io::Seek; use std::io::{Read, Write}; use std::os::fd::AsFd; use std::rc::{Rc, Weak}; +pub fn my_alternative_fread_0(p: Ptr, n: u64, m: u64, f: AnyPtr) -> u64 { + let p: Value> = Rc::new(RefCell::new(p)); + let n: Value = Rc::new(RefCell::new(n)); + let m: Value = Rc::new(RefCell::new(m)); + let f: Value = Rc::new(RefCell::new(f)); + return 22_u64; +} pub fn main() { std::process::exit(main_0()); } fn main_0() -> i32 { - let rfn: Value) -> u64>> = + let fn1: Value) -> u64>> = Rc::new(RefCell::new(fn_ptr!( rules::stdio_tgt_refcount::f5, fn(AnyPtr, u64, u64, Ptr<::std::fs::File>) -> u64 ))); assert!({ - let _lhs = (*rfn.borrow()).clone(); + let _lhs = (*fn1.borrow()).clone(); _lhs == fn_ptr!( rules::stdio_tgt_refcount::f5, fn(AnyPtr, u64, u64, Ptr<::std::fs::File>) -> u64 ) }); - assert!(!((*rfn.borrow()).is_null())); - let rfn2: Value, u64, u64, AnyPtr) -> u64>> = Rc::new(RefCell::new( + assert!(!((*fn1.borrow()).is_null())); + let fn2: Value, u64, u64, AnyPtr) -> u64>> = Rc::new(RefCell::new( fn_ptr!( rules::stdio_tgt_refcount::f5, fn(AnyPtr, u64, u64, Ptr<::std::fs::File>) -> u64 @@ -41,9 +48,30 @@ fn main_0() -> i32 { )), )); assert!({ - let _lhs = (*rfn.borrow()).clone(); - _lhs == ((*rfn2.borrow()).cast::) -> u64>(None)) + let _lhs = (*fn1.borrow()).clone(); + _lhs == ((*fn2.borrow()).cast::) -> u64>(None)) .clone() }); + let f3: Value) -> u64>> = + Rc::new(RefCell::new( + fn_ptr!( + my_alternative_fread_0, + fn(Ptr::, u64, u64, AnyPtr) -> u64 + ) + .cast::) -> u64>(Some( + (|a0: AnyPtr, a1: u64, a2: u64, a3: Ptr<::std::fs::File>| -> u64 { + my_alternative_fread_0(a0.cast::().unwrap(), a1, a2, a3.to_any()) + }) as fn(AnyPtr, u64, u64, Ptr<::std::fs::File>) -> u64, + )), + )); + assert!( + (({ + let _arg0: AnyPtr = Default::default(); + let _arg1: u64 = 0_u64; + let _arg2: u64 = 0_u64; + let _arg3: Ptr<::std::fs::File> = Default::default(); + (*(*f3.borrow()))(_arg0, _arg1, _arg2, _arg3) + }) == 22_u64) + ); return 0; } diff --git a/tests/unit/out/unsafe/fn_ptr_stdlib_compare.rs b/tests/unit/out/unsafe/fn_ptr_stdlib_compare.rs index 432cdf5..3ff8e11 100644 --- a/tests/unit/out/unsafe/fn_ptr_stdlib_compare.rs +++ b/tests/unit/out/unsafe/fn_ptr_stdlib_compare.rs @@ -7,27 +7,49 @@ use std::io::Seek; use std::io::{Read, Write}; use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; use std::rc::Rc; +pub unsafe fn my_alternative_fread_0( + mut p: *mut u8, + mut n: u64, + mut m: u64, + mut f: *mut ::libc::c_void, +) -> u64 { + return 22_u64; +} pub fn main() { unsafe { std::process::exit(main_0() as i32); } } unsafe fn main_0() -> i32 { - let mut rfn: Option u64> = + let mut fn1: Option u64> = Some(rules::stdio_tgt_unsafe::f5); - assert!(((rfn) == (Some(rules::stdio_tgt_unsafe::f5)))); - assert!(!((rfn).is_none())); - let mut rfn2: Option u64> = + assert!(((fn1) == (Some(rules::stdio_tgt_unsafe::f5)))); + assert!(!((fn1).is_none())); + let mut fn2: Option u64> = std::mem::transmute::< Option u64>, Option u64>, >(Some(rules::stdio_tgt_unsafe::f5)); assert!( - ((rfn) + ((fn1) == (std::mem::transmute::< Option u64>, Option u64>, - >(rfn2))) + >(fn2))) + ); + let mut f3: Option u64> = + std::mem::transmute::< + Option u64>, + Option u64>, + >(Some(my_alternative_fread_0)); + assert!( + ((unsafe { + let _arg0: *mut ::libc::c_void = Default::default(); + let _arg1: u64 = 0_u64; + let _arg2: u64 = 0_u64; + let _arg3: *mut ::std::fs::File = Default::default(); + (f3).unwrap()(_arg0, _arg1, _arg2, _arg3) + }) == (22_u64)) ); return 0; } From 207106c6c5e43a1e902466ce70a796e42f6281a1 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 15 Apr 2026 15:01:06 +0100 Subject: [PATCH 34/35] Allow char*/void* <-> T* conversions in adapter --- .../converter/models/converter_refcount.cpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index d8b2b13..0a57c26 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -196,11 +196,18 @@ std::string ConverterRefCount::BuildFnAdapter( 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->isVoidPointerType()) { - closure += std::format("a{}.cast::<{}>().unwrap()", i, - GetPointeeRustType(src_pty)); - } else if (src_pty->isVoidPointerType() && tgt_pty->isPointerType()) { - closure += std::format("a{}.to_any()", i); + } else if (src_pty->isPointerType() && tgt_pty->isPointerType()) { + if (tgt_pty->isVoidPointerType()) { + closure += std::format("a{}.cast::<{}>().unwrap()", i, + GetPointeeRustType(src_pty)); + } 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, + GetPointeeRustType(src_pty)); + } else if (src_pty->getPointeeType()->isCharType()) { + closure += std::format("a{}.reinterpret_cast::()", i); + } } else { // UB: Incompatible types return "None"; From c500cff87a9252d8ba7556e676754841bccb86e3 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 15 Apr 2026 15:23:26 +0100 Subject: [PATCH 35/35] Omit enumeral types on generating default integers --- cpp2rust/converter/converter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 0df813f..6870ce9 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -2731,7 +2731,7 @@ std::string Converter::GetDefaultAsStringFallback(clang::QualType qual_type) { return "false"; } - if (qual_type->isIntegerType()) { + if (qual_type->isIntegerType() && !qual_type->isEnumeralType()) { return std::format("0_{}", ToString(qual_type)); }