diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index cf33029e6..9785efd99 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -209,21 +209,6 @@ bool Converter::VisitBuiltinType(clang::BuiltinType *type) { bool Converter::VisitRecordType(clang::RecordType *type) { auto *decl = type->getDecl(); - if (auto lambda = clang::dyn_cast(decl)) { - if (lambda->isLambda()) { - if (in_function_formals_) { - StrCat( - ConvertFunctionPointerType(lambda->getLambdaCallOperator() - ->getType() - ->getAs(), - FnProtoType::LambdaCallOperator)); - } else { - StrCat('_'); - } - return false; - } - } - StrCat(GetRecordName(decl)); Mapper::AddRuleForUserDefinedType(decl); return false; @@ -322,10 +307,8 @@ bool Converter::VisitReferenceType(clang::ReferenceType *type) { } std::string -Converter::ConvertFunctionPointerType(const clang::FunctionProtoType *proto, - FnProtoType kind) { - std::string result = - (kind == FnProtoType::LambdaCallOperator ? "impl Fn(" : "fn("); +Converter::ConvertFunctionPointerType(const clang::FunctionProtoType *proto) { + std::string result = "fn("; for (auto p_ty : proto->param_types()) { result += ToString(p_ty); result += ','; @@ -560,20 +543,6 @@ bool Converter::ConvertVarDeclSkipInit(clang::VarDecl *decl) { return true; } -bool Converter::ConvertLambdaVarDecl(clang::VarDecl *decl) { - if (decl->getType()->isFunctionPointerType()) { - return false; - } - if (decl->hasInit()) { - if (clang::isa( - decl->getInit()->IgnoreUnlessSpelledInSource())) { - // Lambdas are inlined at the call site. - return true; - } - } - return false; -} - void Converter::ConvertVarDeclInitializer(clang::VarDecl *decl) { if (decl->hasInit()) { ConvertVarInit(decl->getType(), decl->getInit()); @@ -628,10 +597,6 @@ void Converter::ConvertGlobalVarDecl(clang::VarDecl *decl) { } bool Converter::VisitVarDecl(clang::VarDecl *decl) { - if (ConvertLambdaVarDecl(decl)) { - return false; - } - if (IsGlobalVar(decl)) { ConvertGlobalVarDecl(decl); } else { @@ -961,7 +926,6 @@ void Converter::EmitRustUnion(clang::RecordDecl *decl) { bool Converter::VisitCXXRecordDecl(clang::CXXRecordDecl *decl) { decl->dump(log()); - Mapper::AddRuleForUserDefinedType(decl); if (!IsConvertibleCXXRecordDecl(decl)) { return false; @@ -991,6 +955,10 @@ bool Converter::VisitCXXRecordDecl(clang::CXXRecordDecl *decl) { DefineImplicitMembers(decl); EmitRustStructOrUnion(decl); + if (decl->isLambda()) { + AddCallableTrait(decl); + AddFunctionPointerConversion(decl); + } } else if (decl->isUnion()) { if (!record_decls_.MarkDefined(GetRecordName(decl))) { return false; @@ -1000,7 +968,6 @@ bool Converter::VisitCXXRecordDecl(clang::CXXRecordDecl *decl) { // FIXME: improve error handling assert(0 && "unsupported record kind"); } - return false; } @@ -1090,7 +1057,7 @@ bool Converter::ConvertCXXMethodDecl(clang::CXXMethodDecl *decl) { } if (method_target_ == MethodTarget::ValueImpl && - (decl->isStatic() || + (IsStaticMethod(decl) || (!decl->isVirtual() && !decl->getParent()->isAbstract()))) { ConvertFunctionQualifiers(decl); } @@ -1098,7 +1065,7 @@ bool Converter::ConvertCXXMethodDecl(clang::CXXMethodDecl *decl) { { PushParen paren(*this); - if (!decl->isStatic()) { + if (!IsStaticMethod(decl)) { StrCat(GetSelfMaybeWithMut(decl), token::kComma); } ConvertFunctionParameters(decl); @@ -2118,7 +2085,7 @@ void Converter::ConvertUserOperatorCall(clang::CXXOperatorCallExpr *expr) { auto info = CollectCallInfo(expr); EmitHoistedArgs(info); if (auto *method = clang::dyn_cast(callee)) { - if (method->isInstance()) { + if (!IsStaticMethod(method)) { SetUFCSReceiver(expr->getArg(0), false, method); } StrCat(GetUFCSName(method), token::kDoubleColon, GetMethodName(method)); @@ -2748,7 +2715,7 @@ bool Converter::IsReferenceType(const clang::Expr *expr) const { GetReturnTypeOfFunction(call)->isReferenceType(); } if (const auto *decl_ref = clang::dyn_cast(e)) { - return decl_ref->getDecl()->getType()->isReferenceType(); + return GetDeclRefType(curr_function_, decl_ref)->isReferenceType(); } if (const auto *member = clang::dyn_cast(e)) { return member->getMemberDecl()->getType()->isReferenceType(); @@ -2911,6 +2878,10 @@ bool Converter::VisitConditionalOperator(clang::ConditionalOperator *expr) { } std::string Converter::ConvertDeclRefExpr(clang::DeclRefExpr *expr) { + if (auto *field = GetLambdaCapturedField(curr_function_, expr->getDecl())) { + return std::format("{}.{}", keyword::kSelfValue, + GetNamedDeclAsString(field)); + } if (isAddrOf()) { clang::Expr *addrof_op = ToAddrOf(ctx_, expr); if (auto str = GetMappedAsString(addrof_op); !str.empty()) { @@ -2927,7 +2898,7 @@ std::string Converter::ConvertDeclRefExpr(clang::DeclRefExpr *expr) { if (auto *function = decl->getAsFunction()) { if (auto method = clang::dyn_cast(function)) { - if (method->isStatic()) { + if (IsStaticMethod(method)) { return std::format("{}::{}", GetRecordName(method->getParent()), GetNamedDeclAsString(method)); } @@ -2957,10 +2928,11 @@ std::string Converter::ConvertDeclRefExpr(clang::DeclRefExpr *expr) { bool Converter::VisitDeclRefExpr(clang::DeclRefExpr *expr) { auto str = ConvertDeclRefExpr(expr); auto decl = expr->getDecl(); + auto decl_t = GetDeclRefType(curr_function_, expr); - if (decl->getType()->getAs() && !isAddrOf() && + if (decl_t->getAs() && !isAddrOf() && !map_iter_decls_.contains(clang::dyn_cast(decl))) { - EmitDeref(std::move(str), decl->getType().getNonReferenceType()); + EmitDeref(std::move(str), decl_t.getNonReferenceType()); SetValueFreshness(expr->getType()); return false; } @@ -2975,23 +2947,8 @@ bool Converter::VisitDeclRefExpr(clang::DeclRefExpr *expr) { return false; } - if (auto var_decl = clang::dyn_cast(decl)) { - if (!var_decl->getType()->isFunctionPointerType()) { - if (auto init = var_decl->getInit()) { - if (auto lambda = clang::dyn_cast( - init->IgnoreUnlessSpelledInSource())) { - PushParen paren(*this); - VisitLambdaExpr(lambda); - computed_expr_type_ = ComputedExprType::FreshValue; - return false; - } - } - } - } - - if (!decl->getType()->getAs() && isAddrOf()) { - StrCat(token::kRef, decl->getType().isConstQualified() ? "" : keyword_mut_, - str); + if (!decl_t->getAs() && isAddrOf()) { + StrCat(token::kRef, decl_t.isConstQualified() ? "" : keyword_mut_, str); computed_expr_type_ = ComputedExprType::FreshPointer; return false; } @@ -3143,7 +3100,8 @@ bool Converter::VisitMemberExpr(clang::MemberExpr *expr) { void Converter::SetUFCSReceiver(clang::Expr *base, bool is_arrow, const clang::CXXMethodDecl *method) { - if (clang::isa(base->IgnoreParenImpCasts())) { + if (clang::isa(base->IgnoreParenImpCasts()) && + !GetLambdaOf(curr_function_)) { bool in_ctor = curr_function_ && clang::isa(curr_function_); ufcs_receiver_ = in_ctor ? "&mut this" : keyword::kSelfValue; @@ -3217,8 +3175,8 @@ void Converter::ConvertMemberExpr(clang::MemberExpr *expr) { } auto *base = expr->getBase(); - bool base_is_this = - clang::isa(base->IgnoreCasts()) && !ThisIsRustPtr(); + bool base_is_this = clang::isa(base->IgnoreCasts()) && + !ThisIsRustPtr() && !GetLambdaOf(curr_function_); PushExprKind push(*this, isLValue() ? ExprKind::LValue : ExprKind::RValue); if (base_is_this) { StrCat(clang::isa(curr_function_) @@ -3236,13 +3194,19 @@ void Converter::ConvertMemberExpr(clang::MemberExpr *expr) { StrCat(GetOverloadedFunctionName(method)); } else if (!name_override.empty()) { StrCat(token::kDot, name_override); - } else if (member->getDeclName().isIdentifier()) { + } else if (member->getDeclName().isIdentifier() || + clang::isa(member)) { StrCat(token::kDot); StrCat(GetNamedDeclAsString(member)); } } bool Converter::VisitCXXThisExpr(clang::CXXThisExpr *expr) { + if (GetLambdaOf(curr_function_)) { + StrCat(keyword::kSelfValue, token::kDot, token::kLambdaThisCapture); + computed_expr_type_ = ComputedExprType::Pointer; + return false; + } if (clang::isa(curr_function_)) { StrCat("&raw mut this"); } else { @@ -3672,24 +3636,84 @@ bool Converter::VisitConstantExpr(clang::ConstantExpr *expr) { } bool Converter::VisitLambdaExpr(clang::LambdaExpr *expr) { - if (isAddrOf() && expr->capture_size() == 0) { - StrCat("Some"); - } + auto *record = expr->getLambdaClass(); + { + Buffer buf(*this); + VisitCXXRecordDecl(record); + hoisted_records_ += std::move(buf).str(); + } + auto *init_list = new (ctx_) clang::InitListExpr( + ctx_, {}, + llvm::ArrayRef(expr->capture_init_begin(), expr->capture_size()), {}, + false); + init_list->setType(expr->getType()); PushParen paren(*this); - StrCat('|'); - for (auto p : expr->getLambdaClass()->getLambdaCallOperator()->parameters()) { - StrCat(GetNamedDeclAsString(p), token::kColon, ToString(p->getType()), - token::kComma); - } - StrCat("| {"); - EmitFunctionPreamble(expr->getLambdaClass()->getLambdaCallOperator()); - PushCurrFunction push_fn(*this, - expr->getLambdaClass()->getLambdaCallOperator()); - ConvertFunctionBody(curr_function_); - StrCat('}'); + Convert(init_list); return false; } +static constexpr unsigned kMaxCallableArity = 3; + +void Converter::AddCallableTrait(clang::CXXRecordDecl *decl) { + auto *op = decl->getLambdaCallOperator(); + ENSURE(op->getNumParams() <= kMaxCallableArity); + if (!op->isConst()) { + return; + } + auto ret = op->getReturnType()->isVoidType() ? std::string("()") + : ToString(op->getReturnType()); + StrCat(keyword::kImpl, std::format("Callable{}", op->getNumParams())); + { + PushAngle angle(*this); + for (auto *p : op->parameters()) { + StrCat(ToString(p->getType()), token::kComma); + } + StrCat(ret); + } + StrCat("for", GetRecordName(decl)); + PushBrace impl_brace(*this); + StrCat(keyword::kFn, "call"); + { + PushParen paren(*this); + StrCat("&self,"); + for (unsigned i = 0; auto *p : op->parameters()) { + StrCat(std::format("a{}:", ++i), ToString(p->getType()), token::kComma); + } + } + StrCat(token::kArrow, ret); + PushBrace fn_brace(*this); + StrCat(keyword_unsafe_); + PushBrace unsafe_brace(*this); + StrCat(GetUFCSName(op), token::kDoubleColon, GetMethodName(op)); + PushParen call_paren(*this); + if (!IsStaticMethod(op)) { + StrCat("self,"); + } + for (unsigned i = 0; i < op->getNumParams(); ++i) { + StrCat(std::format("a{},", i + 1)); + } +} + +std::string +Converter::ConvertLambdaToFunctionPointer(const clang::CXXMethodDecl *op) { + return std::format("Some({}::{})", GetUFCSName(op), GetMethodName(op)); +} + +void Converter::AddFunctionPointerConversion(clang::CXXRecordDecl *decl) { + for (auto *method : decl->methods()) { + auto *conv = clang::dyn_cast(method); + if (!conv) { + continue; + } + StrCat(keyword::kImpl, GetRecordName(decl)); + PushBrace impl_brace(*this); + StrCat("pub fn", GetMethodName(conv), "(&self)", token::kArrow, + ToString(conv->getConversionType())); + PushBrace fn_brace(*this); + StrCat(ConvertLambdaToFunctionPointer(decl->getLambdaCallOperator())); + } +} + bool Converter::VisitImplicitValueInitExpr(clang::ImplicitValueInitExpr *expr) { if (auto arr_ty = clang::dyn_cast( expr->getType()->getCanonicalTypeInternal().getTypePtr())) { @@ -4102,15 +4126,6 @@ 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); - PushInitType init_type(*this, qual_type); - VisitLambdaExpr(lambda); - return; - } - } auto *ignore_casts = expr->IgnoreCasts(); // FIXME: this looks very complicated if (auto *ctor = clang::dyn_cast(ignore_casts); diff --git a/cpp2rust/converter/converter.h b/cpp2rust/converter/converter.h index 9387ee749..bdc20efdc 100644 --- a/cpp2rust/converter/converter.h +++ b/cpp2rust/converter/converter.h @@ -69,11 +69,8 @@ class Converter : public clang::RecursiveASTVisitor { virtual bool VisitPointerType(clang::PointerType *type); - enum class FnProtoType { LambdaCallOperator, FnPtr }; - virtual std::string - ConvertFunctionPointerType(const clang::FunctionProtoType *proto, - FnProtoType kind = FnProtoType::FnPtr); + ConvertFunctionPointerType(const clang::FunctionProtoType *proto); virtual bool VisitDecayedType(clang::DecayedType *type); @@ -115,8 +112,6 @@ class Converter : public clang::RecursiveASTVisitor { virtual bool ConvertVarDeclSkipInit(clang::VarDecl *decl); - virtual bool ConvertLambdaVarDecl(clang::VarDecl *decl); - bool VisitRecordDecl(clang::RecordDecl *decl); virtual bool VisitCXXRecordDecl(clang::CXXRecordDecl *decl); @@ -432,6 +427,13 @@ class Converter : public clang::RecursiveASTVisitor { virtual bool VisitLambdaExpr(clang::LambdaExpr *expr); + virtual void AddCallableTrait(clang::CXXRecordDecl *decl); + + virtual void AddFunctionPointerConversion(clang::CXXRecordDecl *decl); + + virtual std::string + ConvertLambdaToFunctionPointer(const clang::CXXMethodDecl *op); + virtual bool VisitImplicitValueInitExpr(clang::ImplicitValueInitExpr *expr); virtual bool VisitCXXScalarValueInitExpr(clang::CXXScalarValueInitExpr *expr); @@ -510,6 +512,7 @@ class Converter : public clang::RecursiveASTVisitor { PushDelim; using PushParen = PushDelim; using PushBracket = PushDelim; + using PushAngle = PushDelim; using PushLazyType = PushDelim; using PushLazyInit = PushDelim; diff --git a/cpp2rust/converter/converter_lib.cpp b/cpp2rust/converter/converter_lib.cpp index 0dbb2fd11..cd0466462 100644 --- a/cpp2rust/converter/converter_lib.cpp +++ b/cpp2rust/converter/converter_lib.cpp @@ -153,7 +153,9 @@ bool IsUserDefinedDecl(const clang::Decl *decl) { const auto &ctx = decl->getASTContext(); const auto &src_mgr = ctx.getSourceManager(); const auto src_loc = decl->getLocation(); - return !decl->getBeginLoc().isInvalid() && !decl->isImplicit() && + auto *cxx = clang::dyn_cast(decl); + bool implicit = decl->isImplicit() && !(cxx && cxx->isLambda()); + return !decl->getBeginLoc().isInvalid() && !implicit && !src_mgr.isInSystemHeader(src_loc) && !src_mgr.isInSystemMacro(src_loc); } @@ -352,6 +354,15 @@ bool HasDefaultedCopyConstructor(const clang::RecordDecl *decl) { return !cxx->defaultedCopyConstructorIsDeleted(); } +bool RecordHasOnlyReferenceFields(const clang::RecordDecl *decl) { + for (auto *field : decl->fields()) { + if (!field->getType()->isReferenceType()) { + return false; + } + } + return true; +} + bool HasDefaultedCopyAssignment(const clang::RecordDecl *decl) { auto *cxx = clang::dyn_cast(decl); if (!cxx) { @@ -395,6 +406,9 @@ bool IsPassThroughConstructor(const clang::CXXConstructorDecl *ctor) { } bool IsConvertibleCXXRecordDecl(const clang::CXXRecordDecl *decl) { + if (decl->isLambda()) { + return decl->getLambdaCallOperator()->hasBody(); + } return decl->isThisDeclarationADefinition() && std::all_of( decl->method_begin(), decl->method_end(), [](auto *method) { @@ -640,6 +654,51 @@ static size_t GetDeclId(const clang::NamedDecl *decl, bool internal) { return type_mapping.try_emplace(key, type_mapping.size()).first->second; } +const clang::LambdaCapture *GetLambdaCapture(const clang::FieldDecl *field) { + auto *cxx = clang::dyn_cast(field->getParent()); + if (!cxx || !cxx->isLambda()) { + return nullptr; + } + auto capture = cxx->captures_begin(); + for (auto *f : cxx->fields()) { + assert(capture != cxx->captures_end()); + if (f == field) { + return capture; + } + ++capture; + } + assert(0 && "field is not a lambda capture"); + return nullptr; +} + +const clang::CXXRecordDecl *GetLambdaOf(const clang::FunctionDecl *fn) { + auto *method = clang::dyn_cast_or_null(fn); + if (!method || !method->getParent()->isLambda()) { + return nullptr; + } + return method->getParent(); +} + +clang::FieldDecl *GetLambdaCapturedField(const clang::FunctionDecl *fn, + const clang::ValueDecl *var) { + auto *lambda = GetLambdaOf(fn); + if (!lambda) { + return nullptr; + } + llvm::DenseMap captures; + clang::FieldDecl *this_capture = nullptr; + lambda->getCaptureFields(captures, this_capture); + auto it = captures.find(var); + return it == captures.end() ? nullptr : it->second; +} + +clang::QualType GetDeclRefType(const clang::FunctionDecl *fn, + const clang::DeclRefExpr *expr) { + auto *decl = expr->getDecl(); + auto *field = GetLambdaCapturedField(fn, decl); + return field ? field->getType() : decl->getType(); +} + std::string GetNamedDeclAsString(const clang::NamedDecl *decl) { auto name = decl->getDeclName().isIdentifier() ? decl->getName().str() : decl->getNameAsString(); @@ -647,6 +706,21 @@ std::string GetNamedDeclAsString(const clang::NamedDecl *decl) { name = GetFunctionBaseName(fn); } + if (auto *cxx = clang::dyn_cast(decl); + cxx && cxx->isLambda()) { + return std::format("lambda_{}", + type_mapping.try_emplace(GetID(cxx), type_mapping.size()) + .first->second); + } + if (auto *field = clang::dyn_cast(decl)) { + if (auto *capture = GetLambdaCapture(field)) { + if (capture->capturesThis()) { + return token::kLambdaThisCapture; + } + return GetNamedDeclAsString(capture->getCapturedVar()); + } + } + // Anonymous record or enum if (name.empty() && (clang::isa(decl) || clang::isa(decl) || @@ -887,17 +961,14 @@ bool IsUserOperatorCall(const clang::CXXOperatorCallExpr *expr) { method && IsConvertibleMoveAssignment(method)) { return true; } - if (!callee->isUserProvided() || !IsUserDefinedDecl(callee)) { - return false; - } - if (const auto *method = clang::dyn_cast(callee)) { - return !method->getParent()->isLambda(); - } - return true; + return callee->isUserProvided() && IsUserDefinedDecl(callee); } std::string GetFunctionBaseName(const clang::FunctionDecl *decl) { if (auto *conversion = clang::dyn_cast(decl)) { + if (conversion->getParent()->isLambda()) { + return "to_free_function"; + } auto name = "operator_" + conversion->getConversionType().getAsString(); std::replace_if( name.begin(), name.end(), [](char c) { return !std::isalnum(c); }, '_'); @@ -992,8 +1063,21 @@ bool IsEmittableMethod(clang::CXXMethodDecl *method) { clang::isa(method); } +bool IsStaticMethod(const clang::CXXMethodDecl *method) { + if (method->isStatic()) { + return true; + } + auto *parent = method->getParent(); + return parent->isLambda() && parent->getLambdaCallOperator() == method && + parent->captures().empty(); +} + bool IsMethodOnPtr(const clang::CXXMethodDecl *method) { - if (method->isDeleted() || method->isStatic() || method->isVirtual() || + if (GetLambdaOf(method) && + method->getParent()->getLambdaCallOperator() == method) { + return false; + } + if (method->isDeleted() || IsStaticMethod(method) || method->isVirtual() || clang::isa(method)) { return false; } @@ -1003,8 +1087,7 @@ bool IsMethodOnPtr(const clang::CXXMethodDecl *method) { if (method->isImplicit() && !IsComparisonOperator(method)) { return false; } - if (!IsUserDefinedDecl(method->getParent()) || - method->getParent()->isLambda()) { + if (!IsUserDefinedDecl(method->getParent())) { return false; } if (auto *definition = method->getDefinition(); diff --git a/cpp2rust/converter/converter_lib.h b/cpp2rust/converter/converter_lib.h index 709940a70..b7cd80d1d 100644 --- a/cpp2rust/converter/converter_lib.h +++ b/cpp2rust/converter/converter_lib.h @@ -83,6 +83,7 @@ bool IsConvertibleImplicitMember(const clang::CXXMethodDecl *method); clang::CXXConstructorDecl * GetUserDefinedCopyConstructor(const clang::RecordDecl *decl); +bool RecordHasOnlyReferenceFields(const clang::RecordDecl *decl); bool HasCallableCopyConstructor(const clang::RecordDecl *decl); bool HasDefaultedCopyConstructor(const clang::RecordDecl *decl); @@ -100,6 +101,7 @@ bool IsConvertibleCXXMethodDecl(const clang::CXXMethodDecl *decl); bool IsComparisonOperator(const clang::FunctionDecl *fn); bool IsEmittableMethod(clang::CXXMethodDecl *method); +bool IsStaticMethod(const clang::CXXMethodDecl *method); bool IsMethodOnPtr(const clang::CXXMethodDecl *method); bool IsConvertibleFunctionDecl(const clang::FunctionDecl *decl); @@ -172,6 +174,16 @@ bool RecordNeedsDestruction(const clang::CXXRecordDecl *decl); clang::Expr *ToAddrOf(clang::ASTContext &ctx, clang::Expr *expr); +const clang::LambdaCapture *GetLambdaCapture(const clang::FieldDecl *field); + +const clang::CXXRecordDecl *GetLambdaOf(const clang::FunctionDecl *fn); + +clang::FieldDecl *GetLambdaCapturedField(const clang::FunctionDecl *fn, + const clang::ValueDecl *var); + +clang::QualType GetDeclRefType(const clang::FunctionDecl *fn, + const clang::DeclRefExpr *expr); + clang::CXXConstructExpr *MakeConstructExpr(clang::ASTContext &ctx, clang::QualType type, clang::CXXConstructorDecl *ctor, diff --git a/cpp2rust/converter/lex.h b/cpp2rust/converter/lex.h index 93b3b4a8d..89975c16f 100644 --- a/cpp2rust/converter/lex.h +++ b/cpp2rust/converter/lex.h @@ -65,5 +65,6 @@ inline constexpr const char kMut[] = "mut"; namespace token { inline constexpr const char kDefault[] = "Default::default()"; inline constexpr const char kIgnoreRule[] = "libcc2rs::IgnoreRule"; +inline constexpr const char kLambdaThisCapture[] = "this_"; } // namespace token } // namespace cpp2rust diff --git a/cpp2rust/converter/mapper.cpp b/cpp2rust/converter/mapper.cpp index 46db4ec3c..275103d29 100644 --- a/cpp2rust/converter/mapper.cpp +++ b/cpp2rust/converter/mapper.cpp @@ -872,7 +872,7 @@ std::string ToString(clang::QualType qual_type, ScalarSugar sugar) { if (auto cxx_record_decl = qual_type->getAsCXXRecordDecl()) { if (cxx_record_decl->isLambda()) { - return ToString(cxx_record_decl->getLambdaCallOperator()); + return GetNamedDeclAsString(cxx_record_decl); } } diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index e139bf48b..13694f0c0 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -247,9 +247,9 @@ std::string ConverterRefCount::BuildFnAdapter( } std::string ConverterRefCount::ConvertFunctionPointerType( - const clang::FunctionProtoType *proto, FnProtoType kind) { + const clang::FunctionProtoType *proto) { PushConversionKind push(*this, ConversionKind::Unboxed); - return Converter::ConvertFunctionPointerType(proto, kind); + return Converter::ConvertFunctionPointerType(proto); } bool ConverterRefCount::VisitPointerType(clang::PointerType *type) { @@ -431,8 +431,8 @@ bool ConverterRefCount::VisitCXXRecordDecl(clang::CXXRecordDecl *decl) { if (decl_ids_.count(GetID(decl))) { return false; } - Converter::VisitCXXRecordDecl(decl); - return false; + PushConversionKind push(*this, ConversionKind::Unboxed); + return Converter::VisitCXXRecordDecl(decl); } bool ConverterRefCount::VisitOffsetOfExpr(clang::OffsetOfExpr *expr) { @@ -480,8 +480,14 @@ void ConverterRefCount::AddCloneTrait(const clang::RecordDecl *decl) { return; } + if (HasDefaultedCopyConstructor(decl) && RecordHasOnlyReferenceFields(decl)) { + return; + } auto *cxx = clang::dyn_cast(decl); - if (!cxx) { + if (cxx && cxx->isLambda() && !HasCallableCopyConstructor(cxx)) { + return; + } + if (!cxx || cxx->isLambda()) { StrCat(keyword::kImpl, "Clone for", record_name); PushBrace impl_brace(*this); StrCat("fn clone(&self) -> Self"); @@ -490,6 +496,10 @@ void ConverterRefCount::AddCloneTrait(const clang::RecordDecl *decl) { PushBrace init_brace(*this); for (auto *field : decl->fields()) { auto name = GetNamedDeclAsString(field); + if (field->getType()->isReferenceType()) { + StrCat(std::format("{0}: self.{0}.clone(),", name)); + continue; + } StrCat(std::format( "{0}: Rc::new(RefCell::new((*self.{0}.borrow()).clone())),", name)); } @@ -691,10 +701,6 @@ void ConverterRefCount::ConvertVaListVarDecl(clang::VarDecl *decl) { StrCat(GetNamedDeclAsString(decl), token::kColon, "Value"); } -bool ConverterRefCount::ConvertLambdaVarDecl(clang::VarDecl *decl) { - return false; -} - bool ConverterRefCount::ConvertVarDeclSkipInit(clang::VarDecl *decl) { bool unboxed = in_function_formals_; PushConversionKind push(*this, unboxed ? ConversionKind::Unboxed @@ -852,7 +858,7 @@ bool ConverterRefCount::VisitDeclRefExpr(clang::DeclRefExpr *expr) { return false; } - const auto decl_t = decl->getType(); + const auto decl_t = GetDeclRefType(curr_function_, expr); bool is_global_value = false, is_global_ptr = false; if (IsGlobalVar(expr)) { if (decl_t->isReferenceType()) { @@ -2115,6 +2121,10 @@ ConverterRefCount::GetStructAttributes(const clang::RecordDecl *decl) { return attrs; } + if (HasDefaultedCopyConstructor(decl) && RecordHasOnlyReferenceFields(decl)) { + attrs.emplace_back("Clone"); + } + if (RecordDerivesDefault(decl)) { attrs.emplace_back("Default"); } @@ -2123,20 +2133,6 @@ ConverterRefCount::GetStructAttributes(const clang::RecordDecl *decl) { std::string ConverterRefCount::ConvertVarInitValue(clang::QualType qual_type, clang::Expr *expr) { - if (auto lambda = clang::dyn_cast( - expr->IgnoreUnlessSpelledInSource())) { - Buffer buf(*this); - PushConversionKind push(*this, ConversionKind::Unboxed); - if (qual_type->isFunctionPointerType() && lambda->capture_size() == 0) { - StrCat("FnPtr::new("); - VisitLambdaExpr(lambda); - StrCat(')'); - } else { - VisitLambdaExpr(lambda); - } - return std::move(buf).str(); - } - PushInitType init_type(*this, qual_type); if (qual_type->isReferenceType() || qual_type->isFunctionPointerType()) { if (llvm::isa(expr->IgnoreImpCasts())) { @@ -2727,7 +2723,8 @@ void ConverterRefCount::SetUFCSReceiver(clang::Expr *base, bool is_arrow, } bool base_is_pointer = is_arrow && !clang::isa( base->IgnoreParenImpCasts()); - if (clang::isa(base->IgnoreParenImpCasts())) { + if (clang::isa(base->IgnoreParenImpCasts()) && + !GetLambdaOf(curr_function_)) { bool in_ctor = curr_function_ && clang::isa(curr_function_); if (in_ctor) { @@ -2903,8 +2900,13 @@ void ConverterRefCount::ConvertCXXConstructorBody( StrCat("Rc::try_unwrap(__this).ok().unwrap().into_inner()"); } -bool ConverterRefCount::VisitCXXThisExpr( - [[maybe_unused]] clang::CXXThisExpr *expr) { +bool ConverterRefCount::VisitCXXThisExpr(clang::CXXThisExpr *expr) { + if (GetLambdaOf(curr_function_)) { + StrCat("(*", keyword::kSelfValue, token::kDot, token::kLambdaThisCapture, + ".borrow())"); + computed_expr_type_ = ComputedExprType::Pointer; + return false; + } bool in_ctor = curr_function_ && clang::isa(curr_function_); if (in_ctor) { @@ -2915,4 +2917,21 @@ bool ConverterRefCount::VisitCXXThisExpr( computed_expr_type_ = ComputedExprType::Pointer; return false; } + +void ConverterRefCount::AddCallableTrait(clang::CXXRecordDecl *decl) { + PushConversionKind push(*this, ConversionKind::Unboxed); + Converter::AddCallableTrait(decl); +} + +void ConverterRefCount::AddFunctionPointerConversion( + clang::CXXRecordDecl *decl) { + PushConversionKind push(*this, ConversionKind::Unboxed); + Converter::AddFunctionPointerConversion(decl); +} + +std::string ConverterRefCount::ConvertLambdaToFunctionPointer( + const clang::CXXMethodDecl *op) { + return std::format("FnPtr::new({}::{})", GetUFCSName(op), GetMethodName(op)); +} + } // namespace cpp2rust diff --git a/cpp2rust/converter/models/converter_refcount.h b/cpp2rust/converter/models/converter_refcount.h index 41fa971a0..59316e336 100644 --- a/cpp2rust/converter/models/converter_refcount.h +++ b/cpp2rust/converter/models/converter_refcount.h @@ -23,8 +23,7 @@ class ConverterRefCount final : public Converter { bool VisitPointerType(clang::PointerType *type) override; std::string - ConvertFunctionPointerType(const clang::FunctionProtoType *proto, - FnProtoType kind = FnProtoType::FnPtr) override; + ConvertFunctionPointerType(const clang::FunctionProtoType *proto) override; bool VisitCXXRecordDecl(clang::CXXRecordDecl *decl) override; @@ -90,7 +89,12 @@ class ConverterRefCount final : public Converter { void EmitHoistedInArmAssignment(clang::VarDecl *decl) override; - bool ConvertLambdaVarDecl(clang::VarDecl *decl) override; + void AddCallableTrait(clang::CXXRecordDecl *decl) override; + + void AddFunctionPointerConversion(clang::CXXRecordDecl *decl) override; + + std::string + ConvertLambdaToFunctionPointer(const clang::CXXMethodDecl *op) override; bool VisitDeclRefExpr(clang::DeclRefExpr *expr) override; diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index 690d9dca8..6cd722a45 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -31,6 +31,7 @@ - [Increment and Decrement](./runtime/inc-dec.md) - [Iterators](./runtime/iterators.md) - [Function Pointers](./runtime/fn-ptr.md) +- [Callable](./runtime/callable.md) - [Variadic Functions](./runtime/va-args.md) - [Control Flow Macros](./runtime/control-flow.md) - [I/O and Formatting](./runtime/io.md) diff --git a/docs/src/codegen/types/fn-pointers.md b/docs/src/codegen/types/fn-pointers.md index 5d9880fd9..d8d57c0d5 100644 --- a/docs/src/codegen/types/fn-pointers.md +++ b/docs/src/codegen/types/fn-pointers.md @@ -71,4 +71,5 @@ in a variable clones it, and equality compares the address of the wrapped function, so a pointer stays equal to itself after being cast. A capture-less lambda assigned to a function pointer becomes -`FnPtr::new(|...| ...)` with the closure inline (see [Lambdas](./lambdas.md)). +`lambda_N::to_free_function()`, which returns +`FnPtr::new(lambda_N::operator_call)` (see [Lambdas](./lambdas.md)). diff --git a/docs/src/codegen/types/lambdas.md b/docs/src/codegen/types/lambdas.md index 1f3743c9f..bd7e4314f 100644 --- a/docs/src/codegen/types/lambdas.md +++ b/docs/src/codegen/types/lambdas.md @@ -1,7 +1,9 @@ # Lambdas -A lambda becomes a Rust closure with the same parameters and a translated body. -Given +A lambda becomes a struct with one field per capture, an inherent +`operator_call` method holding the translated body, a `Callable` impl so generic +code can invoke it, and, for a capture-less lambda, a `to_free_function` +associated method that yields it as a function pointer. Given ```cpp template int apply(F fn, int x) { return fn(x); } @@ -16,76 +18,125 @@ int main() { the unsafe model produces ```rust -pub unsafe fn apply_0(mut fn_: impl Fn(i32) -> i32, mut x: i32) -> i32 { - return fn_(x); +pub unsafe fn apply_0(mut fn_: lambda_1, mut x: i32) -> i32 { + return (unsafe { lambda_1::operator_call(&fn_, x) }); } unsafe fn main_0() -> i32 { let mut base: i32 = 10; - return apply_0( - (|x: i32| { - return x + base; - }) - .clone(), - 5, - ); + let mut add_base: lambda_1 = (lambda_1 { base: &mut base }); + return (unsafe { apply_0(add_base, 5) }); +} +pub struct lambda_1 { + base: *mut i32, +} +impl lambda_1 { + pub unsafe fn operator_call(&self, mut x: i32) -> i32 { + return ((x) + (*self.base)); + } +} +impl Callable1 for lambda_1 { + fn call(&self, a1: i32) -> i32 { + unsafe { lambda_1::operator_call(self, a1) } + } } ``` and the refcount model produces ```rust -pub fn apply_0(fn_: impl Fn(i32) -> i32, x: i32) -> i32 { - let fn_: Value<_> = Rc::new(RefCell::new(fn_)); +pub fn apply_0(fn_: lambda_1, x: i32) -> i32 { + let fn_: Value = Rc::new(RefCell::new(fn_)); let x: Value = Rc::new(RefCell::new(x)); - return (*fn_.borrow_mut())(*x.borrow()); + return ({ lambda_1::operator_call(&(*fn_.borrow_mut()), (*x.borrow())) }); } 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(); + let add_base: Value = Rc::new(RefCell::new( + (lambda_1 { + base: base.as_pointer(), }), )); - return apply_0((*add_base.borrow()).clone(), 5); + return ({ apply_0((*add_base.borrow()).clone(), 5) }); +} +pub struct lambda_1 { + base: Ptr, +} +impl lambda_1 { + pub fn operator_call(&self, x: i32) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + return ((*x.borrow()) + (self.base.read())); + } +} +impl Callable1 for lambda_1 { + fn call(&self, a1: i32) -> i32 { + { lambda_1::operator_call(self, a1) } + } } ``` -## Closure and type +## Closure struct + +The closure type is named `lambda_N`, numbered in order of appearance, and is +emitted at file scope. Each capture becomes a field named after the captured +variable, typed as the capture field of clang's closure class: + +| Capture | C++ field type | Unsafe | Refcount | +| -------- | -------------- | ------------- | --------------- | +| `[x]` | `T` | `T` | `Value` | +| `[&x]` | `T&` | `*mut T` | `Ptr` | +| `[&arr]` | `T (&)[N]` | `*mut [T; N]` | `Ptr>` | +| `[this]` | `S*` | `*mut S` | `Value>` | -The closure lists the lambda's parameters with their translated types and -contains the body converted like a function body, including, in the refcount -model, the preamble that boxes each parameter. The lambda's own type is never -spelled: a variable holding one is `Value<_>` in the refcount model and the type -is inferred, and a function template parameter that receives one is -`impl Fn(A) -> R`, as `apply` shows. A call through such a parameter is a plain -call, `fn_(x)`, with the refcount model borrowing the boxed closure first. +The struct follows the same trait rules as an ordinary struct, described in +[Traits](./traits.md). + +The lambda expression itself becomes a struct literal. A by-value capture copies +the variable at that point, a by-reference capture takes its address, so C++'s +distinction between `[x]` and `[&x]` is preserved: the first never sees later +writes to `x`, the second does. ## Captures -The C++ capture list is not translated. A Rust closure captures whatever it -mentions by reference, so `[&base]` and `[base]` produce the same closure and -both see the variable's current value at call time. For a by-reference capture -this is C++'s semantics; for a by-value capture it is not, since C++ copies the -variable when the lambda is created. - -## Where the closure is emitted - -The refcount model emits a variable initialized with a lambda as a boxed closure -once and clones it out of the box at each use. - -> [!WARNING] -> -> The unsafe model does not emit a `let` for such a variable; the closure is -> emitted again at every use, which is why the example above shows it inline in -> the `apply_0` call. This was a workaround: a stored closure that captures -> locals by reference keeps them borrowed for as long as it lives, so -> `let foo = || { a += 1; a }; return foo() + a;` does not compile, while -> re-emitting the closure at each call keeps every borrow inside that call. It -> is a bug, since the lambda's creation and its uses are no longer the same -> object ([#314](https://github.com/Cpp2Rust/cpp2rust/issues/314)). - -A capture-less lambda assigned to a function pointer becomes a function pointer -value: `Some(|...| ...)` in the unsafe model and `FnPtr::new(|...| ...)` in the -refcount model (see [Function Pointers](./fn-pointers.md)). Lambdas with -captures cannot be converted to function pointers, as in C++. +Explicit, implicit and init-captures all translate the same way, because clang +materializes every capture as a closure field before the converter runs. `[=]` +and `[&]` produce one field per variable the body mentions, and `[y = x + 1]` +produces a field `y` whose value in the struct literal is the initializer +expression, evaluated where the lambda expression appears. + +A captured `this` becomes a field named `this_`. A use of `this` in the body, +explicit or implied by a member access, reads that field: `self.this_` in the +unsafe model, `(*self.this_.borrow())` in the refcount model. From there member +access and method calls proceed as through any other pointer to the enclosing +class. + +## Call operator + +The body is emitted as `operator_call` on the closure struct. Its receiver +follows the C++ call operator: + +- `&self` for an ordinary lambda, whose call operator is `const`; +- `&mut self` for a `mutable` lambda, so writes to by-value captures persist + across calls; +- no receiver for a capture-less lambda, which makes `operator_call` a plain + associated function. + +## Callable + +A lambda whose call operator is `const` also implements +[`Callable`](../../runtime/callable.md), so it can be passed to rules and +helpers that take a callable argument. + +## Conversion to function pointer + +A capture-less lambda has a conversion operator to function pointer. It becomes +a `to_free_function` method that returns the call operator as a function pointer +value: `Some(lambda_N::operator_call)` in the unsafe model and +`FnPtr::new(lambda_N::operator_call)` in the refcount model (see +[Function Pointers](./fn-pointers.md)). Assigning or passing such a lambda where +a function pointer is expected calls `to_free_function` on the closure object. + +## Where the struct is emitted + +The struct and its impls are hoisted to file scope after the enclosing top-level +declaration, so the function body keeps only the struct literal instead of +several items of boilerplate. diff --git a/docs/src/codegen/types/mappings.md b/docs/src/codegen/types/mappings.md index 02bd111b5..8f2ce203d 100644 --- a/docs/src/codegen/types/mappings.md +++ b/docs/src/codegen/types/mappings.md @@ -3,24 +3,24 @@ The table gives the spelling of each C++ type in both models, before any refcount boxing. `T` stands for the translated inner type. -| C++ | Unsafe model | Refcount model | -| ------------------------------ | ----------------------------------------------- | --------------------------------------------------------- | -| `bool` | `bool` | `bool` | -| `int`, `unsigned long`, ... | `i32`, `u64`, ... (host width) | same | -| `float`, `double` | `f32`, `f64` | same | -| `char` | `libc::c_char` | `u8` | -| `size_t` and other typedefs | by type rule (`usize`), else desugared | same | -| `T[N]` | `[T; N]` | `Box<[T]>` | -| `T[]` | `[T]` | `Box<[T]>` | -| `struct S`, `enum E` | `S`, `E` | same | -| `T *`, `T &` | `*mut T`, `*const T` | [`Ptr`](../../runtime/rc.md#values-and-pointers) | -| `Abstract *` | `*mut dyn Abstract` | [`PtrDyn`](../../runtime/ptr-dyn.md) | -| `void *` | `*mut ::libc::c_void` | [`AnyPtr`](../../runtime/void.md) | -| `R (*)(A)` | `Option R>` | [`FnPtr R>`](../../runtime/fn-ptr.md) | -| `va_list` | [`VaList`](../../runtime/va-args.md) | [`VaList`](../../runtime/va-args.md) | -| lambda closure | `impl Fn(A) -> R` as a parameter, `_` elsewhere | same | -| `std::unique_ptr` | by type rule (`Option>`) | by type rule (`Option>`) | -| `std::vector` and other STL | by type rule (`Vec`) | by type rule (`Vec`, `Vec>>` when nested) | +| C++ | Unsafe model | Refcount model | +| ------------------------------ | -------------------------------------- | --------------------------------------------------------- | +| `bool` | `bool` | `bool` | +| `int`, `unsigned long`, ... | `i32`, `u64`, ... (host width) | same | +| `float`, `double` | `f32`, `f64` | same | +| `char` | `libc::c_char` | `u8` | +| `size_t` and other typedefs | by type rule (`usize`), else desugared | same | +| `T[N]` | `[T; N]` | `Box<[T]>` | +| `T[]` | `[T]` | `Box<[T]>` | +| `struct S`, `enum E` | `S`, `E` | same | +| `T *`, `T &` | `*mut T`, `*const T` | [`Ptr`](../../runtime/rc.md#values-and-pointers) | +| `Abstract *` | `*mut dyn Abstract` | [`PtrDyn`](../../runtime/ptr-dyn.md) | +| `void *` | `*mut ::libc::c_void` | [`AnyPtr`](../../runtime/void.md) | +| `R (*)(A)` | `Option R>` | [`FnPtr R>`](../../runtime/fn-ptr.md) | +| `va_list` | [`VaList`](../../runtime/va-args.md) | [`VaList`](../../runtime/va-args.md) | +| lambda closure | [`lambda_N` struct](./lambdas.md) | same | +| `std::unique_ptr` | by type rule (`Option>`) | by type rule (`Option>`) | +| `std::vector` and other STL | by type rule (`Vec`) | by type rule (`Vec`, `Vec>>` when nested) | Other built-ins (`wchar_t`, `long double`, `char16_t`) are omitted. Rvalue references (`T &&`) have no mapping of their own; they reach the converter only diff --git a/docs/src/rules/writing-rules.md b/docs/src/rules/writing-rules.md index 1bd7b9ef8..c2d42a161 100644 --- a/docs/src/rules/writing-rules.md +++ b/docs/src/rules/writing-rules.md @@ -133,30 +133,32 @@ accesses are rules of their own, matched by the field: `it->first` and ## Callable arguments -A rule parameter may be a callable. Function pointers are spelled directly; for -a lambda, whose type cannot be written, the rule declares a file-scope lambda -and takes `decltype(lambda)`: +A rule parameter may be a callable: a function pointer, a functor or a lambda. +The source side takes it through a helper type, and the target side binds the +corresponding generic parameter with `Callable`: ```cpp // rules/algorithm/src.cpp -auto lambda = [](const T2 &a, const T2 &b) { return false; }; -void f6(T1 first, T1 last, decltype(lambda) comp) { +void f6(T1 first, T1 last, T2 comp) { return std::stable_sort(first, last, comp); } ``` ```rust // rules/algorithm/tgt_unsafe.rs -unsafe fn f6(a0: *mut T1, a1: *mut T1, a2: &mut T2) +unsafe fn f6(a0: *mut T1, a1: *mut T1, a2: T2) where - T2: FnMut(&T1, &T1) -> bool, -{ ... } + T2: Callable2<*const T1, *const T1, bool>, +{ ... a2.call(x, y) ... } ``` +The bound is [`Callable`](../runtime/callable.md) rather than `Fn` so that one +rule serves every kind of callable argument, including translated lambdas, which +are structs and cannot implement `Fn`. + `T1` and `T2` are not template parameters here but file-scope helper structs modelling an iterator and its value type; being named like generics, they bind -as `T1`/`T2` at the use site. The function pointer version of the comparator is -a separate rule (`f7`). +as `T1`/`T2` at the use site. ## Iterators diff --git a/docs/src/runtime/callable.md b/docs/src/runtime/callable.md new file mode 100644 index 000000000..2180eaabc --- /dev/null +++ b/docs/src/runtime/callable.md @@ -0,0 +1,52 @@ +# Callable + +In C++ a function pointer, a functor (a user-defined struct with `operator()`) +and a lambda are all called the same way, `f(x)`, and a template parameter +accepts any of them. Rust has the `Fn` traits for that role, but only closures +and safe `fn` items implement them; a user struct or an `unsafe fn` cannot. +`libcc2rs` therefore provides its own call trait, one per arity: + +```rust +pub trait Callable0 { fn call(&self) -> R; } +pub trait Callable1 { fn call(&self, a1: A1) -> R; } +pub trait Callable2 { fn call(&self, a1: A1, a2: A2) -> R; } +pub trait Callable3 { fn call(&self, a1: A1, a2: A2, a3: A3) -> R; } +``` + +Three kinds of value implement it: + +- safe `fn` items, through a blanket impl for every type implementing the + matching `Fn`; +- `unsafe fn` pointers, through a second blanket impl that wraps the call in an + `unsafe` block; +- [translated lambdas](../codegen/types/lambdas.md), through a call to + `operator_call`. + +Code written against a `CallableK` bound invokes any of them through +`.call(..)`. This is how the STL algorithm rules take their comparators: + +```rust +fn f6(a0: Ptr, a1: Ptr, a2: T2) +where + T2: Callable2, Ptr, bool>, +{ + a0.sort_with_cmp(a1.get_offset(), |x, y| a2.call(x, y)) +} +``` + +## Why not `Fn` + +Implementing `Fn`, `FnMut` or `FnOnce` for a user type needs the +`unboxed_closures` and `fn_traits` features, which are +[nightly-only](https://github.com/rust-lang/rust/issues/29625). + +## Notes + +There is one trait per arity, `Callable0` to `Callable3`, rather than a single +trait over a tuple of arguments, so that a call is written `call(x, y)` and not +`call((x, y))`. + +`call` takes `&self`, so only callables with a `const` call operator can +implement the trait. A `mutable` lambda, whose `operator_call` takes +`&mut self`, gets no `Callable` impl. This is a limitation of the trait +definition, not of the lambda translation. diff --git a/docs/src/runtime/overview.md b/docs/src/runtime/overview.md index c52c9e487..aabf51a6d 100644 --- a/docs/src/runtime/overview.md +++ b/docs/src/runtime/overview.md @@ -46,6 +46,8 @@ Language-feature emulation, used by both models: strings up to the null terminator. - [`fn_ptr`](./fn-ptr.md): `FnPtr`, function pointers with C-style address identity. +- [`callable`](./callable.md): `Callable0` to `Callable3`, the call trait for + translated lambdas. - [`va_args`](./va-args.md): `VaArg` and `VaList`, the representation of variadic calls. - The [`goto`, `goto_block`, and `switch`](./control-flow.md) proc macros, diff --git a/tests/ub/out/refcount/ctor_ref_member.rs b/tests/ub/out/refcount/ctor_ref_member.rs index 485688a0f..7cde83873 100644 --- a/tests/ub/out/refcount/ctor_ref_member.rs +++ b/tests/ub/out/refcount/ctor_ref_member.rs @@ -6,7 +6,7 @@ use std::io::prelude::*; use std::io::{Read, Seek, Write}; use std::os::fd::AsFd; use std::rc::{Rc, Weak}; -#[derive(Default)] +#[derive(Clone, Default)] pub struct S { pub r: Ptr, } @@ -17,15 +17,6 @@ impl S { Rc::try_unwrap(__this).ok().unwrap().into_inner() } } -impl Clone for S { - fn clone(&self) -> Self { - let __this: Value = Rc::new(RefCell::new(Self { - r: (self.r).clone(), - })); - let this: Ptr = __this.as_pointer(); - Rc::try_unwrap(__this).ok().unwrap().into_inner() - } -} impl ByteRepr for S {} pub fn main() { __cpp2rust_init_globals(); diff --git a/tests/ub/out/refcount/ub6.rs b/tests/ub/out/refcount/ub6.rs index ad4b8c8fd..aa8222876 100644 --- a/tests/ub/out/refcount/ub6.rs +++ b/tests/ub/out/refcount/ub6.rs @@ -6,21 +6,11 @@ use std::io::prelude::*; use std::io::{Read, Seek, Write}; use std::os::fd::AsFd; use std::rc::{Rc, Weak}; -#[derive(Default)] +#[derive(Clone, Default)] pub struct Pair { pub x1: Ptr, pub x2: Ptr, } -impl Clone for Pair { - fn clone(&self) -> Self { - let __this: Value = Rc::new(RefCell::new(Self { - x1: (self.x1).clone(), - x2: (self.x2).clone(), - })); - let this: Ptr = __this.as_pointer(); - Rc::try_unwrap(__this).ok().unwrap().into_inner() - } -} impl ByteRepr for Pair {} pub fn mkPair_0(x1: Ptr, x2: Ptr) -> Pair { return Pair { diff --git a/tests/unit/lambda_capture_pass.cpp b/tests/unit/lambda_as_template_argument.cpp similarity index 69% rename from tests/unit/lambda_capture_pass.cpp rename to tests/unit/lambda_as_template_argument.cpp index 439b128c1..8bd7d83a7 100644 --- a/tests/unit/lambda_capture_pass.cpp +++ b/tests/unit/lambda_as_template_argument.cpp @@ -2,18 +2,21 @@ template int apply(F fn, int x) { return fn(x); } +template int apply_twice(F fn, int x) { return fn(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); + assert(apply_twice(scale, 4) == 36); + + assert(apply([](int x) { return -x; }, 9) == -9); return 0; } diff --git a/tests/unit/lambda_basic.cpp b/tests/unit/lambda_basic.cpp new file mode 100644 index 000000000..8996ab76f --- /dev/null +++ b/tests/unit/lambda_basic.cpp @@ -0,0 +1,25 @@ +#include + +int main() { + auto zero = []() { return 42; }; + assert(zero() == 42); + + auto one = [](int x) { return x + 1; }; + assert(one(1) == 2); + + auto three = [](int x, int y, int z) { return x * 100 + y * 10 + z; }; + assert(three(1, 2, 3) == 123); + + int hits = 0; + auto no_return = [&hits](int by) { hits += by; }; + no_return(3); + no_return(4); + assert(hits == 7); + + int a = 2; + int b = 3; + int product = [&]() { return a * b; }(); + assert(product == 6); + + return 0; +} diff --git a/tests/unit/lambda_capture_implicit.cpp b/tests/unit/lambda_capture_implicit.cpp new file mode 100644 index 000000000..293eb9072 --- /dev/null +++ b/tests/unit/lambda_capture_implicit.cpp @@ -0,0 +1,26 @@ +#include + +int main() { + int a = 1; + int b = 2; + int c = 3; + + auto by_value = [=](int x) { return a + b + c + x; }; + assert(by_value(10) == 16); + a = 100; + assert(by_value(10) == 16); + + auto by_ref = [&](int x) { return a + b + c + x; }; + assert(by_ref(10) == 115); + b = 200; + assert(by_ref(10) == 313); + + auto mixed = [=, &c](int x) { + c += x; + return a + b + c; + }; + assert(mixed(1) == 100 + 200 + 4); + assert(c == 4); + + return 0; +} diff --git a/tests/unit/lambda_capture_ref.cpp b/tests/unit/lambda_capture_ref.cpp new file mode 100644 index 000000000..761a05214 --- /dev/null +++ b/tests/unit/lambda_capture_ref.cpp @@ -0,0 +1,40 @@ +#include +#include +#include + +struct S { + int x; + int y; +}; + +int main() { + int base = 10; + auto add_base = [&base](int x) { return x + base; }; + assert(add_base(5) == 15); + base = 100; + assert(add_base(5) == 105); + + S s = {1, 2}; + auto sum = [&s]() { return s.x + s.y; }; + assert(sum() == 3); + s.x = 50; + assert(sum() == 52); + + int counter = 0; + auto bump = [&counter]() { counter++; }; + bump(); + bump(); + assert(counter == 2); + + uint16_t arr[4] = {3, 1, 2, 0}; + auto swap = [&arr](size_t i, size_t j) { + uint16_t t = arr[j]; + arr[j] = arr[i]; + arr[i] = t; + }; + swap(0, 3); + assert(arr[0] == 0); + assert(arr[3] == 3); + + return 0; +} diff --git a/tests/unit/lambda_capture_this.cpp b/tests/unit/lambda_capture_this.cpp new file mode 100644 index 000000000..d34cf8c78 --- /dev/null +++ b/tests/unit/lambda_capture_this.cpp @@ -0,0 +1,31 @@ +#include + +struct S { + int n; + int step; + void add(int k) { n += k; } + int scaled() const { return n * step; } + void bump(int by) { + auto inc = [this](int k) { n += k; }; + inc(by); + inc(by); + } + void bump_via_method(int by) { + auto inc = [this](int k) { add(k); }; + inc(by); + } + int read_scaled() const { + auto get = [this]() { return scaled(); }; + return get(); + } +}; + +int main() { + S s = {0, 2}; + s.bump(3); + assert(s.n == 6); + s.bump_via_method(4); + assert(s.n == 10); + assert(s.read_scaled() == 20); + return 0; +} diff --git a/tests/unit/lambda_capture_value.cpp b/tests/unit/lambda_capture_value.cpp new file mode 100644 index 000000000..cb94939c9 --- /dev/null +++ b/tests/unit/lambda_capture_value.cpp @@ -0,0 +1,31 @@ +#include + +struct S { + int x; + int y; +}; + +int main() { + int factor = 3; + auto scale = [factor](int x) { return x * factor; }; + assert(scale(4) == 12); + factor = 100; + assert(scale(4) == 12); + + int slot = 7; + int *p = &slot; + auto read_ptr = [p]() { return *p; }; + slot = 8; + assert(read_ptr() == 8); + + S s = {1, 2}; + auto sum = [s]() { return s.x + s.y; }; + s.x = 50; + assert(sum() == 3); + + int base = 10; + auto shifted = [y = base + 1](int x) { return x + y; }; + assert(shifted(5) == 16); + + return 0; +} diff --git a/tests/unit/lambda_mutable.cpp b/tests/unit/lambda_mutable.cpp new file mode 100644 index 000000000..5590e46eb --- /dev/null +++ b/tests/unit/lambda_mutable.cpp @@ -0,0 +1,21 @@ +#include + +int main() { + int start = 5; + auto next = [start]() mutable { return start++; }; + assert(next() == 5); + assert(next() == 6); + assert(next() == 7); + assert(start == 5); + + int total = 0; + auto accumulate = [total](int x) mutable { + total += x; + return total; + }; + assert(accumulate(1) == 1); + assert(accumulate(2) == 3); + assert(total == 0); + + return 0; +} diff --git a/tests/unit/lambda_nested.cpp b/tests/unit/lambda_nested.cpp index f7f26e93d..5a026da4a 100644 --- a/tests/unit/lambda_nested.cpp +++ b/tests/unit/lambda_nested.cpp @@ -1,5 +1,16 @@ #include +struct S { + int v; + int nested_this() { + auto outer = [this](int y) { + auto inner = [this, y](int z) { return v + y + z; }; + return inner(1); + }; + return outer(20); + } +}; + int main() { int x = 10; @@ -13,5 +24,8 @@ int main() { x = 100; assert(outer(20) == 121); + S s = {5}; + assert(s.nested_this() == 26); + return 0; } diff --git a/tests/unit/lambda_to_fn_ptr.cpp b/tests/unit/lambda_to_fn_ptr.cpp new file mode 100644 index 000000000..47a0f5962 --- /dev/null +++ b/tests/unit/lambda_to_fn_ptr.cpp @@ -0,0 +1,20 @@ +#include + +typedef int (*transform_t)(int); + +int apply(int x, transform_t fn) { return fn(x); } + +int main() { + transform_t fresh = [](int x) { return -x; }; + assert(fresh(5) == -5); + + auto twice = [](int x) { return x * 2; }; + transform_t named = twice; + assert(named(5) == 10); + assert(apply(5, twice) == 10); + + named = fresh; + assert(named(3) == -3); + + return 0; +} diff --git a/tests/unit/out/refcount/complex_function.rs b/tests/unit/out/refcount/complex_function.rs index 76ba6b783..7ecac949a 100644 --- a/tests/unit/out/refcount/complex_function.rs +++ b/tests/unit/out/refcount/complex_function.rs @@ -43,19 +43,10 @@ impl ByteRepr for X1 { } } } -#[derive(Default)] +#[derive(Clone, Default)] pub struct X2 { pub v: Ptr, } -impl Clone for X2 { - fn clone(&self) -> Self { - let __this: Value = Rc::new(RefCell::new(Self { - v: (self.v).clone(), - })); - let this: Ptr = __this.as_pointer(); - Rc::try_unwrap(__this).ok().unwrap().into_inner() - } -} impl ByteRepr for X2 {} #[derive(Default)] pub struct X3 { diff --git a/tests/unit/out/refcount/destructor.rs b/tests/unit/out/refcount/destructor.rs index 5050cd7c4..92e25ceed 100644 --- a/tests/unit/out/refcount/destructor.rs +++ b/tests/unit/out/refcount/destructor.rs @@ -9,15 +9,8 @@ use std::rc::{Rc, Weak}; thread_local!( pub static global_0: Value = Rc::new(RefCell::new(0)); ); -#[derive(Default)] +#[derive(Clone, Default)] pub struct S {} -impl Clone for S { - fn clone(&self) -> Self { - let __this: Value = Rc::new(RefCell::new(Self {})); - let this: Ptr = __this.as_pointer(); - Rc::try_unwrap(__this).ok().unwrap().into_inner() - } -} impl ByteRepr for S { fn byte_size() -> usize { 1 diff --git a/tests/unit/out/refcount/fn_ptr_default_arg.rs b/tests/unit/out/refcount/fn_ptr_default_arg.rs index 7e5a0bb3d..a8a1e7eb9 100644 --- a/tests/unit/out/refcount/fn_ptr_default_arg.rs +++ b/tests/unit/out/refcount/fn_ptr_default_arg.rs @@ -27,13 +27,36 @@ fn main_0() -> i32 { assert!((({ apply_1(5, None,) }) == 5)); assert!((({ apply_1(5, Some(FnPtr:: i32>::null()),) }) == 5)); assert!((({ apply_1(5, Some(FnPtr:: i32>::new(identity_0)),) }) == 5)); - let negate: Value i32>> = Rc::new(RefCell::new(FnPtr::new( - (|x: i32| { - let x: Value = Rc::new(RefCell::new(x)); - return -(*x.borrow()); - }), - ))); + let negate: Value i32>> = + Rc::new(RefCell::new(({ (lambda_2 {}).to_free_function() }))); assert!((({ apply_1(5, Some((*negate.borrow()).clone()),) }) == -5_i32)); return 0; } +#[derive(Clone, Default)] +pub struct lambda_2 {} +impl lambda_2 { + pub fn operator_call(x: i32) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + return -(*x.borrow()); + } +} +impl ByteRepr for lambda_2 { + fn byte_size() -> usize { + 1 + } + fn to_bytes(&self, buf: &mut [u8]) {} + fn from_bytes(buf: &[u8]) -> Self { + Self {} + } +} +impl Callable1 for lambda_2 { + fn call(&self, a1: i32) -> i32 { + { lambda_2::operator_call(a1) } + } +} +impl lambda_2 { + pub fn to_free_function(&self) -> FnPtr i32> { + FnPtr::new(lambda_2::operator_call) + } +} pub fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/refcount/function_overloading.rs b/tests/unit/out/refcount/function_overloading.rs index e720b72b7..954075010 100644 --- a/tests/unit/out/refcount/function_overloading.rs +++ b/tests/unit/out/refcount/function_overloading.rs @@ -36,15 +36,8 @@ pub fn foo_3(x: Ptr, y: Ptr, z: Ptr) -> i32 { pub fn bar_4(x: Ptr) -> i32 { return (x.read()); } -#[derive(Default)] +#[derive(Clone, Default)] pub struct Foo {} -impl Clone for Foo { - fn clone(&self) -> Self { - let __this: Value = Rc::new(RefCell::new(Self {})); - let this: Ptr = __this.as_pointer(); - Rc::try_unwrap(__this).ok().unwrap().into_inner() - } -} impl ByteRepr for Foo { fn byte_size() -> usize { 1 diff --git a/tests/unit/out/refcount/global_init_side_effect.rs b/tests/unit/out/refcount/global_init_side_effect.rs index 847bf9cf8..3cd7aac03 100644 --- a/tests/unit/out/refcount/global_init_side_effect.rs +++ b/tests/unit/out/refcount/global_init_side_effect.rs @@ -9,7 +9,7 @@ use std::rc::{Rc, Weak}; thread_local!( pub static total_0: Value = Rc::new(RefCell::new(0)); ); -#[derive(Default)] +#[derive(Clone, Default)] pub struct S {} impl S { pub fn S(x: i32) -> Self { @@ -20,13 +20,6 @@ impl S { Rc::try_unwrap(__this).ok().unwrap().into_inner() } } -impl Clone for S { - fn clone(&self) -> Self { - let __this: Value = Rc::new(RefCell::new(Self {})); - let this: Ptr = __this.as_pointer(); - Rc::try_unwrap(__this).ok().unwrap().into_inner() - } -} impl ByteRepr for S { fn byte_size() -> usize { 1 diff --git a/tests/unit/out/refcount/global_non_const_init.rs b/tests/unit/out/refcount/global_non_const_init.rs index a60421a35..760b566e3 100644 --- a/tests/unit/out/refcount/global_non_const_init.rs +++ b/tests/unit/out/refcount/global_non_const_init.rs @@ -99,15 +99,8 @@ thread_local!( thread_local!( pub static inline_member_11: Value = Rc::new(RefCell::new(Ctor::Ctor2({ 5 }))); ); -#[derive(Default)] +#[derive(Clone, Default)] pub struct Holder {} -impl Clone for Holder { - fn clone(&self) -> Self { - let __this: Value = Rc::new(RefCell::new(Self {})); - let this: Ptr = __this.as_pointer(); - Rc::try_unwrap(__this).ok().unwrap().into_inner() - } -} impl ByteRepr for Holder { fn byte_size() -> usize { 1 diff --git a/tests/unit/out/refcount/lambda_as_template_argument.rs b/tests/unit/out/refcount/lambda_as_template_argument.rs new file mode 100644 index 000000000..c2b978e9c --- /dev/null +++ b/tests/unit/out/refcount/lambda_as_template_argument.rs @@ -0,0 +1,135 @@ +extern crate libcc2rs; +use libcc2rs::*; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::io::prelude::*; +use std::io::{Read, Seek, Write}; +use std::os::fd::AsFd; +use std::rc::{Rc, Weak}; +pub fn apply_0(fn_: lambda_1, x: i32) -> i32 { + let fn_: Value = Rc::new(RefCell::new(fn_)); + let x: Value = Rc::new(RefCell::new(x)); + return ({ lambda_1::operator_call(&(*fn_.borrow_mut()), (*x.borrow())) }); +} +pub fn apply_2(fn_: lambda_3, x: i32) -> i32 { + let fn_: Value = Rc::new(RefCell::new(fn_)); + let x: Value = Rc::new(RefCell::new(x)); + return ({ lambda_3::operator_call(&(*fn_.borrow_mut()), (*x.borrow())) }); +} +pub fn apply_4(fn_: lambda_5, x: i32) -> i32 { + let fn_: Value = Rc::new(RefCell::new(fn_)); + let x: Value = Rc::new(RefCell::new(x)); + return ({ lambda_5::operator_call((*x.borrow())) }); +} +pub fn apply_twice_6(fn_: lambda_3, x: i32) -> i32 { + let fn_: Value = Rc::new(RefCell::new(fn_)); + let x: Value = Rc::new(RefCell::new(x)); + return ({ + let _x: i32 = ({ lambda_3::operator_call(&(*fn_.borrow_mut()), (*x.borrow())) }); + lambda_3::operator_call(&(*fn_.borrow_mut()), _x) + }); +} +pub fn main() { + __cpp2rust_init_globals(); + 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( + (lambda_1 { + base: base.as_pointer(), + }), + )); + assert!((({ apply_0((*add_base.borrow()).clone(), 5,) }) == 15)); + (*base.borrow_mut()) = 100; + assert!((({ apply_0((*add_base.borrow()).clone(), 5,) }) == 105)); + let factor: Value = Rc::new(RefCell::new(3)); + let scale: Value = Rc::new(RefCell::new( + (lambda_3 { + factor: Rc::new(RefCell::new((*factor.borrow()))), + }), + )); + assert!((({ apply_2((*scale.borrow()).clone(), 4,) }) == 12)); + assert!((({ apply_twice_6((*scale.borrow()).clone(), 4,) }) == 36)); + assert!((({ apply_4((lambda_5 {}), 9,) }) == -9_i32)); + return 0; +} +#[derive(Clone, Default)] +pub struct lambda_1 { + base: Ptr, +} +impl lambda_1 { + pub fn operator_call(&self, x: i32) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + return ((*x.borrow()) + (self.base.read())); + } +} +impl ByteRepr for lambda_1 {} +impl Callable1 for lambda_1 { + fn call(&self, a1: i32) -> i32 { + { lambda_1::operator_call(self, a1) } + } +} +#[derive(Default)] +pub struct lambda_3 { + factor: Value, +} +impl lambda_3 { + pub fn operator_call(&self, x: i32) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + return ((*x.borrow()) * (*self.factor.borrow())); + } +} +impl Clone for lambda_3 { + fn clone(&self) -> Self { + Self { + factor: Rc::new(RefCell::new((*self.factor.borrow()).clone())), + } + } +} +impl ByteRepr for lambda_3 { + fn byte_size() -> usize { + 4 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.factor.borrow()).to_bytes(&mut buf[0..4]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + factor: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), + } + } +} +impl Callable1 for lambda_3 { + fn call(&self, a1: i32) -> i32 { + { lambda_3::operator_call(self, a1) } + } +} +#[derive(Clone, Default)] +pub struct lambda_5 {} +impl lambda_5 { + pub fn operator_call(x: i32) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + return -(*x.borrow()); + } +} +impl ByteRepr for lambda_5 { + fn byte_size() -> usize { + 1 + } + fn to_bytes(&self, buf: &mut [u8]) {} + fn from_bytes(buf: &[u8]) -> Self { + Self {} + } +} +impl Callable1 for lambda_5 { + fn call(&self, a1: i32) -> i32 { + { lambda_5::operator_call(a1) } + } +} +impl lambda_5 { + pub fn to_free_function(&self) -> FnPtr i32> { + FnPtr::new(lambda_5::operator_call) + } +} +pub fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/refcount/lambda_basic.rs b/tests/unit/out/refcount/lambda_basic.rs new file mode 100644 index 000000000..33fa897a0 --- /dev/null +++ b/tests/unit/out/refcount/lambda_basic.rs @@ -0,0 +1,161 @@ +extern crate libcc2rs; +use libcc2rs::*; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::io::prelude::*; +use std::io::{Read, Seek, Write}; +use std::os::fd::AsFd; +use std::rc::{Rc, Weak}; +pub fn main() { + __cpp2rust_init_globals(); + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let zero: Value = Rc::new(RefCell::new((lambda_0 {}))); + assert!((({ lambda_0::operator_call() }) == 42)); + let one: Value = Rc::new(RefCell::new((lambda_1 {}))); + assert!((({ lambda_1::operator_call(1,) }) == 2)); + let three: Value = Rc::new(RefCell::new((lambda_2 {}))); + assert!((({ lambda_2::operator_call(1, 2, 3,) }) == 123)); + let hits: Value = Rc::new(RefCell::new(0)); + let no_return: Value = Rc::new(RefCell::new( + (lambda_3 { + hits: hits.as_pointer(), + }), + )); + ({ lambda_3::operator_call(&(*no_return.borrow_mut()), 3) }); + ({ lambda_3::operator_call(&(*no_return.borrow_mut()), 4) }); + assert!(((*hits.borrow()) == 7)); + let a: Value = Rc::new(RefCell::new(2)); + let b: Value = Rc::new(RefCell::new(3)); + let product: Value = Rc::new(RefCell::new( + ({ + lambda_4::operator_call( + &(lambda_4 { + a: a.as_pointer(), + b: b.as_pointer(), + }), + ) + }), + )); + assert!(((*product.borrow()) == 6)); + return 0; +} +#[derive(Clone, Default)] +pub struct lambda_0 {} +impl lambda_0 { + pub fn operator_call() -> i32 { + return 42; + } +} +impl ByteRepr for lambda_0 { + fn byte_size() -> usize { + 1 + } + fn to_bytes(&self, buf: &mut [u8]) {} + fn from_bytes(buf: &[u8]) -> Self { + Self {} + } +} +impl Callable0 for lambda_0 { + fn call(&self) -> i32 { + { lambda_0::operator_call() } + } +} +impl lambda_0 { + pub fn to_free_function(&self) -> FnPtr i32> { + FnPtr::new(lambda_0::operator_call) + } +} +#[derive(Clone, Default)] +pub struct lambda_1 {} +impl lambda_1 { + pub fn operator_call(x: i32) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + return ((*x.borrow()) + 1); + } +} +impl ByteRepr for lambda_1 { + fn byte_size() -> usize { + 1 + } + fn to_bytes(&self, buf: &mut [u8]) {} + fn from_bytes(buf: &[u8]) -> Self { + Self {} + } +} +impl Callable1 for lambda_1 { + fn call(&self, a1: i32) -> i32 { + { lambda_1::operator_call(a1) } + } +} +impl lambda_1 { + pub fn to_free_function(&self) -> FnPtr i32> { + FnPtr::new(lambda_1::operator_call) + } +} +#[derive(Clone, Default)] +pub struct lambda_2 {} +impl lambda_2 { + pub fn operator_call(x: i32, y: i32, z: i32) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + let y: Value = Rc::new(RefCell::new(y)); + let z: Value = Rc::new(RefCell::new(z)); + return ((((*x.borrow()) * 100) + ((*y.borrow()) * 10)) + (*z.borrow())); + } +} +impl ByteRepr for lambda_2 { + fn byte_size() -> usize { + 1 + } + fn to_bytes(&self, buf: &mut [u8]) {} + fn from_bytes(buf: &[u8]) -> Self { + Self {} + } +} +impl Callable3 for lambda_2 { + fn call(&self, a1: i32, a2: i32, a3: i32) -> i32 { + { lambda_2::operator_call(a1, a2, a3) } + } +} +impl lambda_2 { + pub fn to_free_function(&self) -> FnPtr i32> { + FnPtr::new(lambda_2::operator_call) + } +} +#[derive(Clone, Default)] +pub struct lambda_3 { + hits: Ptr, +} +impl lambda_3 { + pub fn operator_call(&self, by: i32) { + let by: Value = Rc::new(RefCell::new(by)); + { + let _ptr = self.hits.clone(); + _ptr.write(_ptr.read() + (*by.borrow())) + }; + } +} +impl ByteRepr for lambda_3 {} +impl Callable1 for lambda_3 { + fn call(&self, a1: i32) -> () { + { lambda_3::operator_call(self, a1) } + } +} +#[derive(Clone, Default)] +pub struct lambda_4 { + a: Ptr, + b: Ptr, +} +impl lambda_4 { + pub fn operator_call(&self) -> i32 { + return ((self.a.read()) * (self.b.read())); + } +} +impl ByteRepr for lambda_4 {} +impl Callable0 for lambda_4 { + fn call(&self) -> i32 { + { lambda_4::operator_call(self) } + } +} +pub fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/refcount/lambda_capture_implicit.rs b/tests/unit/out/refcount/lambda_capture_implicit.rs new file mode 100644 index 000000000..a02b687ad --- /dev/null +++ b/tests/unit/out/refcount/lambda_capture_implicit.rs @@ -0,0 +1,140 @@ +extern crate libcc2rs; +use libcc2rs::*; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::io::prelude::*; +use std::io::{Read, Seek, Write}; +use std::os::fd::AsFd; +use std::rc::{Rc, Weak}; +pub fn main() { + __cpp2rust_init_globals(); + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let a: Value = Rc::new(RefCell::new(1)); + let b: Value = Rc::new(RefCell::new(2)); + let c: Value = Rc::new(RefCell::new(3)); + let by_value: Value = Rc::new(RefCell::new( + (lambda_0 { + a: Rc::new(RefCell::new((*a.borrow()))), + b: Rc::new(RefCell::new((*b.borrow()))), + c: Rc::new(RefCell::new((*c.borrow()))), + }), + )); + assert!((({ lambda_0::operator_call(&(*by_value.borrow_mut()), 10,) }) == 16)); + (*a.borrow_mut()) = 100; + assert!((({ lambda_0::operator_call(&(*by_value.borrow_mut()), 10,) }) == 16)); + let by_ref: Value = Rc::new(RefCell::new( + (lambda_1 { + a: a.as_pointer(), + b: b.as_pointer(), + c: c.as_pointer(), + }), + )); + assert!((({ lambda_1::operator_call(&(*by_ref.borrow_mut()), 10,) }) == 115)); + (*b.borrow_mut()) = 200; + assert!((({ lambda_1::operator_call(&(*by_ref.borrow_mut()), 10,) }) == 313)); + let mixed: Value = Rc::new(RefCell::new( + (lambda_2 { + c: c.as_pointer(), + a: Rc::new(RefCell::new((*a.borrow()))), + b: Rc::new(RefCell::new((*b.borrow()))), + }), + )); + assert!((({ lambda_2::operator_call(&(*mixed.borrow_mut()), 1,) }) == ((100 + 200) + 4))); + assert!(((*c.borrow()) == 4)); + return 0; +} +#[derive(Default)] +pub struct lambda_0 { + a: Value, + b: Value, + c: Value, +} +impl lambda_0 { + pub fn operator_call(&self, x: i32) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + return ((((*self.a.borrow()) + (*self.b.borrow())) + (*self.c.borrow())) + (*x.borrow())); + } +} +impl Clone for lambda_0 { + fn clone(&self) -> Self { + Self { + a: Rc::new(RefCell::new((*self.a.borrow()).clone())), + b: Rc::new(RefCell::new((*self.b.borrow()).clone())), + c: Rc::new(RefCell::new((*self.c.borrow()).clone())), + } + } +} +impl ByteRepr for lambda_0 { + fn byte_size() -> usize { + 12 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.a.borrow()).to_bytes(&mut buf[0..4]); + (*self.b.borrow()).to_bytes(&mut buf[4..8]); + (*self.c.borrow()).to_bytes(&mut buf[8..12]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + a: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), + b: Rc::new(RefCell::new(::from_bytes(&buf[4..8]))), + c: Rc::new(RefCell::new(::from_bytes(&buf[8..12]))), + } + } +} +impl Callable1 for lambda_0 { + fn call(&self, a1: i32) -> i32 { + { lambda_0::operator_call(self, a1) } + } +} +#[derive(Clone, Default)] +pub struct lambda_1 { + a: Ptr, + b: Ptr, + c: Ptr, +} +impl lambda_1 { + pub fn operator_call(&self, x: i32) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + return ((((self.a.read()) + (self.b.read())) + (self.c.read())) + (*x.borrow())); + } +} +impl ByteRepr for lambda_1 {} +impl Callable1 for lambda_1 { + fn call(&self, a1: i32) -> i32 { + { lambda_1::operator_call(self, a1) } + } +} +#[derive(Default)] +pub struct lambda_2 { + c: Ptr, + a: Value, + b: Value, +} +impl lambda_2 { + pub fn operator_call(&self, x: i32) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + { + let _ptr = self.c.clone(); + _ptr.write(_ptr.read() + (*x.borrow())) + }; + return (((*self.a.borrow()) + (*self.b.borrow())) + (self.c.read())); + } +} +impl Clone for lambda_2 { + fn clone(&self) -> Self { + Self { + c: self.c.clone(), + a: Rc::new(RefCell::new((*self.a.borrow()).clone())), + b: Rc::new(RefCell::new((*self.b.borrow()).clone())), + } + } +} +impl ByteRepr for lambda_2 {} +impl Callable1 for lambda_2 { + fn call(&self, a1: i32) -> i32 { + { lambda_2::operator_call(self, a1) } + } +} +pub fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/refcount/lambda_capture_pass.rs b/tests/unit/out/refcount/lambda_capture_pass.rs deleted file mode 100644 index ad5347557..000000000 --- a/tests/unit/out/refcount/lambda_capture_pass.rs +++ /dev/null @@ -1,44 +0,0 @@ -extern crate libcc2rs; -use libcc2rs::*; -use std::cell::RefCell; -use std::collections::BTreeMap; -use std::io::prelude::*; -use std::io::{Read, Seek, Write}; -use std::os::fd::AsFd; -use std::rc::{Rc, Weak}; -pub fn 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 ({ (*fn_.borrow_mut())((*x.borrow())) }); -} -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 ({ (*fn_.borrow_mut())((*x.borrow())) }); -} -pub fn main() { - __cpp2rust_init_globals(); - 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!((({ apply_0((*add_base.borrow()).clone(), 5,) }) == 15)); - (*base.borrow_mut()) = 100; - assert!((({ apply_0((*add_base.borrow()).clone(), 5,) }) == 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!((({ apply_1((*scale.borrow()).clone(), 4,) }) == 12)); - return 0; -} -pub fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/refcount/lambda_capture_ref.rs b/tests/unit/out/refcount/lambda_capture_ref.rs new file mode 100644 index 000000000..17a7e7852 --- /dev/null +++ b/tests/unit/out/refcount/lambda_capture_ref.rs @@ -0,0 +1,158 @@ +extern crate libcc2rs; +use libcc2rs::*; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::io::prelude::*; +use std::io::{Read, Seek, Write}; +use std::os::fd::AsFd; +use std::rc::{Rc, Weak}; +#[derive(Default)] +pub struct S { + pub x: Value, + pub y: Value, +} +impl Clone for S { + fn clone(&self) -> Self { + let __this: Value = Rc::new(RefCell::new(Self { + x: Rc::new(RefCell::new((*self.x.borrow()))), + y: Rc::new(RefCell::new((*self.y.borrow()))), + })); + let this: Ptr = __this.as_pointer(); + Rc::try_unwrap(__this).ok().unwrap().into_inner() + } +} +impl ByteRepr for S { + fn byte_size() -> usize { + 8 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.x.borrow()).to_bytes(&mut buf[0..4]); + (*self.y.borrow()).to_bytes(&mut buf[4..8]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + x: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), + y: Rc::new(RefCell::new(::from_bytes(&buf[4..8]))), + } + } +} +pub fn main() { + __cpp2rust_init_globals(); + 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( + (lambda_0 { + base: base.as_pointer(), + }), + )); + assert!((({ lambda_0::operator_call(&(*add_base.borrow_mut()), 5,) }) == 15)); + (*base.borrow_mut()) = 100; + assert!((({ lambda_0::operator_call(&(*add_base.borrow_mut()), 5,) }) == 105)); + let s: Value = Rc::new(RefCell::new(S { + x: Rc::new(RefCell::new(1)), + y: Rc::new(RefCell::new(2)), + })); + let sum: Value = Rc::new(RefCell::new((lambda_1 { s: s.as_pointer() }))); + assert!((({ lambda_1::operator_call(&(*sum.borrow_mut()),) }) == 3)); + (*(*s.borrow()).x.borrow_mut()) = 50; + assert!((({ lambda_1::operator_call(&(*sum.borrow_mut()),) }) == 52)); + let counter: Value = Rc::new(RefCell::new(0)); + let bump: Value = Rc::new(RefCell::new( + (lambda_2 { + counter: counter.as_pointer(), + }), + )); + ({ lambda_2::operator_call(&(*bump.borrow_mut())) }); + ({ lambda_2::operator_call(&(*bump.borrow_mut())) }); + assert!(((*counter.borrow()) == 2)); + let arr: Value> = Rc::new(RefCell::new(Box::new([3_u16, 1_u16, 2_u16, 0_u16]))); + let swap: Value = Rc::new(RefCell::new( + (lambda_3 { + arr: (arr.as_pointer() as Ptr>), + }), + )); + ({ lambda_3::operator_call(&(*swap.borrow_mut()), 0_usize, 3_usize) }); + assert!((((*arr.borrow())[(0) as usize] as i32) == 0)); + assert!((((*arr.borrow())[(3) as usize] as i32) == 3)); + return 0; +} +#[derive(Clone, Default)] +pub struct lambda_0 { + base: Ptr, +} +impl lambda_0 { + pub fn operator_call(&self, x: i32) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + return ((*x.borrow()) + (self.base.read())); + } +} +impl ByteRepr for lambda_0 {} +impl Callable1 for lambda_0 { + fn call(&self, a1: i32) -> i32 { + { lambda_0::operator_call(self, a1) } + } +} +#[derive(Clone, Default)] +pub struct lambda_1 { + s: Ptr, +} +impl lambda_1 { + pub fn operator_call(&self) -> i32 { + return ((*(*self.s.upgrade().deref()).x.borrow()) + + (*(*self.s.upgrade().deref()).y.borrow())); + } +} +impl ByteRepr for lambda_1 {} +impl Callable0 for lambda_1 { + fn call(&self) -> i32 { + { lambda_1::operator_call(self) } + } +} +#[derive(Clone, Default)] +pub struct lambda_2 { + counter: Ptr, +} +impl lambda_2 { + pub fn operator_call(&self) { + self.counter.with_mut(|__v| __v.postfix_inc()); + } +} +impl ByteRepr for lambda_2 {} +impl Callable0<()> for lambda_2 { + fn call(&self) -> () { + { lambda_2::operator_call(self) } + } +} +#[derive(Clone, Default)] +pub struct lambda_3 { + arr: Ptr>, +} +impl lambda_3 { + pub fn operator_call(&self, i: usize, j: usize) { + let i: Value = Rc::new(RefCell::new(i)); + let j: Value = Rc::new(RefCell::new(j)); + let t: Value = Rc::new(RefCell::new( + ((self.arr.to_strong().as_pointer() as Ptr) + .offset((*j.borrow()) as isize) + .read()), + )); + let __rhs = ((self.arr.to_strong().as_pointer() as Ptr) + .offset((*i.borrow()) as isize) + .read()); + (self.arr.to_strong().as_pointer() as Ptr) + .offset((*j.borrow()) as isize) + .write(__rhs); + (self.arr.to_strong().as_pointer() as Ptr) + .offset((*i.borrow()) as isize) + .write((*t.borrow())); + } +} +impl ByteRepr for lambda_3 {} +impl Callable2 for lambda_3 { + fn call(&self, a1: usize, a2: usize) -> () { + { lambda_3::operator_call(self, a1, a2) } + } +} +pub fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/refcount/lambda_capture_this.rs b/tests/unit/out/refcount/lambda_capture_this.rs new file mode 100644 index 000000000..ada3b0714 --- /dev/null +++ b/tests/unit/out/refcount/lambda_capture_this.rs @@ -0,0 +1,203 @@ +extern crate libcc2rs; +use libcc2rs::*; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::io::prelude::*; +use std::io::{Read, Seek, Write}; +use std::os::fd::AsFd; +use std::rc::{Rc, Weak}; +#[derive(Default)] +pub struct S { + pub n: Value, + pub step: Value, +} +impl Clone for S { + fn clone(&self) -> Self { + let __this: Value = Rc::new(RefCell::new(Self { + n: Rc::new(RefCell::new((*self.n.borrow()))), + step: Rc::new(RefCell::new((*self.step.borrow()))), + })); + let this: Ptr = __this.as_pointer(); + Rc::try_unwrap(__this).ok().unwrap().into_inner() + } +} +impl ByteRepr for S { + fn byte_size() -> usize { + 8 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.n.borrow()).to_bytes(&mut buf[0..4]); + (*self.step.borrow()).to_bytes(&mut buf[4..8]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + n: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), + step: Rc::new(RefCell::new(::from_bytes(&buf[4..8]))), + } + } +} +#[derive(Default)] +pub struct lambda_0 { + this_: Value>, +} +impl lambda_0 { + fn operator_call(&self, k: i32) { + let k: Value = Rc::new(RefCell::new(k)); + (*(*(*self.this_.borrow()).upgrade().deref()).n.borrow_mut()) += (*k.borrow()); + } +} +impl Clone for lambda_0 { + fn clone(&self) -> Self { + Self { + this_: Rc::new(RefCell::new((*self.this_.borrow()).clone())), + } + } +} +impl ByteRepr for lambda_0 { + fn byte_size() -> usize { + 8 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.this_.borrow()).to_bytes(&mut buf[0..8]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + this_: Rc::new(RefCell::new(>::from_bytes(&buf[0..8]))), + } + } +} +impl Callable1 for lambda_0 { + fn call(&self, a1: i32) -> () { + { lambda_0::operator_call(self, a1) } + } +} +#[derive(Default)] +pub struct lambda_1 { + this_: Value>, +} +impl lambda_1 { + fn operator_call(&self, k: i32) { + let k: Value = Rc::new(RefCell::new(k)); + ({ SImpl::add(&(*self.this_.borrow()), (*k.borrow())) }); + } +} +impl Clone for lambda_1 { + fn clone(&self) -> Self { + Self { + this_: Rc::new(RefCell::new((*self.this_.borrow()).clone())), + } + } +} +impl ByteRepr for lambda_1 { + fn byte_size() -> usize { + 8 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.this_.borrow()).to_bytes(&mut buf[0..8]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + this_: Rc::new(RefCell::new(>::from_bytes(&buf[0..8]))), + } + } +} +impl Callable1 for lambda_1 { + fn call(&self, a1: i32) -> () { + { lambda_1::operator_call(self, a1) } + } +} +#[derive(Default)] +pub struct lambda_2 { + this_: Value>, +} +impl lambda_2 { + fn operator_call(&self) -> i32 { + return ({ SImpl::scaled(&(*self.this_.borrow())) }); + } +} +impl Clone for lambda_2 { + fn clone(&self) -> Self { + Self { + this_: Rc::new(RefCell::new((*self.this_.borrow()).clone())), + } + } +} +impl ByteRepr for lambda_2 { + fn byte_size() -> usize { + 8 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.this_.borrow()).to_bytes(&mut buf[0..8]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + this_: Rc::new(RefCell::new(>::from_bytes(&buf[0..8]))), + } + } +} +impl Callable0 for lambda_2 { + fn call(&self) -> i32 { + { lambda_2::operator_call(self) } + } +} +pub fn main() { + __cpp2rust_init_globals(); + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let s: Value = Rc::new(RefCell::new(S { + n: Rc::new(RefCell::new(0)), + step: Rc::new(RefCell::new(2)), + })); + ({ SImpl::bump(&s.as_pointer(), 3) }); + assert!(((*(*s.borrow()).n.borrow()) == 6)); + ({ SImpl::bump_via_method(&s.as_pointer(), 4) }); + assert!(((*(*s.borrow()).n.borrow()) == 10)); + assert!((({ SImpl::read_scaled(&s.as_pointer(),) }) == 20)); + return 0; +} +pub trait SImpl { + fn add(&self, k: i32); + fn scaled(&self) -> i32; + fn bump(&self, by: i32); + fn bump_via_method(&self, by: i32); + fn read_scaled(&self) -> i32; +} +impl SImpl for Ptr { + fn add(&self, k: i32) { + let k: Value = Rc::new(RefCell::new(k)); + (*(*(*self).upgrade().deref()).n.borrow_mut()) += (*k.borrow()); + } + fn scaled(&self) -> i32 { + return ((*(*(*self).upgrade().deref()).n.borrow()) + * (*(*(*self).upgrade().deref()).step.borrow())); + } + fn bump(&self, by: i32) { + let by: Value = Rc::new(RefCell::new(by)); + let inc: Value = Rc::new(RefCell::new( + (lambda_0 { + this_: Rc::new(RefCell::new((*self).clone())), + }), + )); + ({ lambda_0::operator_call(&(*inc.borrow_mut()), (*by.borrow())) }); + ({ lambda_0::operator_call(&(*inc.borrow_mut()), (*by.borrow())) }); + } + fn bump_via_method(&self, by: i32) { + let by: Value = Rc::new(RefCell::new(by)); + let inc: Value = Rc::new(RefCell::new( + (lambda_1 { + this_: Rc::new(RefCell::new((*self).clone())), + }), + )); + ({ lambda_1::operator_call(&(*inc.borrow_mut()), (*by.borrow())) }); + } + fn read_scaled(&self) -> i32 { + let get: Value = Rc::new(RefCell::new( + (lambda_2 { + this_: Rc::new(RefCell::new((*self).clone())), + }), + )); + return ({ lambda_2::operator_call(&(*get.borrow_mut())) }); + } +} +pub fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/refcount/lambda_capture_value.rs b/tests/unit/out/refcount/lambda_capture_value.rs new file mode 100644 index 000000000..a4c8fc8c9 --- /dev/null +++ b/tests/unit/out/refcount/lambda_capture_value.rs @@ -0,0 +1,220 @@ +extern crate libcc2rs; +use libcc2rs::*; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::io::prelude::*; +use std::io::{Read, Seek, Write}; +use std::os::fd::AsFd; +use std::rc::{Rc, Weak}; +#[derive(Default)] +pub struct S { + pub x: Value, + pub y: Value, +} +impl Clone for S { + fn clone(&self) -> Self { + let __this: Value = Rc::new(RefCell::new(Self { + x: Rc::new(RefCell::new((*self.x.borrow()))), + y: Rc::new(RefCell::new((*self.y.borrow()))), + })); + let this: Ptr = __this.as_pointer(); + Rc::try_unwrap(__this).ok().unwrap().into_inner() + } +} +impl ByteRepr for S { + fn byte_size() -> usize { + 8 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.x.borrow()).to_bytes(&mut buf[0..4]); + (*self.y.borrow()).to_bytes(&mut buf[4..8]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + x: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), + y: Rc::new(RefCell::new(::from_bytes(&buf[4..8]))), + } + } +} +pub fn main() { + __cpp2rust_init_globals(); + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let factor: Value = Rc::new(RefCell::new(3)); + let scale: Value = Rc::new(RefCell::new( + (lambda_0 { + factor: Rc::new(RefCell::new((*factor.borrow()))), + }), + )); + assert!((({ lambda_0::operator_call(&(*scale.borrow_mut()), 4,) }) == 12)); + (*factor.borrow_mut()) = 100; + assert!((({ lambda_0::operator_call(&(*scale.borrow_mut()), 4,) }) == 12)); + let slot: Value = Rc::new(RefCell::new(7)); + let p: Value> = Rc::new(RefCell::new((slot.as_pointer()))); + let read_ptr: Value = Rc::new(RefCell::new( + (lambda_1 { + p: Rc::new(RefCell::new((*p.borrow()).clone())), + }), + )); + (*slot.borrow_mut()) = 8; + assert!((({ lambda_1::operator_call(&(*read_ptr.borrow_mut()),) }) == 8)); + let s: Value = Rc::new(RefCell::new(S { + x: Rc::new(RefCell::new(1)), + y: Rc::new(RefCell::new(2)), + })); + let sum: Value = Rc::new(RefCell::new( + (lambda_2 { + s: Rc::new(RefCell::new((*s.borrow()).clone())), + }), + )); + (*(*s.borrow()).x.borrow_mut()) = 50; + assert!((({ lambda_2::operator_call(&(*sum.borrow_mut()),) }) == 3)); + let base: Value = Rc::new(RefCell::new(10)); + let shifted: Value = Rc::new(RefCell::new( + (lambda_3 { + y: Rc::new(RefCell::new(((*base.borrow()) + 1))), + }), + )); + assert!((({ lambda_3::operator_call(&(*shifted.borrow_mut()), 5,) }) == 16)); + return 0; +} +#[derive(Default)] +pub struct lambda_0 { + factor: Value, +} +impl lambda_0 { + pub fn operator_call(&self, x: i32) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + return ((*x.borrow()) * (*self.factor.borrow())); + } +} +impl Clone for lambda_0 { + fn clone(&self) -> Self { + Self { + factor: Rc::new(RefCell::new((*self.factor.borrow()).clone())), + } + } +} +impl ByteRepr for lambda_0 { + fn byte_size() -> usize { + 4 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.factor.borrow()).to_bytes(&mut buf[0..4]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + factor: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), + } + } +} +impl Callable1 for lambda_0 { + fn call(&self, a1: i32) -> i32 { + { lambda_0::operator_call(self, a1) } + } +} +#[derive(Default)] +pub struct lambda_1 { + p: Value>, +} +impl lambda_1 { + pub fn operator_call(&self) -> i32 { + return ((*self.p.borrow()).read()); + } +} +impl Clone for lambda_1 { + fn clone(&self) -> Self { + Self { + p: Rc::new(RefCell::new((*self.p.borrow()).clone())), + } + } +} +impl ByteRepr for lambda_1 { + fn byte_size() -> usize { + 8 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.p.borrow()).to_bytes(&mut buf[0..8]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + p: Rc::new(RefCell::new(>::from_bytes(&buf[0..8]))), + } + } +} +impl Callable0 for lambda_1 { + fn call(&self) -> i32 { + { lambda_1::operator_call(self) } + } +} +#[derive(Default)] +pub struct lambda_2 { + s: Value, +} +impl lambda_2 { + pub fn operator_call(&self) -> i32 { + return ((*(*self.s.borrow()).x.borrow()) + (*(*self.s.borrow()).y.borrow())); + } +} +impl Clone for lambda_2 { + fn clone(&self) -> Self { + Self { + s: Rc::new(RefCell::new((*self.s.borrow()).clone())), + } + } +} +impl ByteRepr for lambda_2 { + fn byte_size() -> usize { + 8 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.s.borrow()).to_bytes(&mut buf[0..8]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + s: Rc::new(RefCell::new(::from_bytes(&buf[0..8]))), + } + } +} +impl Callable0 for lambda_2 { + fn call(&self) -> i32 { + { lambda_2::operator_call(self) } + } +} +#[derive(Default)] +pub struct lambda_3 { + y: Value, +} +impl lambda_3 { + pub fn operator_call(&self, x: i32) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + return ((*x.borrow()) + (*self.y.borrow())); + } +} +impl Clone for lambda_3 { + fn clone(&self) -> Self { + Self { + y: Rc::new(RefCell::new((*self.y.borrow()).clone())), + } + } +} +impl ByteRepr for lambda_3 { + fn byte_size() -> usize { + 4 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.y.borrow()).to_bytes(&mut buf[0..4]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + y: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), + } + } +} +impl Callable1 for lambda_3 { + fn call(&self, a1: i32) -> i32 { + { lambda_3::operator_call(self, a1) } + } +} +pub fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/refcount/lambda_mutable.rs b/tests/unit/out/refcount/lambda_mutable.rs new file mode 100644 index 000000000..51dc3c439 --- /dev/null +++ b/tests/unit/out/refcount/lambda_mutable.rs @@ -0,0 +1,95 @@ +extern crate libcc2rs; +use libcc2rs::*; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::io::prelude::*; +use std::io::{Read, Seek, Write}; +use std::os::fd::AsFd; +use std::rc::{Rc, Weak}; +pub fn main() { + __cpp2rust_init_globals(); + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let start: Value = Rc::new(RefCell::new(5)); + let next: Value = Rc::new(RefCell::new( + (lambda_0 { + start: Rc::new(RefCell::new((*start.borrow()))), + }), + )); + assert!((({ lambda_0::operator_call(&mut (*next.borrow_mut()),) }) == 5)); + assert!((({ lambda_0::operator_call(&mut (*next.borrow_mut()),) }) == 6)); + assert!((({ lambda_0::operator_call(&mut (*next.borrow_mut()),) }) == 7)); + assert!(((*start.borrow()) == 5)); + let total: Value = Rc::new(RefCell::new(0)); + let accumulate: Value = Rc::new(RefCell::new( + (lambda_1 { + total: Rc::new(RefCell::new((*total.borrow()))), + }), + )); + assert!((({ lambda_1::operator_call(&mut (*accumulate.borrow_mut()), 1,) }) == 1)); + assert!((({ lambda_1::operator_call(&mut (*accumulate.borrow_mut()), 2,) }) == 3)); + assert!(((*total.borrow()) == 0)); + return 0; +} +#[derive(Default)] +pub struct lambda_0 { + start: Value, +} +impl lambda_0 { + pub fn operator_call(&self) -> i32 { + return (*self.start.borrow_mut()).postfix_inc(); + } +} +impl Clone for lambda_0 { + fn clone(&self) -> Self { + Self { + start: Rc::new(RefCell::new((*self.start.borrow()).clone())), + } + } +} +impl ByteRepr for lambda_0 { + fn byte_size() -> usize { + 4 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.start.borrow()).to_bytes(&mut buf[0..4]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + start: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), + } + } +} +#[derive(Default)] +pub struct lambda_1 { + total: Value, +} +impl lambda_1 { + pub fn operator_call(&self, x: i32) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + (*self.total.borrow_mut()) += (*x.borrow()); + return (*self.total.borrow()); + } +} +impl Clone for lambda_1 { + fn clone(&self) -> Self { + Self { + total: Rc::new(RefCell::new((*self.total.borrow()).clone())), + } + } +} +impl ByteRepr for lambda_1 { + fn byte_size() -> usize { + 4 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.total.borrow()).to_bytes(&mut buf[0..4]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + total: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), + } + } +} +pub fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/refcount/lambda_nested.rs b/tests/unit/out/refcount/lambda_nested.rs index 29670d7b9..160fc63a5 100644 --- a/tests/unit/out/refcount/lambda_nested.rs +++ b/tests/unit/out/refcount/lambda_nested.rs @@ -6,27 +6,187 @@ use std::io::prelude::*; use std::io::{Read, Seek, Write}; use std::os::fd::AsFd; use std::rc::{Rc, Weak}; +#[derive(Default)] +pub struct S { + pub v: Value, +} +impl Clone for S { + fn clone(&self) -> Self { + let __this: Value = Rc::new(RefCell::new(Self { + v: Rc::new(RefCell::new((*self.v.borrow()))), + })); + let this: Ptr = __this.as_pointer(); + Rc::try_unwrap(__this).ok().unwrap().into_inner() + } +} +impl ByteRepr for S { + fn byte_size() -> usize { + 4 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.v.borrow()).to_bytes(&mut buf[0..4]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + v: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), + } + } +} +#[derive(Default)] +pub struct lambda_1 { + this_: Value>, + y: Value, +} +impl lambda_1 { + fn operator_call(&self, z: i32) -> i32 { + let z: Value = Rc::new(RefCell::new(z)); + return (((*(*(*self.this_.borrow()).upgrade().deref()).v.borrow()) + (*self.y.borrow())) + + (*z.borrow())); + } +} +impl Clone for lambda_1 { + fn clone(&self) -> Self { + Self { + this_: Rc::new(RefCell::new((*self.this_.borrow()).clone())), + y: Rc::new(RefCell::new((*self.y.borrow()).clone())), + } + } +} +impl ByteRepr for lambda_1 { + fn byte_size() -> usize { + 16 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.this_.borrow()).to_bytes(&mut buf[0..8]); + (*self.y.borrow()).to_bytes(&mut buf[8..12]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + this_: Rc::new(RefCell::new(>::from_bytes(&buf[0..8]))), + y: Rc::new(RefCell::new(::from_bytes(&buf[8..12]))), + } + } +} +impl Callable1 for lambda_1 { + fn call(&self, a1: i32) -> i32 { + { lambda_1::operator_call(self, a1) } + } +} +#[derive(Default)] +pub struct lambda_0 { + this_: Value>, +} +impl lambda_0 { + fn operator_call(&self, y: i32) -> i32 { + let y: Value = Rc::new(RefCell::new(y)); + let inner: Value = Rc::new(RefCell::new( + (lambda_1 { + this_: Rc::new(RefCell::new((*self.this_.borrow()).clone())), + y: Rc::new(RefCell::new((*y.borrow()))), + }), + )); + return ({ lambda_1::operator_call(&(*inner.borrow_mut()), 1) }); + } +} +impl Clone for lambda_0 { + fn clone(&self) -> Self { + Self { + this_: Rc::new(RefCell::new((*self.this_.borrow()).clone())), + } + } +} +impl ByteRepr for lambda_0 { + fn byte_size() -> usize { + 8 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.this_.borrow()).to_bytes(&mut buf[0..8]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + this_: Rc::new(RefCell::new(>::from_bytes(&buf[0..8]))), + } + } +} +impl Callable1 for lambda_0 { + fn call(&self, a1: i32) -> i32 { + { lambda_0::operator_call(self, a1) } + } +} pub fn main() { __cpp2rust_init_globals(); 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 ({ (*inner.borrow_mut())(1) }); - }), - )); - assert!((({ (*outer.borrow_mut())(20,) }) == 31)); + let outer: Value = Rc::new(RefCell::new((lambda_2 { x: x.as_pointer() }))); + assert!((({ lambda_2::operator_call(&(*outer.borrow_mut()), 20,) }) == 31)); (*x.borrow_mut()) = 100; - assert!((({ (*outer.borrow_mut())(20,) }) == 121)); + assert!((({ lambda_2::operator_call(&(*outer.borrow_mut()), 20,) }) == 121)); + let s: Value = Rc::new(RefCell::new(S { + v: Rc::new(RefCell::new(5)), + })); + assert!((({ SImpl::nested_this(&s.as_pointer(),) }) == 26)); return 0; } +#[derive(Default)] +pub struct lambda_3 { + x: Ptr, + y: Value, +} +impl lambda_3 { + pub fn operator_call(&self, z: i32) -> i32 { + let z: Value = Rc::new(RefCell::new(z)); + return (((self.x.read()) + (*self.y.borrow())) + (*z.borrow())); + } +} +impl Clone for lambda_3 { + fn clone(&self) -> Self { + Self { + x: self.x.clone(), + y: Rc::new(RefCell::new((*self.y.borrow()).clone())), + } + } +} +impl ByteRepr for lambda_3 {} +impl Callable1 for lambda_3 { + fn call(&self, a1: i32) -> i32 { + { lambda_3::operator_call(self, a1) } + } +} +#[derive(Clone, Default)] +pub struct lambda_2 { + x: Ptr, +} +impl lambda_2 { + pub fn operator_call(&self, y: i32) -> i32 { + let y: Value = Rc::new(RefCell::new(y)); + let inner: Value = Rc::new(RefCell::new( + (lambda_3 { + x: (self.x).clone(), + y: Rc::new(RefCell::new((*y.borrow()))), + }), + )); + return ({ lambda_3::operator_call(&(*inner.borrow_mut()), 1) }); + } +} +impl ByteRepr for lambda_2 {} +impl Callable1 for lambda_2 { + fn call(&self, a1: i32) -> i32 { + { lambda_2::operator_call(self, a1) } + } +} +pub trait SImpl { + fn nested_this(&self) -> i32; +} +impl SImpl for Ptr { + fn nested_this(&self) -> i32 { + let outer: Value = Rc::new(RefCell::new( + (lambda_0 { + this_: Rc::new(RefCell::new((*self).clone())), + }), + )); + return ({ lambda_0::operator_call(&(*outer.borrow_mut()), 20) }); + } +} pub fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/refcount/lambda_to_fn_ptr.rs b/tests/unit/out/refcount/lambda_to_fn_ptr.rs new file mode 100644 index 000000000..37f4c3a8c --- /dev/null +++ b/tests/unit/out/refcount/lambda_to_fn_ptr.rs @@ -0,0 +1,85 @@ +extern crate libcc2rs; +use libcc2rs::*; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::io::prelude::*; +use std::io::{Read, Seek, Write}; +use std::os::fd::AsFd; +use std::rc::{Rc, Weak}; +pub fn apply_0(x: i32, fn_: FnPtr i32>) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + let fn_: Value i32>> = Rc::new(RefCell::new(fn_)); + return ({ (*(*fn_.borrow()))((*x.borrow())) }); +} +pub fn main() { + __cpp2rust_init_globals(); + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let fresh: Value i32>> = + Rc::new(RefCell::new(({ (lambda_1 {}).to_free_function() }))); + assert!((({ (*(*fresh.borrow()))(5,) }) == -5_i32)); + let twice: Value = Rc::new(RefCell::new((lambda_2 {}))); + let named: Value i32>> = + Rc::new(RefCell::new(({ (*twice.borrow()).to_free_function() }))); + assert!((({ (*(*named.borrow()))(5,) }) == 10)); + assert!((({ apply_0(5, ({ (*twice.borrow()).to_free_function() }),) }) == 10)); + (*named.borrow_mut()) = (*fresh.borrow()).clone(); + assert!((({ (*(*named.borrow()))(3,) }) == -3_i32)); + return 0; +} +#[derive(Clone, Default)] +pub struct lambda_1 {} +impl lambda_1 { + pub fn operator_call(x: i32) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + return -(*x.borrow()); + } +} +impl ByteRepr for lambda_1 { + fn byte_size() -> usize { + 1 + } + fn to_bytes(&self, buf: &mut [u8]) {} + fn from_bytes(buf: &[u8]) -> Self { + Self {} + } +} +impl Callable1 for lambda_1 { + fn call(&self, a1: i32) -> i32 { + { lambda_1::operator_call(a1) } + } +} +impl lambda_1 { + pub fn to_free_function(&self) -> FnPtr i32> { + FnPtr::new(lambda_1::operator_call) + } +} +#[derive(Clone, Default)] +pub struct lambda_2 {} +impl lambda_2 { + pub fn operator_call(x: i32) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + return ((*x.borrow()) * 2); + } +} +impl ByteRepr for lambda_2 { + fn byte_size() -> usize { + 1 + } + fn to_bytes(&self, buf: &mut [u8]) {} + fn from_bytes(buf: &[u8]) -> Self { + Self {} + } +} +impl Callable1 for lambda_2 { + fn call(&self, a1: i32) -> i32 { + { lambda_2::operator_call(a1) } + } +} +impl lambda_2 { + pub fn to_free_function(&self) -> FnPtr i32> { + FnPtr::new(lambda_2::operator_call) + } +} +pub fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/refcount/nested_structs.rs b/tests/unit/out/refcount/nested_structs.rs index 31ba4c3eb..1bd02d720 100644 --- a/tests/unit/out/refcount/nested_structs.rs +++ b/tests/unit/out/refcount/nested_structs.rs @@ -144,15 +144,8 @@ impl ByteRepr for Level0_Level1_2 { } } } -#[derive(Default)] +#[derive(Clone, Default)] pub struct Level0 {} -impl Clone for Level0 { - fn clone(&self) -> Self { - let __this: Value = Rc::new(RefCell::new(Self {})); - let this: Ptr = __this.as_pointer(); - Rc::try_unwrap(__this).ok().unwrap().into_inner() - } -} impl ByteRepr for Level0 { fn byte_size() -> usize { 1 diff --git a/tests/unit/out/refcount/operator_member_pointer_member.rs b/tests/unit/out/refcount/operator_member_pointer_member.rs index ef79b5c54..90e82e56b 100644 --- a/tests/unit/out/refcount/operator_member_pointer_member.rs +++ b/tests/unit/out/refcount/operator_member_pointer_member.rs @@ -32,7 +32,7 @@ impl ByteRepr for Inner { } } } -#[derive(Default)] +#[derive(Clone, Default)] pub struct Table {} impl Table { pub fn operator_index(i: i32) -> Ptr { @@ -40,13 +40,6 @@ impl Table { return (table_0.with(|v| v.as_pointer()) as Ptr).offset((*i.borrow())); } } -impl Clone for Table { - fn clone(&self) -> Self { - let __this: Value = Rc::new(RefCell::new(Self {})); - let this: Ptr
= __this.as_pointer(); - Rc::try_unwrap(__this).ok().unwrap().into_inner() - } -} impl ByteRepr for Table { fn byte_size() -> usize { 1 diff --git a/tests/unit/out/refcount/operator_other_member.rs b/tests/unit/out/refcount/operator_other_member.rs index fbd3e5c22..930b78f63 100644 --- a/tests/unit/out/refcount/operator_other_member.rs +++ b/tests/unit/out/refcount/operator_other_member.rs @@ -6,7 +6,7 @@ use std::io::prelude::*; use std::io::{Read, Seek, Write}; use std::os::fd::AsFd; use std::rc::{Rc, Weak}; -#[derive(Default)] +#[derive(Clone, Default)] pub struct Static {} impl Static { pub fn operator_call(a: i32, b: i32) -> i32 { @@ -15,13 +15,6 @@ impl Static { return ((*a.borrow()) * (*b.borrow())); } } -impl Clone for Static { - fn clone(&self) -> Self { - let __this: Value = Rc::new(RefCell::new(Self {})); - let this: Ptr = __this.as_pointer(); - Rc::try_unwrap(__this).ok().unwrap().into_inner() - } -} impl ByteRepr for Static { fn byte_size() -> usize { 1 diff --git a/tests/unit/out/refcount/polymorphism.rs b/tests/unit/out/refcount/polymorphism.rs index ecceb0753..8a78db664 100644 --- a/tests/unit/out/refcount/polymorphism.rs +++ b/tests/unit/out/refcount/polymorphism.rs @@ -9,20 +9,13 @@ use std::rc::{Rc, Weak}; pub trait Animal { fn bark(&self) -> bool; } -#[derive(Default)] +#[derive(Clone, Default)] pub struct Dog {} impl Animal for Dog { fn bark(&self) -> bool { return true; } } -impl Clone for Dog { - fn clone(&self) -> Self { - let __this: Value = Rc::new(RefCell::new(Self {})); - let this: Ptr = __this.as_pointer(); - Rc::try_unwrap(__this).ok().unwrap().into_inner() - } -} impl ByteRepr for Dog { fn byte_size() -> usize { 8 @@ -32,20 +25,13 @@ impl ByteRepr for Dog { Self {} } } -#[derive(Default)] +#[derive(Clone, Default)] pub struct Cat {} impl Animal for Cat { fn bark(&self) -> bool { return false; } } -impl Clone for Cat { - fn clone(&self) -> Self { - let __this: Value = Rc::new(RefCell::new(Self {})); - let this: Ptr = __this.as_pointer(); - Rc::try_unwrap(__this).ok().unwrap().into_inner() - } -} impl ByteRepr for Cat { fn byte_size() -> usize { 8 diff --git a/tests/unit/out/refcount/random.rs b/tests/unit/out/refcount/random.rs index e81f828cd..ba8f0cdf0 100644 --- a/tests/unit/out/refcount/random.rs +++ b/tests/unit/out/refcount/random.rs @@ -58,15 +58,8 @@ impl ByteRepr for Pair {} pub fn zero_0() -> i32 { return 0; } -#[derive(Default)] +#[derive(Clone, Default)] pub struct X1 {} -impl Clone for X1 { - fn clone(&self) -> Self { - let __this: Value = Rc::new(RefCell::new(Self {})); - let this: Ptr = __this.as_pointer(); - Rc::try_unwrap(__this).ok().unwrap().into_inner() - } -} impl ByteRepr for X1 { fn byte_size() -> usize { 1 diff --git a/tests/unit/out/refcount/stable_sort.rs b/tests/unit/out/refcount/stable_sort.rs index 5ed2d31df..dc26d917d 100644 --- a/tests/unit/out/refcount/stable_sort.rs +++ b/tests/unit/out/refcount/stable_sort.rs @@ -13,14 +13,8 @@ pub fn main() { fn main_0() -> i32 { let arr1: Value> = Rc::new(RefCell::new(Box::new([5, 2, 8, 1, 3]))); { - let fun = |x: Ptr, y: Ptr| { - (|x: i32, y: i32| { - let x: Value = Rc::new(RefCell::new(x)); - let y: Value = Rc::new(RefCell::new(y)); - return ((*x.borrow()) < (*y.borrow())); - }) - .call((x.read()).clone(), (y.read()).clone()) - }; + let fun = + |x: Ptr, y: Ptr| (lambda_0 {}).call((x.read()).clone(), (y.read()).clone()); (arr1.as_pointer() as Ptr).sort_with_cmp( (arr1.as_pointer() as Ptr) .offset((5) as isize) @@ -30,4 +24,32 @@ fn main_0() -> i32 { }; return 0; } +#[derive(Clone, Default)] +pub struct lambda_0 {} +impl lambda_0 { + pub fn operator_call(x: i32, y: i32) -> bool { + let x: Value = Rc::new(RefCell::new(x)); + let y: Value = Rc::new(RefCell::new(y)); + return ((*x.borrow()) < (*y.borrow())); + } +} +impl ByteRepr for lambda_0 { + fn byte_size() -> usize { + 1 + } + fn to_bytes(&self, buf: &mut [u8]) {} + fn from_bytes(buf: &[u8]) -> Self { + Self {} + } +} +impl Callable2 for lambda_0 { + fn call(&self, a1: i32, a2: i32) -> bool { + { lambda_0::operator_call(a1, a2) } + } +} +impl lambda_0 { + pub fn to_free_function(&self) -> FnPtr bool> { + FnPtr::new(lambda_0::operator_call) + } +} pub fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/refcount/static_var_in_class.rs b/tests/unit/out/refcount/static_var_in_class.rs index 25170f912..0996ec9ff 100644 --- a/tests/unit/out/refcount/static_var_in_class.rs +++ b/tests/unit/out/refcount/static_var_in_class.rs @@ -9,15 +9,8 @@ use std::rc::{Rc, Weak}; thread_local!( static inner_const_0: Value = Rc::new(RefCell::new(1)); ); -#[derive(Default)] +#[derive(Clone, Default)] pub struct C {} -impl Clone for C { - fn clone(&self) -> Self { - let __this: Value = Rc::new(RefCell::new(Self {})); - let this: Ptr = __this.as_pointer(); - Rc::try_unwrap(__this).ok().unwrap().into_inner() - } -} impl ByteRepr for C { fn byte_size() -> usize { 1 @@ -30,15 +23,8 @@ impl ByteRepr for C { thread_local!( pub static inner_const_1: Value = Rc::new(RefCell::new(2)); ); -#[derive(Default)] +#[derive(Clone, Default)] pub struct S {} -impl Clone for S { - fn clone(&self) -> Self { - let __this: Value = Rc::new(RefCell::new(Self {})); - let this: Ptr = __this.as_pointer(); - Rc::try_unwrap(__this).ok().unwrap().into_inner() - } -} impl ByteRepr for S { fn byte_size() -> usize { 1 diff --git a/tests/unit/out/refcount/vector_with_allocator.rs b/tests/unit/out/refcount/vector_with_allocator.rs index 9787e6eab..401a0f8c2 100644 --- a/tests/unit/out/refcount/vector_with_allocator.rs +++ b/tests/unit/out/refcount/vector_with_allocator.rs @@ -6,15 +6,8 @@ use std::io::prelude::*; use std::io::{Read, Seek, Write}; use std::os::fd::AsFd; use std::rc::{Rc, Weak}; -#[derive(Default)] +#[derive(Clone, Default)] pub struct TestAllocator_int_ {} -impl Clone for TestAllocator_int_ { - fn clone(&self) -> Self { - let __this: Value = Rc::new(RefCell::new(Self {})); - let this: Ptr = __this.as_pointer(); - Rc::try_unwrap(__this).ok().unwrap().into_inner() - } -} impl ByteRepr for TestAllocator_int_ { fn byte_size() -> usize { 1 @@ -24,15 +17,8 @@ impl ByteRepr for TestAllocator_int_ { Self {} } } -#[derive(Default)] +#[derive(Clone, Default)] pub struct TestAllocator_double_ {} -impl Clone for TestAllocator_double_ { - fn clone(&self) -> Self { - let __this: Value = Rc::new(RefCell::new(Self {})); - let this: Ptr = __this.as_pointer(); - Rc::try_unwrap(__this).ok().unwrap().into_inner() - } -} impl ByteRepr for TestAllocator_double_ { fn byte_size() -> usize { 1 diff --git a/tests/unit/out/unsafe/fn_ptr_default_arg.rs b/tests/unit/out/unsafe/fn_ptr_default_arg.rs index dfd44d75e..00a52db97 100644 --- a/tests/unit/out/unsafe/fn_ptr_default_arg.rs +++ b/tests/unit/out/unsafe/fn_ptr_default_arg.rs @@ -26,10 +26,26 @@ unsafe fn main_0() -> i32 { assert!(((unsafe { apply_1(5, None,) }) == (5))); assert!(((unsafe { apply_1(5, Some(None),) }) == (5))); assert!(((unsafe { apply_1(5, Some(Some(identity_0)),) }) == (5))); - let mut negate: Option i32> = Some(|x: i32| { - return -x; - }); + let mut negate: Option i32> = (unsafe { (lambda_2 {}).to_free_function() }); assert!(((unsafe { apply_1(5, Some(negate),) }) == (-5_i32))); return 0; } +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_2 {} +impl lambda_2 { + pub unsafe fn operator_call(mut x: i32) -> i32 { + return -x; + } +} +impl Callable1 for lambda_2 { + fn call(&self, a1: i32) -> i32 { + unsafe { lambda_2::operator_call(a1) } + } +} +impl lambda_2 { + pub fn to_free_function(&self) -> Option i32> { + Some(lambda_2::operator_call) + } +} pub unsafe fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/unsafe/lambda_as_template_argument.rs b/tests/unit/out/unsafe/lambda_as_template_argument.rs new file mode 100644 index 000000000..a0af4388f --- /dev/null +++ b/tests/unit/out/unsafe/lambda_as_template_argument.rs @@ -0,0 +1,91 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::{Read, Seek, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +pub unsafe fn apply_0(mut fn_: lambda_1, mut x: i32) -> i32 { + return (unsafe { lambda_1::operator_call(&fn_, x) }); +} +pub unsafe fn apply_2(mut fn_: lambda_3, mut x: i32) -> i32 { + return (unsafe { lambda_3::operator_call(&fn_, x) }); +} +pub unsafe fn apply_4(mut fn_: lambda_5, mut x: i32) -> i32 { + return (unsafe { lambda_5::operator_call(x) }); +} +pub unsafe fn apply_twice_6(mut fn_: lambda_3, mut x: i32) -> i32 { + return (unsafe { + let _x: i32 = (unsafe { lambda_3::operator_call(&fn_, x) }); + lambda_3::operator_call(&fn_, _x) + }); +} +pub fn main() { + unsafe { + __cpp2rust_init_globals(); + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut base: i32 = 10; + let mut add_base: lambda_1 = (lambda_1 { base: &mut base }); + assert!(((unsafe { apply_0(add_base, 5,) }) == (15))); + base = 100; + assert!(((unsafe { apply_0(add_base, 5,) }) == (105))); + let mut factor: i32 = 3; + let mut scale: lambda_3 = (lambda_3 { factor: factor }); + assert!(((unsafe { apply_2(scale, 4,) }) == (12))); + assert!(((unsafe { apply_twice_6(scale, 4,) }) == (36))); + assert!(((unsafe { apply_4((lambda_5 {}), 9,) }) == (-9_i32))); + return 0; +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_1 { + base: *mut i32, +} +impl lambda_1 { + pub unsafe fn operator_call(&self, mut x: i32) -> i32 { + return ((x) + (*self.base)); + } +} +impl Callable1 for lambda_1 { + fn call(&self, a1: i32) -> i32 { + unsafe { lambda_1::operator_call(self, a1) } + } +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_3 { + factor: i32, +} +impl lambda_3 { + pub unsafe fn operator_call(&self, mut x: i32) -> i32 { + return ((x) * (self.factor)); + } +} +impl Callable1 for lambda_3 { + fn call(&self, a1: i32) -> i32 { + unsafe { lambda_3::operator_call(self, a1) } + } +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_5 {} +impl lambda_5 { + pub unsafe fn operator_call(mut x: i32) -> i32 { + return -x; + } +} +impl Callable1 for lambda_5 { + fn call(&self, a1: i32) -> i32 { + unsafe { lambda_5::operator_call(a1) } + } +} +impl lambda_5 { + pub fn to_free_function(&self) -> Option i32> { + Some(lambda_5::operator_call) + } +} +pub unsafe fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/unsafe/lambda_basic.rs b/tests/unit/out/unsafe/lambda_basic.rs new file mode 100644 index 000000000..49bc4ba63 --- /dev/null +++ b/tests/unit/out/unsafe/lambda_basic.rs @@ -0,0 +1,125 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::{Read, Seek, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +pub fn main() { + unsafe { + __cpp2rust_init_globals(); + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut zero: lambda_0 = (lambda_0 {}); + assert!(((unsafe { lambda_0::operator_call() }) == (42))); + let mut one: lambda_1 = (lambda_1 {}); + assert!(((unsafe { lambda_1::operator_call(1,) }) == (2))); + let mut three: lambda_2 = (lambda_2 {}); + assert!(((unsafe { lambda_2::operator_call(1, 2, 3,) }) == (123))); + let mut hits: i32 = 0; + let mut no_return: lambda_3 = (lambda_3 { hits: &mut hits }); + (unsafe { lambda_3::operator_call(&no_return, 3) }); + (unsafe { lambda_3::operator_call(&no_return, 4) }); + assert!(((hits) == (7))); + let mut a: i32 = 2; + let mut b: i32 = 3; + let mut product: i32 = (unsafe { + lambda_4::operator_call( + &(lambda_4 { + a: &mut a, + b: &mut b, + }), + ) + }); + assert!(((product) == (6))); + return 0; +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_0 {} +impl lambda_0 { + pub unsafe fn operator_call() -> i32 { + return 42; + } +} +impl Callable0 for lambda_0 { + fn call(&self) -> i32 { + unsafe { lambda_0::operator_call() } + } +} +impl lambda_0 { + pub fn to_free_function(&self) -> Option i32> { + Some(lambda_0::operator_call) + } +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_1 {} +impl lambda_1 { + pub unsafe fn operator_call(mut x: i32) -> i32 { + return ((x) + (1)); + } +} +impl Callable1 for lambda_1 { + fn call(&self, a1: i32) -> i32 { + unsafe { lambda_1::operator_call(a1) } + } +} +impl lambda_1 { + pub fn to_free_function(&self) -> Option i32> { + Some(lambda_1::operator_call) + } +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_2 {} +impl lambda_2 { + pub unsafe fn operator_call(mut x: i32, mut y: i32, mut z: i32) -> i32 { + return ((((x) * (100)) + ((y) * (10))) + (z)); + } +} +impl Callable3 for lambda_2 { + fn call(&self, a1: i32, a2: i32, a3: i32) -> i32 { + unsafe { lambda_2::operator_call(a1, a2, a3) } + } +} +impl lambda_2 { + pub fn to_free_function(&self) -> Option i32> { + Some(lambda_2::operator_call) + } +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_3 { + hits: *mut i32, +} +impl lambda_3 { + pub unsafe fn operator_call(&self, mut by: i32) { + (*self.hits) += by; + } +} +impl Callable1 for lambda_3 { + fn call(&self, a1: i32) -> () { + unsafe { lambda_3::operator_call(self, a1) } + } +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_4 { + a: *mut i32, + b: *mut i32, +} +impl lambda_4 { + pub unsafe fn operator_call(&self) -> i32 { + return ((*self.a) * (*self.b)); + } +} +impl Callable0 for lambda_4 { + fn call(&self) -> i32 { + unsafe { lambda_4::operator_call(self) } + } +} +pub unsafe fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/unsafe/lambda_capture_implicit.rs b/tests/unit/out/unsafe/lambda_capture_implicit.rs new file mode 100644 index 000000000..a7e2a5f04 --- /dev/null +++ b/tests/unit/out/unsafe/lambda_capture_implicit.rs @@ -0,0 +1,92 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::{Read, Seek, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +pub fn main() { + unsafe { + __cpp2rust_init_globals(); + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut a: i32 = 1; + let mut b: i32 = 2; + let mut c: i32 = 3; + let mut by_value: lambda_0 = (lambda_0 { a: a, b: b, c: c }); + assert!(((unsafe { lambda_0::operator_call(&by_value, 10,) }) == (16))); + a = 100; + assert!(((unsafe { lambda_0::operator_call(&by_value, 10,) }) == (16))); + let mut by_ref: lambda_1 = (lambda_1 { + a: &mut a, + b: &mut b, + c: &mut c, + }); + assert!(((unsafe { lambda_1::operator_call(&by_ref, 10,) }) == (115))); + b = 200; + assert!(((unsafe { lambda_1::operator_call(&by_ref, 10,) }) == (313))); + let mut mixed: lambda_2 = (lambda_2 { + c: &mut c, + a: a, + b: b, + }); + assert!(((unsafe { lambda_2::operator_call(&mixed, 1,) }) == (((100) + (200)) + (4)))); + assert!(((c) == (4))); + return 0; +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_0 { + a: i32, + b: i32, + c: i32, +} +impl lambda_0 { + pub unsafe fn operator_call(&self, mut x: i32) -> i32 { + return ((((self.a) + (self.b)) + (self.c)) + (x)); + } +} +impl Callable1 for lambda_0 { + fn call(&self, a1: i32) -> i32 { + unsafe { lambda_0::operator_call(self, a1) } + } +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_1 { + a: *mut i32, + b: *mut i32, + c: *mut i32, +} +impl lambda_1 { + pub unsafe fn operator_call(&self, mut x: i32) -> i32 { + return ((((*self.a) + (*self.b)) + (*self.c)) + (x)); + } +} +impl Callable1 for lambda_1 { + fn call(&self, a1: i32) -> i32 { + unsafe { lambda_1::operator_call(self, a1) } + } +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_2 { + c: *mut i32, + a: i32, + b: i32, +} +impl lambda_2 { + pub unsafe fn operator_call(&self, mut x: i32) -> i32 { + (*self.c) += x; + return (((self.a) + (self.b)) + (*self.c)); + } +} +impl Callable1 for lambda_2 { + fn call(&self, a1: i32) -> i32 { + unsafe { lambda_2::operator_call(self, a1) } + } +} +pub unsafe fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/unsafe/lambda_capture_pass.rs b/tests/unit/out/unsafe/lambda_capture_pass.rs deleted file mode 100644 index 900cca4ea..000000000 --- a/tests/unit/out/unsafe/lambda_capture_pass.rs +++ /dev/null @@ -1,60 +0,0 @@ -extern crate libc; -use libc::*; -extern crate libcc2rs; -use libcc2rs::*; -use std::collections::BTreeMap; -use std::io::{Read, Seek, Write}; -use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; -use std::rc::Rc; -pub unsafe fn apply_0(mut fn_: impl Fn(i32) -> i32, mut x: i32) -> i32 { - return (unsafe { fn_(x) }); -} -pub unsafe fn apply_1(mut fn_: impl Fn(i32) -> i32, mut x: i32) -> i32 { - return (unsafe { fn_(x) }); -} -pub fn main() { - unsafe { - __cpp2rust_init_globals(); - std::process::exit(main_0() as i32); - } -} -unsafe fn main_0() -> i32 { - let mut base: i32 = 10; - assert!( - ((unsafe { - apply_0( - (|x: i32| { - return ((x) + (base)); - }) - .clone(), - 5, - ) - }) == (15)) - ); - base = 100; - assert!( - ((unsafe { - apply_0( - (|x: i32| { - return ((x) + (base)); - }) - .clone(), - 5, - ) - }) == (105)) - ); - let mut factor: i32 = 3; - assert!( - ((unsafe { - apply_1( - (|x: i32| { - return ((x) * (factor)); - }) - .clone(), - 4, - ) - }) == (12)) - ); - return 0; -} -pub unsafe fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/unsafe/lambda_capture_ref.rs b/tests/unit/out/unsafe/lambda_capture_ref.rs new file mode 100644 index 000000000..a89edd891 --- /dev/null +++ b/tests/unit/out/unsafe/lambda_capture_ref.rs @@ -0,0 +1,108 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::{Read, Seek, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct S { + pub x: i32, + pub y: i32, +} +pub fn main() { + unsafe { + __cpp2rust_init_globals(); + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut base: i32 = 10; + let mut add_base: lambda_0 = (lambda_0 { base: &mut base }); + assert!(((unsafe { lambda_0::operator_call(&add_base, 5,) }) == (15))); + base = 100; + assert!(((unsafe { lambda_0::operator_call(&add_base, 5,) }) == (105))); + let mut s: S = S { x: 1, y: 2 }; + let mut sum: lambda_1 = (lambda_1 { s: &mut s }); + assert!(((unsafe { lambda_1::operator_call(&sum,) }) == (3))); + s.x = 50; + assert!(((unsafe { lambda_1::operator_call(&sum,) }) == (52))); + let mut counter: i32 = 0; + let mut bump: lambda_2 = (lambda_2 { + counter: &mut counter, + }); + (unsafe { lambda_2::operator_call(&bump) }); + (unsafe { lambda_2::operator_call(&bump) }); + assert!(((counter) == (2))); + let mut arr: [u16; 4] = [3_u16, 1_u16, 2_u16, 0_u16]; + let mut swap: lambda_3 = (lambda_3 { arr: &mut arr }); + (unsafe { lambda_3::operator_call(&swap, 0_usize, 3_usize) }); + assert!(((arr[(0) as usize] as i32) == (0))); + assert!(((arr[(3) as usize] as i32) == (3))); + return 0; +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_0 { + base: *mut i32, +} +impl lambda_0 { + pub unsafe fn operator_call(&self, mut x: i32) -> i32 { + return ((x) + (*self.base)); + } +} +impl Callable1 for lambda_0 { + fn call(&self, a1: i32) -> i32 { + unsafe { lambda_0::operator_call(self, a1) } + } +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_1 { + s: *mut S, +} +impl lambda_1 { + pub unsafe fn operator_call(&self) -> i32 { + return (((*self.s).x) + ((*self.s).y)); + } +} +impl Callable0 for lambda_1 { + fn call(&self) -> i32 { + unsafe { lambda_1::operator_call(self) } + } +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_2 { + counter: *mut i32, +} +impl lambda_2 { + pub unsafe fn operator_call(&self) { + (*self.counter).postfix_inc(); + } +} +impl Callable0<()> for lambda_2 { + fn call(&self) -> () { + unsafe { lambda_2::operator_call(self) } + } +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_3 { + arr: *mut [u16; 4], +} +impl lambda_3 { + pub unsafe fn operator_call(&self, mut i: usize, mut j: usize) { + let mut t: u16 = (*self.arr)[(j)]; + (*self.arr)[(j)] = (*self.arr)[(i)]; + (*self.arr)[(i)] = t; + } +} +impl Callable2 for lambda_3 { + fn call(&self, a1: usize, a2: usize) -> () { + unsafe { lambda_3::operator_call(self, a1, a2) } + } +} +pub unsafe fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/unsafe/lambda_capture_this.rs b/tests/unit/out/unsafe/lambda_capture_this.rs new file mode 100644 index 000000000..17e8ee87d --- /dev/null +++ b/tests/unit/out/unsafe/lambda_capture_this.rs @@ -0,0 +1,102 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::{Read, Seek, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct S { + pub n: i32, + pub step: i32, +} +impl S { + pub unsafe fn add(&mut self, mut k: i32) { + self.n += k; + } + pub unsafe fn scaled(&self) -> i32 { + return ((self.n) * (self.step)); + } + pub unsafe fn bump(&mut self, mut by: i32) { + let mut inc: lambda_0 = (lambda_0 { + this_: (self as *mut S), + }); + (unsafe { lambda_0::operator_call(&inc, by) }); + (unsafe { lambda_0::operator_call(&inc, by) }); + } + pub unsafe fn bump_via_method(&mut self, mut by: i32) { + let mut inc: lambda_1 = (lambda_1 { + this_: (self as *mut S), + }); + (unsafe { lambda_1::operator_call(&inc, by) }); + } + pub unsafe fn read_scaled(&self) -> i32 { + let mut get: lambda_2 = (lambda_2 { + this_: (self as *const S), + }); + return (unsafe { lambda_2::operator_call(&get) }); + } +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_0 { + this_: *mut S, +} +impl lambda_0 { + pub unsafe fn operator_call(&self, mut k: i32) { + (*self.this_).n += k; + } +} +impl Callable1 for lambda_0 { + fn call(&self, a1: i32) -> () { + unsafe { lambda_0::operator_call(self, a1) } + } +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_1 { + this_: *mut S, +} +impl lambda_1 { + pub unsafe fn operator_call(&self, mut k: i32) { + (unsafe { S::add(&mut (*self.this_), k) }); + } +} +impl Callable1 for lambda_1 { + fn call(&self, a1: i32) -> () { + unsafe { lambda_1::operator_call(self, a1) } + } +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_2 { + this_: *const S, +} +impl lambda_2 { + pub unsafe fn operator_call(&self) -> i32 { + return (unsafe { S::scaled(&(*self.this_)) }); + } +} +impl Callable0 for lambda_2 { + fn call(&self) -> i32 { + unsafe { lambda_2::operator_call(self) } + } +} +pub fn main() { + unsafe { + __cpp2rust_init_globals(); + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut s: S = S { n: 0, step: 2 }; + (unsafe { S::bump(&mut s, 3) }); + assert!(((s.n) == (6))); + (unsafe { S::bump_via_method(&mut s, 4) }); + assert!(((s.n) == (10))); + assert!(((unsafe { S::read_scaled(&s,) }) == (20))); + return 0; +} +pub unsafe fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/unsafe/lambda_capture_value.rs b/tests/unit/out/unsafe/lambda_capture_value.rs new file mode 100644 index 000000000..5415ae3d6 --- /dev/null +++ b/tests/unit/out/unsafe/lambda_capture_value.rs @@ -0,0 +1,101 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::{Read, Seek, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct S { + pub x: i32, + pub y: i32, +} +pub fn main() { + unsafe { + __cpp2rust_init_globals(); + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut factor: i32 = 3; + let mut scale: lambda_0 = (lambda_0 { factor: factor }); + assert!(((unsafe { lambda_0::operator_call(&scale, 4,) }) == (12))); + factor = 100; + assert!(((unsafe { lambda_0::operator_call(&scale, 4,) }) == (12))); + let mut slot: i32 = 7; + let mut p: *mut i32 = (&mut slot as *mut i32); + let mut read_ptr: lambda_1 = (lambda_1 { p: p }); + slot = 8; + assert!(((unsafe { lambda_1::operator_call(&read_ptr,) }) == (8))); + let mut s: S = S { x: 1, y: 2 }; + let mut sum: lambda_2 = (lambda_2 { s: s }); + s.x = 50; + assert!(((unsafe { lambda_2::operator_call(&sum,) }) == (3))); + let mut base: i32 = 10; + let mut shifted: lambda_3 = (lambda_3 { y: ((base) + (1)) }); + assert!(((unsafe { lambda_3::operator_call(&shifted, 5,) }) == (16))); + return 0; +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_0 { + factor: i32, +} +impl lambda_0 { + pub unsafe fn operator_call(&self, mut x: i32) -> i32 { + return ((x) * (self.factor)); + } +} +impl Callable1 for lambda_0 { + fn call(&self, a1: i32) -> i32 { + unsafe { lambda_0::operator_call(self, a1) } + } +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_1 { + p: *mut i32, +} +impl lambda_1 { + pub unsafe fn operator_call(&self) -> i32 { + return (*self.p); + } +} +impl Callable0 for lambda_1 { + fn call(&self) -> i32 { + unsafe { lambda_1::operator_call(self) } + } +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_2 { + s: S, +} +impl lambda_2 { + pub unsafe fn operator_call(&self) -> i32 { + return ((self.s.x) + (self.s.y)); + } +} +impl Callable0 for lambda_2 { + fn call(&self) -> i32 { + unsafe { lambda_2::operator_call(self) } + } +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_3 { + y: i32, +} +impl lambda_3 { + pub unsafe fn operator_call(&self, mut x: i32) -> i32 { + return ((x) + (self.y)); + } +} +impl Callable1 for lambda_3 { + fn call(&self, a1: i32) -> i32 { + unsafe { lambda_3::operator_call(self, a1) } + } +} +pub unsafe fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/unsafe/lambda_mutable.rs b/tests/unit/out/unsafe/lambda_mutable.rs new file mode 100644 index 000000000..ac77f664b --- /dev/null +++ b/tests/unit/out/unsafe/lambda_mutable.rs @@ -0,0 +1,50 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::{Read, Seek, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +pub fn main() { + unsafe { + __cpp2rust_init_globals(); + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut start: i32 = 5; + let mut next: lambda_0 = (lambda_0 { start: start }); + assert!(((unsafe { lambda_0::operator_call(&mut next,) }) == (5))); + assert!(((unsafe { lambda_0::operator_call(&mut next,) }) == (6))); + assert!(((unsafe { lambda_0::operator_call(&mut next,) }) == (7))); + assert!(((start) == (5))); + let mut total: i32 = 0; + let mut accumulate: lambda_1 = (lambda_1 { total: total }); + assert!(((unsafe { lambda_1::operator_call(&mut accumulate, 1,) }) == (1))); + assert!(((unsafe { lambda_1::operator_call(&mut accumulate, 2,) }) == (3))); + assert!(((total) == (0))); + return 0; +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_0 { + start: i32, +} +impl lambda_0 { + pub unsafe fn operator_call(&mut self) -> i32 { + return self.start.postfix_inc(); + } +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_1 { + total: i32, +} +impl lambda_1 { + pub unsafe fn operator_call(&mut self, mut x: i32) -> i32 { + self.total += x; + return self.total; + } +} +pub unsafe fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/unsafe/lambda_nested.rs b/tests/unit/out/unsafe/lambda_nested.rs index d36a62c9c..a5e43f6e8 100644 --- a/tests/unit/out/unsafe/lambda_nested.rs +++ b/tests/unit/out/unsafe/lambda_nested.rs @@ -6,6 +6,54 @@ use std::collections::BTreeMap; use std::io::{Read, Seek, Write}; use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; use std::rc::Rc; +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct S { + pub v: i32, +} +impl S { + pub unsafe fn nested_this(&mut self) -> i32 { + let mut outer: lambda_0 = (lambda_0 { + this_: (self as *mut S), + }); + return (unsafe { lambda_0::operator_call(&outer, 20) }); + } +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_1 { + this_: *mut S, + y: i32, +} +impl lambda_1 { + pub unsafe fn operator_call(&self, mut z: i32) -> i32 { + return ((((*self.this_).v) + (self.y)) + (z)); + } +} +impl Callable1 for lambda_1 { + fn call(&self, a1: i32) -> i32 { + unsafe { lambda_1::operator_call(self, a1) } + } +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_0 { + this_: *mut S, +} +impl lambda_0 { + pub unsafe fn operator_call(&self, mut y: i32) -> i32 { + let mut inner: lambda_1 = (lambda_1 { + this_: self.this_, + y: y, + }); + return (unsafe { lambda_1::operator_call(&inner, 1) }); + } +} +impl Callable1 for lambda_0 { + fn call(&self, a1: i32) -> i32 { + unsafe { lambda_0::operator_call(self, a1) } + } +} pub fn main() { unsafe { __cpp2rust_init_globals(); @@ -14,29 +62,44 @@ pub fn main() { } unsafe fn main_0() -> i32 { let mut x: i32 = 10; - assert!( - ((unsafe { - (|y: i32| { - return (unsafe { - (|z: i32| { - return (((x) + (y)) + (z)); - })(1) - }); - })(20) - }) == (31)) - ); + let mut outer: lambda_2 = (lambda_2 { x: &mut x }); + assert!(((unsafe { lambda_2::operator_call(&outer, 20,) }) == (31))); x = 100; - assert!( - ((unsafe { - (|y: i32| { - return (unsafe { - (|z: i32| { - return (((x) + (y)) + (z)); - })(1) - }); - })(20) - }) == (121)) - ); + assert!(((unsafe { lambda_2::operator_call(&outer, 20,) }) == (121))); + let mut s: S = S { v: 5 }; + assert!(((unsafe { S::nested_this(&mut s,) }) == (26))); return 0; } +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_3 { + x: *mut i32, + y: i32, +} +impl lambda_3 { + pub unsafe fn operator_call(&self, mut z: i32) -> i32 { + return (((*self.x) + (self.y)) + (z)); + } +} +impl Callable1 for lambda_3 { + fn call(&self, a1: i32) -> i32 { + unsafe { lambda_3::operator_call(self, a1) } + } +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_2 { + x: *mut i32, +} +impl lambda_2 { + pub unsafe fn operator_call(&self, mut y: i32) -> i32 { + let mut inner: lambda_3 = (lambda_3 { x: self.x, y: y }); + return (unsafe { lambda_3::operator_call(&inner, 1) }); + } +} +impl Callable1 for lambda_2 { + fn call(&self, a1: i32) -> i32 { + unsafe { lambda_2::operator_call(self, a1) } + } +} pub unsafe fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/unsafe/lambda_to_fn_ptr.rs b/tests/unit/out/unsafe/lambda_to_fn_ptr.rs new file mode 100644 index 000000000..7aa53ad9b --- /dev/null +++ b/tests/unit/out/unsafe/lambda_to_fn_ptr.rs @@ -0,0 +1,65 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::{Read, Seek, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +pub unsafe fn apply_0(mut x: i32, mut fn_: Option i32>) -> i32 { + return (unsafe { (fn_).unwrap()(x) }); +} +pub fn main() { + unsafe { + __cpp2rust_init_globals(); + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut fresh: Option i32> = (unsafe { (lambda_1 {}).to_free_function() }); + assert!(((unsafe { (fresh).unwrap()(5,) }) == (-5_i32))); + let mut twice: lambda_2 = (lambda_2 {}); + let mut named: Option i32> = (unsafe { twice.to_free_function() }); + assert!(((unsafe { (named).unwrap()(5,) }) == (10))); + assert!(((unsafe { apply_0(5, (unsafe { twice.to_free_function() }),) }) == (10))); + named = fresh; + assert!(((unsafe { (named).unwrap()(3,) }) == (-3_i32))); + return 0; +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_1 {} +impl lambda_1 { + pub unsafe fn operator_call(mut x: i32) -> i32 { + return -x; + } +} +impl Callable1 for lambda_1 { + fn call(&self, a1: i32) -> i32 { + unsafe { lambda_1::operator_call(a1) } + } +} +impl lambda_1 { + pub fn to_free_function(&self) -> Option i32> { + Some(lambda_1::operator_call) + } +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_2 {} +impl lambda_2 { + pub unsafe fn operator_call(mut x: i32) -> i32 { + return ((x) * (2)); + } +} +impl Callable1 for lambda_2 { + fn call(&self, a1: i32) -> i32 { + unsafe { lambda_2::operator_call(a1) } + } +} +impl lambda_2 { + pub fn to_free_function(&self) -> Option i32> { + Some(lambda_2::operator_call) + } +} +pub unsafe fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/unsafe/stable_sort.rs b/tests/unit/out/unsafe/stable_sort.rs index d21a3882d..b4db88834 100644 --- a/tests/unit/out/unsafe/stable_sort.rs +++ b/tests/unit/out/unsafe/stable_sort.rs @@ -20,17 +20,9 @@ unsafe fn main_0() -> i32 { .offset((5) as isize) .offset_from(arr1.as_mut_ptr()) as usize; ::std::slice::from_raw_parts_mut(arr1.as_mut_ptr(), len).sort_by(|x, y| { - if (|x: i32, y: i32| { - return ((x) < (y)); - }) - .call(*x, *y) - { + if (lambda_0 {}).call(*x, *y) { std::cmp::Ordering::Less - } else if (|x: i32, y: i32| { - return ((x) < (y)); - }) - .call(*y, *x) - { + } else if (lambda_0 {}).call(*y, *x) { std::cmp::Ordering::Greater } else { std::cmp::Ordering::Equal @@ -39,4 +31,22 @@ unsafe fn main_0() -> i32 { }; return 0; } +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_0 {} +impl lambda_0 { + pub unsafe fn operator_call(mut x: i32, mut y: i32) -> bool { + return ((x) < (y)); + } +} +impl Callable2 for lambda_0 { + fn call(&self, a1: i32, a2: i32) -> bool { + unsafe { lambda_0::operator_call(a1, a2) } + } +} +impl lambda_0 { + pub fn to_free_function(&self) -> Option bool> { + Some(lambda_0::operator_call) + } +} pub unsafe fn __cpp2rust_init_globals() {}