diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index cc4a32dff0..a5bae5c706 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -879,6 +880,9 @@ void Converter::EmitRustStructOrUnion(clang::RecordDecl *decl) { EmitReprC(decl); } EmitDerives(decl); + if (auto *cxx = clang::dyn_cast(decl)) { + EmitConversionAttrs(cxx); + } EmitByteSizeAttr(decl); // Fields @@ -956,6 +960,41 @@ void Converter::EmitDerives(const clang::RecordDecl *decl) { StrCat(")]"); } +void Converter::EmitConversionAttrs(clang::CXXRecordDecl *decl) { + std::unordered_set from_types; + ForEachConvertingConstructor(decl, [&](clang::CXXConstructorDecl *ctor) { + auto *param = ctor->getParamDecl(0); + auto type = param->getType(); + auto source = + GetUnboxedTypeAsString(type.getNonReferenceType().getUnqualifiedType()); + bool is_move = type->isRValueReferenceType(); + if (!from_types.insert(source + (is_move ? "&&" : "")).second) { + return; + } + const char *kind = + !type->isReferenceType() ? "value" + : is_move || type.getNonReferenceType().isConstQualified() ? "ptr" + : "mut_ptr"; + StrCat(std::format( + "#[{}({}, {}, {}{})]", is_move ? "cpp_from_move" : "cpp_from", source, + GetCtorName(ctor), param->hasDefaultArg() ? "some_" : "", kind)); + }); + std::unordered_set into_types; + ForEachMethod(decl, [&](clang::CXXMethodDecl *method) { + if (!IsImplicitConversionOperator(method)) { + return; + } + auto *conversion = clang::cast(method); + auto target = GetUnboxedTypeAsString( + conversion->getConversionType().getUnqualifiedType()); + if (!into_types.insert(target).second) { + return; + } + StrCat( + std::format("#[cpp_into({}, {})]", target, GetMethodName(conversion))); + }); +} + void Converter::EmitReprC(clang::RecordDecl *decl) { if (decl->hasAttr()) { StrCat(std::format("#[repr(C, align({}))]", @@ -4208,6 +4247,10 @@ Converter::GetStructAttributes(const clang::RecordDecl *decl) { struct_attrs.emplace_back("MoveCtorUnsafe"); } + if (HasImplicitConversions(decl)) { + struct_attrs.emplace_back("CppFromUnsafe"); + } + if (HasCopyAssignOperator(decl)) { struct_attrs.emplace_back("CopyAssignUnsafe"); } @@ -4946,6 +4989,14 @@ std::string Converter::ConvertPlaceholder(clang::Expr *expr, clang::Expr *arg, ToStringBase(ctx_.getPointerType(elem))); } + if (auto *init = + RuleRegistry::BuildParamConversion(ctx_, expr, ph_ctx.arg_idx, arg)) { + Buffer buf(*this); + PushExprKind push(*this, ExprKind::RValue); + ConvertInit(init->getType(), init); + return std::move(buf).str(); + } + if (ph_ctx.needs_materialization()) { auto materialized = ph_ctx.materialize_ctx->GetOrMaterialize( static_cast(ph_ctx.materialize_idx), @@ -5093,11 +5144,6 @@ std::string Converter::ConvertIRFragment( result += t->text; } else if (auto *g = std::get_if(&frag)) { result += GetTemplateArgumentAsString(bindings[g->n - 1]); - } else if (auto *d = std::get_if(&frag)) { - auto &arg = bindings[d->n - 1]; - assert(arg.getKind() == clang::TemplateArgument::Type && - "default of a non-type generic"); - result += GetUnboxedDefaultAsString(arg.getAsType()); } else if (auto *ph = std::get_if(&frag)) { assert(expr && "placeholder outside an expression rule"); auto arg_idx = ph->n; @@ -5138,12 +5184,78 @@ std::string Converter::ConvertIRFragment( result += (*re)->prefix + ' ' + ConvertIRFragment((*re)->inner, bindings, expr, args, num_args, ctx); + } else if (auto *call = + std::get_if>(&frag)) { + result += ConvertGenericCall(**call, bindings, expr, args, num_args, ctx); } } return result; } +std::string +Converter::ConvertGenericCall(const TranslationRule::GenericCallFragment &call, + llvm::ArrayRef bindings, + clang::Expr *expr, clang::Expr **args, + unsigned num_args, TempMaterializationCtx *ctx) { + std::vector call_args; + for (const auto &arg : call.args) { + call_args.push_back( + ConvertIRFragment(arg, bindings, expr, args, num_args, ctx)); + } + clang::QualType type; + if (call.generic <= bindings.size() && + bindings[call.generic - 1].getKind() == clang::TemplateArgument::Type) { + type = bindings[call.generic - 1].getAsType(); + } else { + assert(expr && "unbound generic outside an expression rule"); + type = RuleRegistry::GetGenericType(ctx_, expr, call.generic); + } + if (call.method == "default") { + assert(call_args.empty() && "default takes no arguments"); + return GetUnboxedDefaultAsString(type); + } + if (call.method == "cpp_from" || call.method == "cpp_from_move") { + assert(call_args.size() == 1 && "cpp_from takes one argument"); + return ConvertConversion( + type, RuleRegistry::GetConversionSourceType(ctx_, expr, call.generic), + call.method == "cpp_from_move", call_args[0]); + } + return std::format("<{}>::{}({})", GetUnboxedTypeAsString(type), call.method, + llvm::join(call_args, ", ")); +} + +std::string Converter::ConvertConversion(clang::QualType to, + clang::QualType from, bool is_move, + const std::string &ptr) { + if (to->isArithmeticType() && from->isArithmeticType()) { + auto value = DerefPtrExpr(ptr, from); + if (ctx_.hasSameUnqualifiedType(to, from)) { + return value; + } + if (to->isBooleanType()) { + return std::format("({} != {})", value, + from->isFloatingType() ? "0.0" : "0"); + } + if (from->isBooleanType() && to->isFloatingType()) { + return std::format("({} as u8 as {})", value, GetUnsafeTypeAsString(to)); + } + return std::format("({} as {})", value, GetUnsafeTypeAsString(to)); + } + return std::format("<{} as {}<{}>>::{}({})", GetUnboxedTypeAsString(to), + GetConversionTraitName(), GetUnboxedTypeAsString(from), + is_move ? "cpp_from_move" : "cpp_from", ptr); +} + +const char *Converter::GetConversionTraitName() const { + return "CppFromUnsafe"; +} + +std::string Converter::DerefPtrExpr(std::string_view ptr_expr, + clang::QualType pointee_type) { + return std::format("({}{})", GetPointerDerefPrefix(pointee_type), ptr_expr); +} + std::string Converter::ConvertVariadicTail(clang::Expr *expr, const std::vector &all_args) { @@ -5180,14 +5292,18 @@ void Converter::ConvertConstructFromArgs(clang::QualType type, clang::SourceLocation loc) { auto *init = BuildInitExpr(GetSema(), type, args, loc); assert(init && "type cannot be initialized from the arguments"); - if (auto *ctor = - clang::dyn_cast(init->IgnoreImplicit())) { - ConvertConstructedValue(type, ctor); + if (args.empty() && + !clang::isa(init->IgnoreImplicit())) { + StrCat(GetDefaultAsString(type)); return; } + ConvertInit(type, init); +} - if (args.empty()) { - StrCat(GetDefaultAsString(type)); +void Converter::ConvertInit(clang::QualType type, clang::Expr *init) { + if (auto *ctor = + clang::dyn_cast(init->IgnoreImplicit())) { + ConvertConstructedValue(type, ctor); return; } Convert(init); diff --git a/cpp2rust/converter/converter.h b/cpp2rust/converter/converter.h index f6ba0973cf..65eae3dac7 100644 --- a/cpp2rust/converter/converter.h +++ b/cpp2rust/converter/converter.h @@ -178,6 +178,9 @@ class Converter : public clang::RecursiveASTVisitor { void EmitReprC(clang::RecordDecl *decl); void EmitDerives(const clang::RecordDecl *decl); + + void EmitConversionAttrs(clang::CXXRecordDecl *decl); + virtual void EmitRustUnion(clang::RecordDecl *decl); virtual bool EmitsReprCForRecords() const { return true; } @@ -304,6 +307,20 @@ class Converter : public clang::RecursiveASTVisitor { clang::Expr *expr, clang::Expr **args, unsigned num_args, TempMaterializationCtx *ctx); + std::string + ConvertGenericCall(const TranslationRule::GenericCallFragment &call, + llvm::ArrayRef bindings, + clang::Expr *expr, clang::Expr **args, unsigned num_args, + TempMaterializationCtx *ctx); + + std::string ConvertConversion(clang::QualType to, clang::QualType from, + bool is_move, const std::string &ptr); + + virtual const char *GetConversionTraitName() const; + + virtual std::string DerefPtrExpr(std::string_view ptr_expr, + clang::QualType pointee_type); + struct PlaceholderCtx { unsigned arg_idx; std::optional implicit_convert_to; @@ -866,6 +883,8 @@ class Converter : public clang::RecursiveASTVisitor { llvm::ArrayRef args, clang::SourceLocation loc); + void ConvertInit(clang::QualType type, clang::Expr *init); + virtual void ConvertConstructedValue(clang::QualType type, clang::CXXConstructExpr *ctor); diff --git a/cpp2rust/converter/converter_lib.cpp b/cpp2rust/converter/converter_lib.cpp index 8daca90de6..409acc74ac 100644 --- a/cpp2rust/converter/converter_lib.cpp +++ b/cpp2rust/converter/converter_lib.cpp @@ -543,6 +543,50 @@ bool IsConvertibleMoveConstructor(const clang::CXXConstructorDecl *ctor) { return ctor->isUserProvided() || NeedsDefaultedMoveConstructor(parent); } +static bool +IsImplicitConvertingConstructor(const clang::CXXConstructorDecl *ctor) { + return !ctor->isCopyOrMoveConstructor() && !ctor->isImplicit() && + !ctor->isDeleted() && ctor->hasBody() && ctor->getNumParams() == 1 && + ctor->isConvertingConstructor(/*AllowExplicit=*/false); +} + +void ForEachConvertingConstructor( + clang::CXXRecordDecl *decl, + llvm::function_ref fn) { + for (auto *ctor : decl->ctors()) { + if (IsImplicitConvertingConstructor(ctor)) { + fn(ctor); + } + } + for (auto *ctor : GetTemplateInstantiatedCtors(decl)) { + if (IsImplicitConvertingConstructor(ctor)) { + fn(ctor); + } + } +} + +bool IsImplicitConversionOperator(const clang::CXXMethodDecl *method) { + auto *conversion = clang::dyn_cast(method); + return conversion && !conversion->isExplicit() && !conversion->isDeleted() && + conversion->hasBody() && + !conversion->getConversionType()->isReferenceType(); +} + +bool HasImplicitConversions(const clang::RecordDecl *decl) { + auto *cxx = clang::dyn_cast(decl); + if (!cxx || !IsUserDefinedDecl(cxx)) { + return false; + } + bool found = false; + ForEachConvertingConstructor( + const_cast(cxx), + [&](clang::CXXConstructorDecl *) { found = true; }); + ForEachMethod(cxx, [&](clang::CXXMethodDecl *method) { + found = found || IsImplicitConversionOperator(method); + }); + return found; +} + bool HasMoveFromConstructor(const clang::RecordDecl *decl) { auto *cxx = clang::dyn_cast(decl); return cxx && llvm::any_of(cxx->ctors(), [](auto *ctor) { diff --git a/cpp2rust/converter/converter_lib.h b/cpp2rust/converter/converter_lib.h index feba03343f..2ebaa52627 100644 --- a/cpp2rust/converter/converter_lib.h +++ b/cpp2rust/converter/converter_lib.h @@ -105,6 +105,14 @@ bool IsConvertibleMoveConstructor(const clang::CXXConstructorDecl *ctor); // Whether decl has a move constructor converted to a move_from method. bool HasMoveFromConstructor(const clang::RecordDecl *decl); +void ForEachConvertingConstructor( + clang::CXXRecordDecl *decl, + llvm::function_ref fn); + +bool IsImplicitConversionOperator(const clang::CXXMethodDecl *method); + +bool HasImplicitConversions(const clang::RecordDecl *decl); + bool IsConvertibleMoveAssignment(const clang::CXXMethodDecl *method); bool IsConvertibleCopyAssignment(const clang::CXXMethodDecl *method); diff --git a/cpp2rust/converter/models/boxed_vars.cpp b/cpp2rust/converter/models/boxed_vars.cpp index f5f663405f..b5f7387a53 100644 --- a/cpp2rust/converter/models/boxed_vars.cpp +++ b/cpp2rust/converter/models/boxed_vars.cpp @@ -177,7 +177,9 @@ class AddressTakenVisitor if (auto *source = GetTrivialCopySource(expr)) { AddValueUse(source); } - AddRuleArgs(expr, expr->getArgs(), expr->getNumArgs()); + if (!expr->isElidable()) { + AddRuleArgs(expr, expr->getArgs(), expr->getNumArgs()); + } return true; } @@ -237,6 +239,10 @@ class AddressTakenVisitor auto all_args = BuildUnifiedArgs(expr, args, num_args); for (unsigned i = 0; i < all_args.size() && i < rule->params.size(); ++i) { auto *arg = IgnoreNoOpCasts(all_args[i]); + if (auto *init = RuleRegistry::BuildParamConversion(ctx_, expr, i, arg)) { + TraverseStmt(init); + continue; + } if (!rule->params[i].is_pointer() || arg->getType()->isPointerType() || RuleRegistry::MapsToPointer(ctx_, arg->getType())) { AddValueUse(arg); diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index 3550437fdb..58bd0793a4 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -2257,6 +2257,10 @@ ConverterRefCount::GetStructAttributes(const clang::RecordDecl *decl) { attrs.emplace_back("MoveCtor"); } + if (HasImplicitConversions(decl)) { + attrs.emplace_back("CppFrom"); + } + if (HasCopyAssignOperator(decl)) { attrs.emplace_back("CopyAssign"); } @@ -2276,6 +2280,10 @@ ConverterRefCount::GetStructAttributes(const clang::RecordDecl *decl) { return attrs; } +const char *ConverterRefCount::GetConversionTraitName() const { + return "CppFrom"; +} + bool ConverterRefCount::TypeDerivesDefault(clang::QualType qual_type) { // Arrays are translated to Value>, whose Default is empty return !qual_type->isArrayType() && Converter::TypeDerivesDefault(qual_type); diff --git a/cpp2rust/converter/models/converter_refcount.h b/cpp2rust/converter/models/converter_refcount.h index a99dd063ca..eef71cddf5 100644 --- a/cpp2rust/converter/models/converter_refcount.h +++ b/cpp2rust/converter/models/converter_refcount.h @@ -418,7 +418,9 @@ class ConverterRefCount final : public Converter { // Wraps a pointer expression with deref prefix/suffix: e.g. // "(*ptr.upgrade().deref())" or "(ptr.read())" std::string DerefPtrExpr(std::string_view ptr_expr, - clang::QualType pointee_type); + clang::QualType pointee_type) override; + + const char *GetConversionTraitName() const override; std::string GetInnerType(clang::QualType type); diff --git a/cpp2rust/converter/rules/registry.cpp b/cpp2rust/converter/rules/registry.cpp index 70790d78d3..f0e21f7812 100644 --- a/cpp2rust/converter/rules/registry.cpp +++ b/cpp2rust/converter/rules/registry.cpp @@ -87,18 +87,19 @@ clang::QualType getInitPattern(const clang::FunctionDecl *rule) { void collectGenerics(const std::vector &body, std::unordered_set &used) { - TranslationRule::AnyFragment( - body, [&](const TranslationRule::BodyFragment &fragment) { - if (auto generic = - std::get_if(&fragment)) { - used.insert(generic->n); - } - if (auto generic = - std::get_if(&fragment)) { - used.insert(generic->n); - } - return false; - }); + TranslationRule::AnyFragment(body, [&](const TranslationRule::BodyFragment + &fragment) { + if (auto generic = + std::get_if(&fragment)) { + used.insert(generic->n); + } + if (auto call = + std::get_if>( + &fragment)) { + used.insert((*call)->generic); + } + return false; + }); } void collectGenerics(llvm::StringRef type, std::unordered_set &used) { @@ -120,6 +121,27 @@ void collectGenerics(llvm::StringRef type, std::unordered_set &used) { } } +bool isBoundArgument(const TranslationRule::ExprRule &rule, unsigned n) { + return llvm::any_of(rule.generics, [&](const auto &bounds) { + return llvm::any_of(bounds, [&](const TranslationRule::Bound &bound) { + return llvm::is_contained(bound.args, n); + }); + }); +} + +unsigned iteratorOverGeneric(const TranslationRule::ExprRule &rule, + unsigned n) { + for (unsigned i = 0; i < rule.generics.size(); ++i) { + for (const auto &bound : rule.generics[i]) { + if (llvm::StringRef(bound.trait_name).ends_with("Iterator") && + llvm::is_contained(bound.args, n)) { + return i + 1; + } + } + } + return 0; +} + void checkGenerics(const std::string &dir, const std::string &name, const clang::FunctionDecl *decl, const TranslationRule::ExprRule &rule) { @@ -136,7 +158,8 @@ void checkGenerics(const std::string &dir, const std::string &name, collectGenerics(param.type, used); } for (unsigned i : used) { - if (!declared.contains(std::format("T{}", i))) { + if (!declared.contains(std::format("T{}", i)) && + !isBoundArgument(rule, i)) { llvm::errs() << dir << "::" << name << ": generic T" << i << " used by the target but missing from src\n"; llvm::report_fatal_error("Absent generic from src"); @@ -381,6 +404,46 @@ Matcher::Match Search(clang::ASTContext &ctx, getBindings(match.rule_decl->decl, match.args)}; } +clang::QualType iteratorElementType(clang::ASTContext &ctx, + clang::QualType iterator) { + iterator = iterator.getNonReferenceType().getUnqualifiedType(); + if (iterator->isPointerType()) { + return iterator->getPointeeType().getUnqualifiedType(); + } + auto [rule, bindings] = Search(ctx, iterator); + assert(rule && !bindings.empty() && + bindings[0].getKind() == clang::TemplateArgument::Type && + "iterator type rule declares no element generic T1"); + return bindings[0].getAsType(); +} + +clang::QualType GetGenericType(clang::ASTContext &ctx, const clang::Expr *expr, + unsigned n) { + auto [rule, bindings] = Search(ctx, expr); + assert(rule && "expression must have a translation rule"); + if (n <= bindings.size() && + bindings[n - 1].getKind() == clang::TemplateArgument::Type) { + return bindings[n - 1].getAsType(); + } + auto iterator = iteratorOverGeneric(*rule, n); + assert(iterator && + "generic is neither bound by the src nor the element of an iterator"); + return iteratorElementType(ctx, GetGenericType(ctx, expr, iterator)); +} + +clang::QualType GetConversionSourceType(clang::ASTContext &ctx, + const clang::Expr *expr, unsigned to) { + auto rule = Search(ctx, expr).first; + assert(rule && "expression must have a translation rule"); + for (const auto &bound : rule->generics.at(to - 1)) { + if (bound.trait_name == "CppFrom" || bound.trait_name == "CppFromUnsafe") { + assert(bound.args.size() == 1 && "CppFrom takes one generic"); + return GetGenericType(ctx, expr, bound.args[0]); + } + } + llvm::report_fatal_error("converted generic has no CppFrom bound"); +} + clang::QualType GetInitType(const clang::Expr *expr) { auto match = findExpr(expr); assert(match.rule_decl && "expression must have a translation rule"); @@ -461,6 +524,30 @@ bool ParamIsPointer(clang::ASTContext &ctx, const clang::Expr *expr, return rule->params.at(index).is_pointer(); } +clang::Expr *BuildParamConversion(clang::ASTContext &ctx, + const clang::Expr *expr, unsigned index, + clang::Expr *arg) { + auto [rule, bindings] = Search(ctx, expr); + assert(rule && "expression must have a translation rule"); + llvm::StringRef type = rule->params.at(index).type; + unsigned n = 0; + if (!type.consume_front("T") || type.empty() || type.getAsInteger(10, n)) { + return nullptr; + } + auto &binding = bindings.at(n - 1); + assert(binding.getKind() == clang::TemplateArgument::Type && + "parameter typed by a non-type generic"); + auto target = binding.getAsType(); + if ((arg->getType()->isArrayType() && target->isPointerType()) || + ctx.hasSameUnqualifiedType(arg->getType().getNonReferenceType(), + target)) { + return nullptr; + } + auto *init = BuildInitExpr(*sema_, target, arg, arg->getExprLoc()); + assert(init && "argument cannot be converted to the parameter type"); + return init; +} + bool IsLibcPassthrough(clang::ASTContext &ctx, const clang::Expr *expr) { const auto *tgt_ir = GetExprRule(ctx, expr); if (tgt_ir == nullptr || !tgt_ir->body.empty() || !tgt_ir->is_extern) { diff --git a/cpp2rust/converter/rules/registry.h b/cpp2rust/converter/rules/registry.h index 8de311400c..a84fb45611 100644 --- a/cpp2rust/converter/rules/registry.h +++ b/cpp2rust/converter/rules/registry.h @@ -38,12 +38,24 @@ Matcher::Match Search(clang::ASTContext &ctx, const TranslationRule::ExprRule *GetExprRule(clang::ASTContext &ctx, const clang::Expr *expr); clang::QualType GetInitType(const clang::Expr *expr); + +clang::QualType GetGenericType(clang::ASTContext &ctx, const clang::Expr *expr, + unsigned n); + +clang::QualType GetConversionSourceType(clang::ASTContext &ctx, + const clang::Expr *expr, unsigned to); + bool HasExprRule(const clang::FunctionDecl *decl); bool IsLibcPassthrough(clang::ASTContext &ctx, const clang::Expr *expr); bool ReturnsPointer(clang::ASTContext &ctx, const clang::Expr *expr); bool ReturnsReference(const clang::Expr *expr); bool ParamIsPointer(clang::ASTContext &ctx, const clang::Expr *expr, unsigned index); + +clang::Expr *BuildParamConversion(clang::ASTContext &ctx, + const clang::Expr *expr, unsigned index, + clang::Expr *arg); + bool MapsToPointer(clang::ASTContext &ctx, clang::QualType qual_type); bool MapsToRefcountPointer(clang::ASTContext &ctx, clang::QualType qual_type); diff --git a/cpp2rust/converter/translation_rule.cpp b/cpp2rust/converter/translation_rule.cpp index b8adc57408..f634a20aa4 100644 --- a/cpp2rust/converter/translation_rule.cpp +++ b/cpp2rust/converter/translation_rule.cpp @@ -3,6 +3,7 @@ #include "converter/translation_rule.h" +#include #include #include @@ -72,6 +73,21 @@ MethodCallFragment ParseMethodCallFragmentJSON(const llvm::json::Object &obj) { return mc; } +GenericCallFragment +ParseGenericCallFragmentJSON(const llvm::json::Object &obj) { + GenericCallFragment call; + call.generic = obj.getInteger("generic").value_or(0); + call.method = obj.getString("method").value_or("").str(); + if (auto *args = obj.getArray("args")) { + for (auto &arg : *args) { + if (auto *fragments = arg.getAsArray()) { + call.args.push_back(ParseBodyFragmentsJSON(*fragments)); + } + } + } + return call; +} + RefExprFragment ParseRefExprFragmentJSON(const llvm::json::Object &obj) { RefExprFragment re; re.prefix = obj.getString("prefix").value_or("").str(); @@ -91,8 +107,6 @@ std::vector ParseBodyFragmentsJSON(const llvm::json::Array &arr) { result.push_back(TextFragment{str->str()}); } else if (auto n = frag_obj->getInteger("generic")) { result.push_back(GenericFragment{(unsigned)*n}); - } else if (auto n = frag_obj->getInteger("default")) { - result.push_back(DefaultFragment{(unsigned)*n}); } else if (auto *ph = frag_obj->getObject("placeholder")) { result.push_back(ParsePlaceholderFragmentJSON(*ph)); } else if (auto *mc = frag_obj->getObject("method_call")) { @@ -101,6 +115,9 @@ std::vector ParseBodyFragmentsJSON(const llvm::json::Array &arr) { } else if (auto *re = frag_obj->getObject("ref_expr")) { result.push_back( std::make_unique(ParseRefExprFragmentJSON(*re))); + } else if (auto *call = frag_obj->getObject("generic_call")) { + result.push_back(std::make_unique( + ParseGenericCallFragmentJSON(*call))); } else if (frag_obj->get("va_args")) { result.push_back(VaArgsFragment{}); } else if (frag_obj->get("init")) { @@ -137,6 +154,11 @@ bool AnyFragment(const std::vector &body, if (auto *re = std::get_if>(&frag)) { return AnyFragment((*re)->inner, pred); } + if (auto *call = std::get_if>(&frag)) { + return llvm::any_of((*call)->args, [&](const auto &arg) { + return AnyFragment(arg, pred); + }); + } return false; }); } @@ -202,7 +224,10 @@ void ExprRule::dump() const { for (auto &bounds : generics) { log() << " generic T" << ++i << ':'; for (auto &b : bounds) { - log() << ' ' << b; + log() << ' ' << b.trait_name; + for (unsigned arg : b.args) { + log() << " T" << arg; + } } log() << '\n'; } @@ -232,9 +257,16 @@ void RefExprFragment::dump() const { } } -void GenericFragment::dump() const { log() << " generic: " << n << '\n'; } +void GenericCallFragment::dump() const { + log() << " generic_call: T" << generic << "::" << method << '\n'; + for (auto &arg : args) { + for (auto &frag : arg) { + BodyFragmentDump(frag); + } + } +} -void DefaultFragment::dump() const { log() << " default: " << n << '\n'; } +void GenericFragment::dump() const { log() << " generic: " << n << '\n'; } void TypeInfo::dump() const { log() << type; @@ -285,16 +317,33 @@ ExprRule ParseExprRuleJSON(const llvm::json::Object &obj) { if (auto *generics = obj.getObject("generics")) { for (auto &[key, val] : *generics) { - if (auto *arr = val.getAsArray()) { - std::vector bounds; - for (auto &b : *arr) { - if (auto s = b.getAsString()) - bounds.push_back(s->str()); + auto *arr = val.getAsArray(); + if (!arr) { + continue; + } + std::vector bounds; + for (auto &b : *arr) { + auto *bound = b.getAsObject(); + if (!bound) { + continue; + } + Bound parsed; + parsed.trait_name = bound->getString("trait").value_or("").str(); + if (auto *args = bound->getArray("args")) { + for (auto &arg : *args) { + llvm::StringRef name = arg.getAsString().value_or(""); + unsigned n = 0; + if (name.consume_front("T") && !name.empty() && + !name.getAsInteger(10, n)) { + parsed.args.push_back(n); + } + } } - size_t id = atoi(llvm::StringRef(key).data() + 1) - 1; // starts in T1 - ir.generics.resize(std::max(ir.generics.size(), id + 1)); - ir.generics[id] = std::move(bounds); + bounds.push_back(std::move(parsed)); } + size_t id = atoi(llvm::StringRef(key).data() + 1) - 1; // starts in T1 + ir.generics.resize(std::max(ir.generics.size(), id + 1)); + ir.generics[id] = std::move(bounds); } } diff --git a/cpp2rust/converter/translation_rule.h b/cpp2rust/converter/translation_rule.h index a923c6868c..1bb3ae9d4c 100644 --- a/cpp2rust/converter/translation_rule.h +++ b/cpp2rust/converter/translation_rule.h @@ -9,7 +9,6 @@ #include #include -#include #include #include @@ -41,12 +40,6 @@ struct GenericFragment { void dump() const; }; -struct DefaultFragment { - unsigned n; - - void dump() const; -}; - struct VaArgsFragment { void dump() const; }; @@ -57,12 +50,12 @@ struct InitFragment { struct MethodCallFragment; // forward declaration struct RefExprFragment; +struct GenericCallFragment; -using BodyFragment = - std::variant, - std::unique_ptr>; +using BodyFragment = std::variant< + TextFragment, PlaceholderFragment, GenericFragment, VaArgsFragment, + InitFragment, std::unique_ptr, + std::unique_ptr, std::unique_ptr>; struct MethodCallFragment { std::vector receiver; @@ -79,6 +72,19 @@ struct RefExprFragment { void dump() const; }; +struct GenericCallFragment { + unsigned generic; + std::string method; + std::vector> args; + + void dump() const; +}; + +struct Bound { + std::string trait_name; + std::vector args; +}; + // Whether pred holds for a fragment of body, or for one nested in them. bool AnyFragment(const std::vector &body, llvm::function_ref pred); @@ -97,7 +103,7 @@ struct TypeInfo { struct ExprRule { std::vector params; TypeInfo return_type; - std::vector> generics; // "T1" -> ["Ord", "Clone"] + std::vector> generics; // "T1" -> [Ord, Clone] std::vector body; bool multi_statement = false; bool is_extern = false; diff --git a/libcc2rs-macros/src/cpp_from.rs b/libcc2rs-macros/src/cpp_from.rs new file mode 100644 index 0000000000..aed5ec94d1 --- /dev/null +++ b/libcc2rs-macros/src/cpp_from.rs @@ -0,0 +1,220 @@ +// Copyright (c) 2022-present INESC-ID. +// Distributed under the MIT license that can be found in the LICENSE file. + +use proc_macro::TokenStream; +use proc_macro2::TokenStream as TokenStream2; +use quote::{format_ident, quote}; +use syn::parse::{Parse, ParseStream}; +use syn::{DeriveInput, Ident, Token, Type, parse_macro_input}; + +// #[derive(CppFrom)] +// #[cpp_from(i32, new, value)] // S(int) +// #[cpp_from(i32, new_1, some_value)] // S(int = 0) +// #[cpp_from(T, new_2, ptr)] // S(const T &) +// #[cpp_from(T, new_3, mut_ptr)] // S(T &) +// #[cpp_from_move(T, new_4, ptr)] // S(T &&) +// #[cpp_into(i32, to_i32)] // operator int() const +// pub struct S { ... } +// +// Implements libcc2rs::CppFrom for S with each converting constructor +// of S, and libcc2rs::CppFrom for each type S converts to with a +// conversion operator, such that the rules convert values as C++ does +// implicitly. `value` passes the pointee to the constructor, `ptr` the +// pointer, `mut_ptr` a mutable pointer, and `some_` wraps the argument in +// Some for a defaulted parameter. CppFromUnsafe is the same for the unsafe +// model. + +#[derive(Clone, Copy)] +enum Kind { + Value, + Ptr, + MutPtr, +} + +struct Conversion { + ty: Type, + method: Ident, + kind: Kind, + some: bool, +} + +impl Parse for Conversion { + fn parse(input: ParseStream) -> syn::Result { + let ty = input.parse()?; + input.parse::()?; + let method = input.parse()?; + let mut kind = Kind::Ptr; + let mut some = false; + if input.peek(Token![,]) { + input.parse::()?; + let spelled: Ident = input.parse()?; + let name = spelled.to_string(); + let name = match name.strip_prefix("some_") { + Some(rest) => { + some = true; + rest + } + None => name.as_str(), + }; + kind = match name { + "value" => Kind::Value, + "ptr" => Kind::Ptr, + "mut_ptr" => Kind::MutPtr, + _ => { + return Err(syn::Error::new( + spelled.span(), + "expected `value`, `ptr` or `mut_ptr`, optionally prefixed by `some_`", + )); + } + }; + } + Ok(Conversion { + ty, + method, + kind, + some, + }) + } +} + +#[derive(Default)] +struct Source { + from: Option, + from_move: Option, +} + +fn ctor_call( + name: &Ident, + conversion: &Conversion, + is_unsafe: bool, + is_move: bool, +) -> TokenStream2 { + let method = &conversion.method; + let arg = match (conversion.kind, is_unsafe) { + (Kind::Value, true) => quote!((*src).clone()), + (Kind::Value, false) => quote!(src.read()), + (Kind::MutPtr, true) if !is_move => quote!(src.cast_mut()), + (Kind::Ptr | Kind::MutPtr, _) => quote!(src), + }; + let arg = if conversion.some { + quote!(Some(#arg)) + } else { + arg + }; + quote!(#name::#method(#arg)) +} + +fn method(is_unsafe: bool, signature: TokenStream2, body: TokenStream2) -> TokenStream2 { + if is_unsafe { + quote! { unsafe #signature { unsafe { #body } } } + } else { + quote! { #signature { #body } } + } +} + +pub fn expand(input: TokenStream, is_unsafe: bool) -> TokenStream { + let input = parse_macro_input!(input as DeriveInput); + let name = &input.ident; + let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); + + let mut sources: Vec<(String, Source)> = Vec::new(); + let mut intos: Vec = Vec::new(); + for attr in &input.attrs { + let Some(attr_name) = attr.path().get_ident().map(ToString::to_string) else { + continue; + }; + let is_move = match attr_name.as_str() { + "cpp_from" => false, + "cpp_from_move" => true, + "cpp_into" => { + intos.push(attr.parse_args().expect("cpp_into(Type, method)")); + continue; + } + _ => continue, + }; + let conversion: Conversion = attr + .parse_args() + .expect("cpp_from(Type, method, value|ptr|mut_ptr)"); + let ty = &conversion.ty; + let key = quote!(#ty).to_string(); + let source = match sources.iter().position(|(k, _)| *k == key) { + Some(i) => &mut sources[i].1, + None => { + sources.push((key.clone(), Source::default())); + &mut sources.last_mut().unwrap().1 + } + }; + let slot = if is_move { + &mut source.from_move + } else { + &mut source.from + }; + assert!(slot.is_none(), "two conversions from {key}"); + *slot = Some(conversion); + } + + let tr = if is_unsafe { + quote!(::libcc2rs::CppFromUnsafe) + } else { + quote!(::libcc2rs::CppFrom) + }; + let pointer = |ty: &Type, is_mut: bool| { + if is_unsafe && is_mut { + quote!(*mut #ty) + } else if is_unsafe { + quote!(*const #ty) + } else { + quote!(::libcc2rs::Ptr<#ty>) + } + }; + + let from_impls = sources.iter().map(|(_, source)| { + let any = source.from.as_ref().or(source.from_move.as_ref()).unwrap(); + let ty = &any.ty; + let src = pointer(ty, false); + let from_body = match &source.from { + Some(conversion) => ctor_call(name, conversion, is_unsafe, false), + None => quote!(unreachable!("no conversion from an lvalue")), + }; + let from_fn = method(is_unsafe, quote!(fn cpp_from(src: #src) -> Self), from_body); + let move_fn = source.from_move.as_ref().map(|conversion| { + let src = pointer(ty, true); + method( + is_unsafe, + quote!(fn cpp_from_move(src: #src) -> Self), + ctor_call(name, conversion, is_unsafe, true), + ) + }); + quote! { + impl #impl_generics #tr<#ty> for #name #ty_generics #where_clause { + #from_fn + #move_fn + } + } + }); + + let impl_trait = format_ident!("{}Impl", name); + let into_impls = intos.iter().map(|conversion| { + let ty = &conversion.ty; + let op = &conversion.method; + let self_ty = quote!(#name #ty_generics); + let src = pointer(&syn::parse_quote!(#self_ty), false); + let body = if is_unsafe { + quote!((*src).#op()) + } else { + quote!(#impl_trait::#op(&src)) + }; + let from_fn = method(is_unsafe, quote!(fn cpp_from(src: #src) -> Self), body); + quote! { + impl #impl_generics #tr<#self_ty> for #ty #where_clause { + #from_fn + } + } + }); + + quote! { + #(#from_impls)* + #(#into_impls)* + } + .into() +} diff --git a/libcc2rs-macros/src/lib.rs b/libcc2rs-macros/src/lib.rs index 9d0076c753..0471f4c453 100644 --- a/libcc2rs-macros/src/lib.rs +++ b/libcc2rs-macros/src/lib.rs @@ -5,6 +5,7 @@ use proc_macro::TokenStream; mod assign; mod byte_repr; +mod cpp_from; mod destructor; mod fn_ptr_arg; mod goto; @@ -217,3 +218,20 @@ pub fn derive_destructor(input: TokenStream) -> TokenStream { pub fn derive_destructor_unsafe(input: TokenStream) -> TokenStream { destructor::expand(input, true) } + +// #[derive(CppFrom)] +// #[cpp_from(i32, new, value)] +// #[cpp_into(i32, to_i32)] +// pub struct S { ... } +// +// Encodes the C++ converting construction and conversion operators in rules. + +#[proc_macro_derive(CppFrom, attributes(cpp_from, cpp_from_move, cpp_into))] +pub fn derive_cpp_from(input: TokenStream) -> TokenStream { + cpp_from::expand(input, false) +} + +#[proc_macro_derive(CppFromUnsafe, attributes(cpp_from, cpp_from_move, cpp_into))] +pub fn derive_cpp_from_unsafe(input: TokenStream) -> TokenStream { + cpp_from::expand(input, true) +} diff --git a/libcc2rs/src/conversion.rs b/libcc2rs/src/conversion.rs new file mode 100644 index 0000000000..946e6aee3d --- /dev/null +++ b/libcc2rs/src/conversion.rs @@ -0,0 +1,37 @@ +// Copyright (c) 2022-present INESC-ID. +// Distributed under the MIT license that can be found in the LICENSE file. + +use crate::rc::Ptr; +use crate::reinterpret::ByteRepr; + +pub trait CppFrom: Sized { + fn cpp_from(src: Ptr) -> Self; + + fn cpp_from_move(src: Ptr) -> Self { + Self::cpp_from(src) + } +} + +pub trait CppFromUnsafe: Sized { + /// # Safety + /// `src` must point to a live value. + unsafe fn cpp_from(src: *const S) -> Self; + + /// # Safety + /// `src` must point to a live value. + unsafe fn cpp_from_move(src: *mut S) -> Self { + unsafe { Self::cpp_from(src) } + } +} + +impl CppFrom for T { + fn cpp_from(src: Ptr) -> T { + src.read() + } +} + +impl CppFromUnsafe for T { + unsafe fn cpp_from(src: *const T) -> T { + unsafe { (*src).clone() } + } +} diff --git a/libcc2rs/src/lib.rs b/libcc2rs/src/lib.rs index 82649cc40e..054d91d25a 100644 --- a/libcc2rs/src/lib.rs +++ b/libcc2rs/src/lib.rs @@ -48,6 +48,9 @@ pub use capture::{ mod cmp; pub use cmp::*; +mod conversion; +pub use conversion::{CppFrom, CppFromUnsafe}; + mod swap; // Used by cpp_swap! and cpp_swap_unsafe!. #[doc(hidden)] @@ -99,7 +102,7 @@ mod format; pub use format::*; pub use libcc2rs_macros::{ - ByteRepr, CopyAssign, CopyAssignUnsafe, Destructor, DestructorUnsafe, FnPtrArg, MoveAssign, - MoveAssignUnsafe, MoveCtor, MoveCtorUnsafe, Record, VaArg, goto, goto_block, lambda, - lambda_unsafe, switch, + ByteRepr, CopyAssign, CopyAssignUnsafe, CppFrom, CppFromUnsafe, Destructor, DestructorUnsafe, + FnPtrArg, MoveAssign, MoveAssignUnsafe, MoveCtor, MoveCtorUnsafe, Record, VaArg, goto, + goto_block, lambda, lambda_unsafe, switch, }; diff --git a/rule-preprocessor/src/ir.rs b/rule-preprocessor/src/ir.rs index a767bf3766..09014cd82b 100644 --- a/rule-preprocessor/src/ir.rs +++ b/rule-preprocessor/src/ir.rs @@ -76,7 +76,7 @@ pub struct TypeInfo { pub struct FnIr { pub body: Vec, #[serde(skip_serializing_if = "Option::is_none")] - pub generics: Option>>, + pub generics: Option>>, #[serde(skip_serializing_if = "Option::is_none")] pub multi_statement: Option, #[serde(skip_serializing_if = "Option::is_none")] @@ -110,6 +110,9 @@ impl FnIr { check(&method_call.receiver) || check(&method_call.body) } BodyFragment::RefExpr { ref_expr } => check(&ref_expr.inner), + BodyFragment::GenericCall { generic_call } => { + generic_call.args.iter().any(|arg| check(arg)) + } _ => false, }) } @@ -161,9 +164,6 @@ pub enum BodyFragment { Generic { generic: i32, }, - Default { - default: i32, - }, MethodCall { method_call: MethodCallInner, }, @@ -176,6 +176,9 @@ pub enum BodyFragment { Init { init: std::marker::PhantomData<()>, }, + GenericCall { + generic_call: GenericCallInner, + }, } #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] @@ -208,6 +211,20 @@ pub struct RefExprInner { pub inner: Vec, } +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct GenericCallInner { + pub generic: i32, + pub method: String, + pub args: Vec>, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Bound { + #[serde(rename = "trait")] + pub trait_name: String, + pub args: Vec, +} + // For convenience: match on fragment kind impl BodyFragment { pub fn as_text_mut(&mut self) -> Option<&mut String> { @@ -258,6 +275,13 @@ fn resolve_nth_unknown( return true; } } + BodyFragment::GenericCall { generic_call } => { + for arg in &mut generic_call.args { + if resolve(arg, param, nth, count, patch) { + return true; + } + } + } _ => {} } } diff --git a/rule-preprocessor/src/syntactic.rs b/rule-preprocessor/src/syntactic.rs index 17fc7b50be..1441fc7ee6 100644 --- a/rule-preprocessor/src/syntactic.rs +++ b/rule-preprocessor/src/syntactic.rs @@ -11,8 +11,8 @@ use std::collections::BTreeMap; use std::path::{Path, PathBuf}; use crate::ir::{ - Access, BodyFragment, FileIr, FnIr, MethodCallInner, Model, PlaceholderInner, RefExprInner, - RuleIr, RulesIR, TypeInfo, TypeIr, + Access, BodyFragment, Bound, FileIr, FnIr, GenericCallInner, MethodCallInner, Model, + PlaceholderInner, RefExprInner, RuleIr, RulesIR, TypeInfo, TypeIr, }; /// Classify a type AST node as refcount pointer (`Ptr`), unsafe pointer @@ -190,12 +190,12 @@ impl<'a> FragmentCtx<'a> { self.emit_method_call(&call); return; } - if let Some(generic) = - ast::CallExpr::cast(node.clone()).and_then(|call| self.generic_default(&call)) + if let Some(generic_call) = + ast::CallExpr::cast(node.clone()).and_then(|call| self.generic_call(&call)) { self.flush_text(); self.fragments - .push(BodyFragment::Default { default: generic }); + .push(BodyFragment::GenericCall { generic_call }); return; } for child in node.children_with_tokens() { @@ -260,22 +260,11 @@ impl<'a> FragmentCtx<'a> { self.text_buf.push_str(token.text()); } - fn generic_default(&self, call: &ast::CallExpr) -> Option { - if call.arg_list()?.args().next().is_some() { + fn generic_of_path(&self, path: &ast::Path) -> Option { + if path.qualifier().is_some() { return None; } - let ast::Expr::PathExpr(path_expr) = call.expr()? else { - return None; - }; - let path = path_expr.path()?; - if path.segment()?.name_ref()?.text() != "default" { - return None; - } - let qualifier = path.qualifier()?; - if qualifier.qualifier().is_some() { - return None; - } - let segment = qualifier.segment()?; + let segment = path.segment()?; let name = match segment.name_ref() { Some(name_ref) => name_ref.text().to_string(), None => segment @@ -292,6 +281,29 @@ impl<'a> FragmentCtx<'a> { Some(name[1..].parse().unwrap_or(0)) } + fn generic_call(&self, call: &ast::CallExpr) -> Option { + let ast::Expr::PathExpr(path_expr) = call.expr()? else { + return None; + }; + let path = path_expr.path()?; + let method = path.segment()?.name_ref()?.text().to_string(); + let generic = self.generic_of_path(&path.qualifier()?)?; + let args = call + .arg_list()? + .args() + .map(|arg| { + let mut ctx = FragmentCtx::new(self.builder, self.params, self.generic_names); + ctx.visit(ra_ap_syntax::NodeOrToken::Node(arg.syntax().clone())); + ctx.finish() + }) + .collect(); + Some(GenericCallInner { + generic, + method, + args, + }) + } + fn emit_method_call(&mut self, call: &ast::MethodCallExpr) { assert!( call.receiver().is_some(), @@ -401,14 +413,37 @@ impl<'a> FnIrBuilder<'a> { } } - fn generics(&self) -> BTreeMap> { + fn generics(&self) -> BTreeMap> { let mut generics = BTreeMap::new(); - let extract_bounds = |tbl: Option| -> Vec { + let extract_bounds = |tbl: Option| -> Vec { tbl.into_iter() .flat_map(|tbl| tbl.bounds()) - .map(|b| b.syntax().text().to_string()) - .filter(|s| s != "'static") + .filter(|b| b.lifetime().is_none()) + .map(|b| { + let segment = match b.ty() { + Some(ast::Type::PathType(path)) => path.path().and_then(|p| p.segment()), + _ => None, + }; + let Some(segment) = segment else { + return Bound { + trait_name: b.syntax().text().to_string(), + args: Vec::new(), + }; + }; + Bound { + trait_name: segment + .name_ref() + .map(|name| name.text().to_string()) + .unwrap_or_default(), + args: segment + .generic_arg_list() + .into_iter() + .flat_map(|args| args.generic_args()) + .map(|arg| arg.syntax().text().to_string()) + .collect(), + } + }) .collect() }; diff --git a/rules/algorithm/tgt_refcount.rs b/rules/algorithm/tgt_refcount.rs index 00ebd32424..69a2f5bd53 100644 --- a/rules/algorithm/tgt_refcount.rs +++ b/rules/algorithm/tgt_refcount.rs @@ -17,8 +17,8 @@ fn f1, T2: CppLess + Clone + ByteRepr>(a0: T1, a fn f2< T1: CppInputIterator, T2: CppIterator, - T3: Clone + ByteRepr, - T4: From + ByteRepr, + T3: ByteRepr, + T4: CppFrom + ByteRepr, >( a0: T1, a1: T1, @@ -28,7 +28,7 @@ fn f2< let __last = a1; let mut __out = a2; while __first != __last { - __out.iter_deref().write(__first.iter_deref().read().into()); + __out.iter_deref().write(T4::cpp_from(__first.iter_deref())); __first.iter_inc(); __out.iter_inc(); } diff --git a/rules/algorithm/tgt_unsafe.rs b/rules/algorithm/tgt_unsafe.rs index 9aafbe9397..85f35d9325 100644 --- a/rules/algorithm/tgt_unsafe.rs +++ b/rules/algorithm/tgt_unsafe.rs @@ -18,7 +18,7 @@ unsafe fn f1, T2: Ord>(a0: T1, a1: T1) { } } -unsafe fn f2, T2: UnsafeCppIterator, T3: Clone, T4: From>( +unsafe fn f2, T2: UnsafeCppIterator, T3, T4: CppFromUnsafe>( a0: T1, a1: T1, a2: T2, @@ -27,7 +27,7 @@ unsafe fn f2, T2: UnsafeCppIterator, T3: Clon let __last = a1; let mut __out = a2; while __first != __last { - *__out.iter_deref() = (*__first.iter_deref()).clone().into(); + *__out.iter_deref() = T4::cpp_from(__first.iter_deref()); __first.iter_inc(); __out.iter_inc(); } diff --git a/rules/cctype/src.cpp b/rules/cctype/src.cpp index 2b21305769..8832bf218c 100644 --- a/rules/cctype/src.cpp +++ b/rules/cctype/src.cpp @@ -3,4 +3,4 @@ #include -template int f1(T1 a0) { return toupper(a0); } +int f1(int a0) { return toupper(a0); } diff --git a/rules/cctype/tgt_unsafe.rs b/rules/cctype/tgt_unsafe.rs index 2d1f5b9806..17725e43ce 100644 --- a/rules/cctype/tgt_unsafe.rs +++ b/rules/cctype/tgt_unsafe.rs @@ -1,11 +1,10 @@ // Copyright (c) 2022-present INESC-ID. // Distributed under the MIT license that can be found in the LICENSE file. -unsafe fn f1>(a0: T1) -> i32 { - let __c: i32 = a0.into(); - if (0..=255).contains(&__c) { - (__c as u8).to_ascii_uppercase() as i32 +unsafe fn f1(a0: i32) -> i32 { + if (0..=255).contains(&a0) { + (a0 as u8).to_ascii_uppercase() as i32 } else { - __c + a0 } } diff --git a/rules/fstream/src.cpp b/rules/fstream/src.cpp index 3e27d32bde..05905f6fe8 100644 --- a/rules/fstream/src.cpp +++ b/rules/fstream/src.cpp @@ -7,7 +7,7 @@ using t1 = std::ifstream; using t2 = std::ofstream; -using t3 = std::ostream_iterator; +template using t3 = std::ostream_iterator; using t4 = std::ostream_iterator::ostream_type; std::ofstream f1(const char *filename, std::ios_base::openmode mode) { diff --git a/rules/fstream/tgt_unsafe.rs b/rules/fstream/tgt_unsafe.rs index 9542e030a7..b43ad125d0 100644 --- a/rules/fstream/tgt_unsafe.rs +++ b/rules/fstream/tgt_unsafe.rs @@ -9,7 +9,7 @@ fn t2() -> ::std::fs::File { ::std::fs::File::open("").unwrap() } -fn t3() -> ::std::fs::File { +fn t3() -> ::std::fs::File { ::std::fs::File::open("").unwrap() } diff --git a/rules/iterator_category/src.cpp b/rules/iterator_category/src.cpp index 35c3670e71..3895c49cdb 100644 --- a/rules/iterator_category/src.cpp +++ b/rules/iterator_category/src.cpp @@ -387,3 +387,18 @@ template < T1 &f26(T3 &&a0) { return --a0; } + +template < + typename T1, typename T2, + typename = typename std::enable_if< + std::is_base_of< + std::input_iterator_tag, + typename std::iterator_traits::iterator_category>::value && + std::is_base_of< + std::input_iterator_tag, + typename std::iterator_traits::iterator_category>::value && + !std::is_same::value && !std::is_pointer::value && + !std::is_pointer::value>::type> +auto f27(const T1 &a0, const T2 &a1) -> decltype(a0 == a1) { + return a0 == a1; +} diff --git a/rules/iterator_category/tgt_refcount.rs b/rules/iterator_category/tgt_refcount.rs index 30d6500464..8e3828931d 100644 --- a/rules/iterator_category/tgt_refcount.rs +++ b/rules/iterator_category/tgt_refcount.rs @@ -128,3 +128,7 @@ fn f26, T2>(a0: T1) -> T1 { let mut __it = a0; __it.iter_dec() } + +fn f27 + PartialEq, T2: CppInputIterator, T3>(a0: T1, a1: T2) -> bool { + a0 == a1 +} diff --git a/rules/iterator_category/tgt_unsafe.rs b/rules/iterator_category/tgt_unsafe.rs index 49694d5eb3..e288beda66 100644 --- a/rules/iterator_category/tgt_unsafe.rs +++ b/rules/iterator_category/tgt_unsafe.rs @@ -128,3 +128,7 @@ unsafe fn f26, T2>(a0: T1) -> T1 { let mut __it = a0; __it.iter_dec() } + +unsafe fn f27 + PartialEq, T2: UnsafeCppInputIterator, T3>(a0: T1, a1: T2) -> bool { + a0 == a1 +} diff --git a/rules/pair/src.cpp b/rules/pair/src.cpp index f085066f66..e6c24349c4 100644 --- a/rules/pair/src.cpp +++ b/rules/pair/src.cpp @@ -78,3 +78,35 @@ template T1 &&f21(std::pair &&a0) { template T2 &&f22(std::pair &&a0) { return std::get<1>(std::move(a0)); } + +template < + typename T1, typename T2, typename T3, typename T4, + typename = typename std::enable_if::value && + std::is_same::value)>::type> +std::pair f23(std::pair &&a0) { + return std::pair(std::move(a0)); +} + +template < + typename T1, typename T2, typename T3, typename T4, + typename = typename std::enable_if::value && + std::is_same::value)>::type> +std::pair f24(const std::pair &a0) { + return std::pair(a0); +} + +template < + typename T1, typename T2, typename T3, typename T4, + typename = typename std::enable_if::value && + std::is_same::value)>::type> +std::pair &f25(std::pair &a0, const std::pair &a1) { + return a0.template operator= (a1); +} + +template < + typename T1, typename T2, typename T3, typename T4, + typename = typename std::enable_if::value && + std::is_same::value)>::type> +std::pair &f26(std::pair &a0, std::pair &&a1) { + return a0.template operator= (std::move(a1)); +} diff --git a/rules/pair/tgt_refcount.rs b/rules/pair/tgt_refcount.rs index 07757ab396..5ca871e600 100644 --- a/rules/pair/tgt_refcount.rs +++ b/rules/pair/tgt_refcount.rs @@ -20,24 +20,15 @@ fn f2(a0: (Value, Value)) -> (Value, Value } fn f7(a0: T1, a1: T2) -> (Value, Value) { - ( - Rc::new(RefCell::new(a0.try_into().expect("failed conversion"))), - Rc::new(RefCell::new(a1.try_into().expect("failed conversion"))), - ) + (Rc::new(RefCell::new(a0)), Rc::new(RefCell::new(a1))) } fn f9(a0: T1, a1: T2) -> (Value, Value) { - ( - Rc::new(RefCell::new(a0.try_into().expect("failed conversion"))), - Rc::new(RefCell::new(a1.try_into().expect("failed conversion"))), - ) + (Rc::new(RefCell::new(a0)), Rc::new(RefCell::new(a1))) } fn f10(a0: T1, a1: T2) -> (Value, Value) { - ( - Rc::new(RefCell::new(a0.try_into().expect("failed conversion"))), - Rc::new(RefCell::new(a1.try_into().expect("failed conversion"))), - ) + (Rc::new(RefCell::new(a0)), Rc::new(RefCell::new(a1))) } fn f12(a0: &mut (Value, Value)) -> (Value, Value) { @@ -92,3 +83,45 @@ fn f21(a0: (Value, Value)) -> Ptr { fn f22(a0: (Value, Value)) -> Ptr { a0.1.as_pointer() } + +fn f23, T2: CppFrom, T3, T4>( + a0: &mut (Value, Value), +) -> (Value, Value) { + let __a0 = a0; + ( + Rc::new(RefCell::new(T1::cpp_from_move(__a0.0.as_pointer()))), + Rc::new(RefCell::new(T2::cpp_from_move(__a0.1.as_pointer()))), + ) +} + +fn f24, T2: CppFrom, T3, T4>( + a0: (Value, Value), +) -> (Value, Value) { + let __a0 = a0; + ( + Rc::new(RefCell::new(T1::cpp_from(__a0.0.as_pointer()))), + Rc::new(RefCell::new(T2::cpp_from(__a0.1.as_pointer()))), + ) +} + +fn f25 + ByteRepr, T2: CppFrom + ByteRepr, T3, T4>( + a0: Ptr<(Value, Value)>, + a1: (Value, Value), +) { + let __a1 = a1; + a0.write(( + Rc::new(RefCell::new(T1::cpp_from(__a1.0.as_pointer()))), + Rc::new(RefCell::new(T2::cpp_from(__a1.1.as_pointer()))), + )) +} + +fn f26 + ByteRepr, T2: CppFrom + ByteRepr, T3, T4>( + a0: Ptr<(Value, Value)>, + a1: &mut (Value, Value), +) { + let __a1 = a1; + a0.write(( + Rc::new(RefCell::new(T1::cpp_from_move(__a1.0.as_pointer()))), + Rc::new(RefCell::new(T2::cpp_from_move(__a1.1.as_pointer()))), + )) +} diff --git a/rules/pair/tgt_unsafe.rs b/rules/pair/tgt_unsafe.rs index 0604e05526..b49796e166 100644 --- a/rules/pair/tgt_unsafe.rs +++ b/rules/pair/tgt_unsafe.rs @@ -1,6 +1,8 @@ // Copyright (c) 2022-present INESC-ID. // Distributed under the MIT license that can be found in the LICENSE file. +use libcc2rs::*; + fn t1() -> (T1, T2) { <(T1, T2)>::default() } @@ -17,13 +19,13 @@ unsafe fn f2(a0: (T1, T2)) -> (T1, T2) { a0.clone() } unsafe fn f7(a0: T1, a1: T2) -> (T1, T2) { - (a0.into(), a1.into()) + (a0, a1) } unsafe fn f9(a0: T1, a1: T2) -> (T1, T2) { - (a0.into(), a1.into()) + (a0, a1) } unsafe fn f10(a0: T1, a1: T2) -> (T1, T2) { - (a0.into(), a1.into()) + (a0, a1) } unsafe fn f12(a0: &mut (T1, T2)) -> (T1, T2) { @@ -69,3 +71,23 @@ unsafe fn f21(a0: &mut (T1, T2)) -> *mut T1 { unsafe fn f22(a0: &mut (T1, T2)) -> *mut T2 { &mut a0.1 } + +unsafe fn f23, T2: CppFromUnsafe, T3, T4>(a0: &mut (T3, T4)) -> (T1, T2) { + let mut __a0 = a0; + (T1::cpp_from_move(&mut __a0.0), T2::cpp_from_move(&mut __a0.1)) +} + +unsafe fn f24, T2: CppFromUnsafe, T3, T4>(a0: &(T3, T4)) -> (T1, T2) { + let __a0 = a0; + (T1::cpp_from(&__a0.0), T2::cpp_from(&__a0.1)) +} + +unsafe fn f25, T2: CppFromUnsafe, T3, T4>(a0: &mut (T1, T2), a1: &(T3, T4)) { + let __a1 = a1; + *a0 = (T1::cpp_from(&__a1.0), T2::cpp_from(&__a1.1)) +} + +unsafe fn f26, T2: CppFromUnsafe, T3, T4>(a0: &mut (T1, T2), a1: &mut (T3, T4)) { + let mut __a1 = a1; + *a0 = (T1::cpp_from_move(&mut __a1.0), T2::cpp_from_move(&mut __a1.1)) +} diff --git a/rules/vector/tgt_refcount.rs b/rules/vector/tgt_refcount.rs index 5036c81e62..26814061c3 100644 --- a/rules/vector/tgt_refcount.rs +++ b/rules/vector/tgt_refcount.rs @@ -62,11 +62,11 @@ fn f79(a0: &mut Vec, a1: RandomAccessIterator, a2: T1) -> __it } -fn f92, T2: Clone + ByteRepr, T3: CppInputIterator>(a0: T3, a1: T3) -> Vec { +fn f92, T2, T3: CppInputIterator, T4: ByteRepr>(a0: T3, a1: T3) -> Vec { let mut __v = Vec::new(); let mut __it = a0; while __it != a1 { - __v.push(::try_from(__it.iter_deref().read()).ok().unwrap()); + __v.push(T1::cpp_from(__it.iter_deref())); __it.iter_inc(); } __v diff --git a/rules/vector/tgt_unsafe.rs b/rules/vector/tgt_unsafe.rs index 4fe004b704..7f7a30e909 100644 --- a/rules/vector/tgt_unsafe.rs +++ b/rules/vector/tgt_unsafe.rs @@ -148,11 +148,11 @@ unsafe fn f91(a0: Vec) -> Vec { a0 } -unsafe fn f92, T2: Clone, T3: UnsafeCppInputIterator>(a0: T3, a1: T3) -> Vec { +unsafe fn f92, T2, T3: UnsafeCppInputIterator, T4>(a0: T3, a1: T3) -> Vec { let mut __v = Vec::new(); let mut __it = a0; while __it != a1 { - __v.push(::try_from((*__it.iter_deref()).clone()).ok().unwrap()); + __v.push(T1::cpp_from(__it.iter_deref())); __it.iter_inc(); } __v diff --git a/tests/multi-file/defaulted_move_cross_tu/out/refcount/defaulted_move_cross_tu.rs b/tests/multi-file/defaulted_move_cross_tu/out/refcount/defaulted_move_cross_tu.rs index 38069e3e4e..10d03e072d 100644 --- a/tests/multi-file/defaulted_move_cross_tu/out/refcount/defaulted_move_cross_tu.rs +++ b/tests/multi-file/defaulted_move_cross_tu/out/refcount/defaulted_move_cross_tu.rs @@ -6,7 +6,8 @@ use std::io::prelude::*; use std::io::{Read, Seek, Write}; use std::os::fd::AsFd; use std::rc::{Rc, Weak}; -#[derive(Record, ByteRepr, FnPtrArg, MoveCtor, MoveAssign)] +#[derive(Record, ByteRepr, FnPtrArg, MoveCtor, CppFrom, MoveAssign)] +#[cpp_from(i32, new, value)] #[byte_size(32)] pub struct S { #[offset(0)] diff --git a/tests/multi-file/defaulted_move_cross_tu/out/unsafe/defaulted_move_cross_tu.rs b/tests/multi-file/defaulted_move_cross_tu/out/unsafe/defaulted_move_cross_tu.rs index b87f18149f..b38d5709fe 100644 --- a/tests/multi-file/defaulted_move_cross_tu/out/unsafe/defaulted_move_cross_tu.rs +++ b/tests/multi-file/defaulted_move_cross_tu/out/unsafe/defaulted_move_cross_tu.rs @@ -7,7 +7,8 @@ use std::io::{Read, Seek, Write}; use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; use std::rc::Rc; #[repr(C)] -#[derive(FnPtrArg, MoveCtorUnsafe, MoveAssignUnsafe, Default)] +#[derive(FnPtrArg, MoveCtorUnsafe, CppFromUnsafe, MoveAssignUnsafe, Default)] +#[cpp_from(i32, new, value)] pub struct S { pub v: Vec, pub n: [i32; 2], diff --git a/tests/ub/out/refcount/ctor_ref_member.rs b/tests/ub/out/refcount/ctor_ref_member.rs index b68843205a..7bade32e0c 100644 --- a/tests/ub/out/refcount/ctor_ref_member.rs +++ b/tests/ub/out/refcount/ctor_ref_member.rs @@ -6,7 +6,8 @@ use std::io::prelude::*; use std::io::{Read, Seek, Write}; use std::os::fd::AsFd; use std::rc::{Rc, Weak}; -#[derive(Clone, Record, ByteRepr, VaArg, FnPtrArg, Default)] +#[derive(Clone, Record, ByteRepr, VaArg, FnPtrArg, CppFrom, Default)] +#[cpp_from(i32, new, ptr)] #[byte_size(8)] pub struct S { #[offset(0)] diff --git a/tests/ub/out/unsafe/ctor_ref_member.rs b/tests/ub/out/unsafe/ctor_ref_member.rs index c79840e0b2..21de4ecc9a 100644 --- a/tests/ub/out/unsafe/ctor_ref_member.rs +++ b/tests/ub/out/unsafe/ctor_ref_member.rs @@ -7,7 +7,8 @@ use std::io::{Read, Seek, Write}; use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; use std::rc::Rc; #[repr(C)] -#[derive(Copy, Clone, VaArg, FnPtrArg, Default)] +#[derive(Copy, Clone, VaArg, FnPtrArg, CppFromUnsafe, Default)] +#[cpp_from(i32, new, ptr)] pub struct S { pub r: *const i32, } diff --git a/tests/unit/out/refcount/clone_vs_move.rs b/tests/unit/out/refcount/clone_vs_move.rs index ebd577ad16..294e7c90b5 100644 --- a/tests/unit/out/refcount/clone_vs_move.rs +++ b/tests/unit/out/refcount/clone_vs_move.rs @@ -213,8 +213,8 @@ fn main_0() -> i32 { (*i.borrow_mut()).prefix_inc(); } let pair1: Value<(Value, Value)> = Rc::new(RefCell::new(( - Rc::new(RefCell::new(1.try_into().expect("failed conversion"))), - Rc::new(RefCell::new(2.try_into().expect("failed conversion"))), + Rc::new(RefCell::new(1)), + Rc::new(RefCell::new(2)), ))); let pair2: Value<(Value, Value)> = Rc::new(RefCell::new(( Rc::new(RefCell::new((*pair1.borrow()).0.borrow().clone())), @@ -228,13 +228,9 @@ fn main_0() -> i32 { assert!(((*(*pair1.borrow()).1.borrow()) == 2)); let pair3: Value<(Value>, Value)> = Rc::new(RefCell::new(( Rc::new(RefCell::new( - (0..(0_usize) as usize) - .map(|_| 0_i32) - .collect::>() - .try_into() - .expect("failed conversion"), + (0..(0_usize) as usize).map(|_| 0_i32).collect::>(), )), - Rc::new(RefCell::new(0.try_into().expect("failed conversion"))), + Rc::new(RefCell::new(0)), ))); let pair4: Value<(Value>, Value)> = Rc::new(RefCell::new(( Rc::new(RefCell::new((*pair3.borrow()).0.borrow().clone())), diff --git a/tests/unit/out/refcount/constructor.rs b/tests/unit/out/refcount/constructor.rs index 99d1805402..9035fdb03f 100644 --- a/tests/unit/out/refcount/constructor.rs +++ b/tests/unit/out/refcount/constructor.rs @@ -9,7 +9,8 @@ use std::rc::{Rc, Weak}; thread_local!( pub static total_0: Value = Rc::new(RefCell::new(0)); ); -#[derive(Clone, Record, ByteRepr, VaArg, FnPtrArg, Destructor, Default)] +#[derive(Clone, Record, ByteRepr, VaArg, FnPtrArg, CppFrom, Destructor, Default)] +#[cpp_from(i32, new, value)] #[byte_size(4)] pub struct S { #[offset(0)] @@ -24,7 +25,8 @@ impl S { Rc::try_unwrap(__this).ok().unwrap().into_inner() } } -#[derive(Clone, Record, ByteRepr, VaArg, FnPtrArg)] +#[derive(Clone, Record, ByteRepr, VaArg, FnPtrArg, CppFrom)] +#[cpp_from(i32, new_1, value)] #[byte_size(8)] pub struct Point { #[offset(0)] @@ -33,11 +35,11 @@ pub struct Point { pub y: i32, } impl Point { - pub fn new_1(mut x: i32, mut y: i32) -> Self { + pub fn new_2(mut x: i32, mut y: i32) -> Self { Self { x: x, y: y } } - pub fn new_2(mut v: i32) -> Self { - let __this: Value = Rc::new(RefCell::new(Point::new_1({ v }, { (v + 1) }))); + pub fn new_1(mut v: i32) -> Self { + let __this: Value = Rc::new(RefCell::new(Point::new_2({ v }, { (v + 1) }))); let this: Ptr = __this.as_pointer(); { field!(this, y).with_mut(|__v| *__v = *__v * 10) @@ -45,7 +47,7 @@ impl Point { Rc::try_unwrap(__this).ok().unwrap().into_inner() } pub fn new_3() -> Self { - let __this: Value = Rc::new(RefCell::new(Point::new_2({ 4 }))); + let __this: Value = Rc::new(RefCell::new(Point::new_1({ 4 }))); let this: Ptr = __this.as_pointer(); { field!(this, x).with_mut(|__v| *__v = *__v + 100) @@ -73,7 +75,7 @@ fn main_0() -> i32 { let mut p: Point = Point::new_3(); assert!((p.x == 104)); assert!((p.y == 50)); - let mut q: Point = Point::new_2({ 7 }); + let mut q: Point = Point::new_1({ 7 }); assert!((q.x == 7)); assert!((q.y == 80)); return 0; diff --git a/tests/unit/out/refcount/conversion_operator_same_translation.rs b/tests/unit/out/refcount/conversion_operator_same_translation.rs index ec3fc43cd8..0479837a24 100644 --- a/tests/unit/out/refcount/conversion_operator_same_translation.rs +++ b/tests/unit/out/refcount/conversion_operator_same_translation.rs @@ -6,13 +6,16 @@ use std::io::prelude::*; use std::io::{Read, Seek, Write}; use std::os::fd::AsFd; use std::rc::{Rc, Weak}; -#[derive(Clone, Record, ByteRepr, VaArg, FnPtrArg, Default)] +#[derive(Clone, Record, ByteRepr, VaArg, FnPtrArg, CppFrom, Default)] +#[cpp_into(i8, to_i8)] +#[cpp_into(u8, to_u8)] #[byte_size(4)] pub struct S { #[offset(0)] pub v: i32, } -#[derive(Clone, Record, ByteRepr, VaArg, FnPtrArg, Default)] +#[derive(Clone, Record, ByteRepr, VaArg, FnPtrArg, CppFrom, Default)] +#[cpp_into(i64, to_i64_1)] #[byte_size(4)] pub struct T { #[offset(0)] diff --git a/tests/unit/out/refcount/copy_assign.rs b/tests/unit/out/refcount/copy_assign.rs index 7eda28563b..75007299c3 100644 --- a/tests/unit/out/refcount/copy_assign.rs +++ b/tests/unit/out/refcount/copy_assign.rs @@ -94,7 +94,8 @@ impl Default for Holder { thread_local!( pub static copies_1: Value = Rc::new(RefCell::new(0)); ); -#[derive(Record, ByteRepr, VaArg, FnPtrArg, CopyAssign, Default)] +#[derive(Record, ByteRepr, VaArg, FnPtrArg, CppFrom, CopyAssign, Default)] +#[cpp_from(i32, new, value)] #[byte_size(4)] pub struct CopyCounted { #[offset(0)] diff --git a/tests/unit/out/refcount/copy_ctor.rs b/tests/unit/out/refcount/copy_ctor.rs index 26ad076bed..a9408f9443 100644 --- a/tests/unit/out/refcount/copy_ctor.rs +++ b/tests/unit/out/refcount/copy_ctor.rs @@ -9,7 +9,8 @@ use std::rc::{Rc, Weak}; thread_local!( pub static copies_0: Value = Rc::new(RefCell::new(0)); ); -#[derive(Record, ByteRepr, VaArg, FnPtrArg, CopyAssign, Default)] +#[derive(Record, ByteRepr, VaArg, FnPtrArg, CppFrom, CopyAssign, Default)] +#[cpp_from(i32, new, value)] #[byte_size(4)] pub struct Counted { #[offset(0)] @@ -67,7 +68,8 @@ impl Default for NonConst { { NonConst::new() } } } -#[derive(Record, ByteRepr, VaArg, FnPtrArg, CopyAssign, Default)] +#[derive(Record, ByteRepr, VaArg, FnPtrArg, CppFrom, CopyAssign, Default)] +#[cpp_from(i32, new, value)] #[byte_size(4)] pub struct Ignored { #[offset(0)] @@ -111,7 +113,8 @@ impl Default for Holder { } } } -#[derive(Record, ByteRepr, VaArg, FnPtrArg, MoveCtor, Default)] +#[derive(Record, ByteRepr, VaArg, FnPtrArg, MoveCtor, CppFrom, Default)] +#[cpp_from(i32, new, value)] #[byte_size(4)] pub struct Box_int_ { #[offset(0)] @@ -155,7 +158,8 @@ impl Owner { } } } -#[derive(Record, ByteRepr, VaArg, FnPtrArg, CopyAssign, Default)] +#[derive(Record, ByteRepr, VaArg, FnPtrArg, CppFrom, CopyAssign, Default)] +#[cpp_from(i32, new, value)] #[byte_size(4)] pub struct OutOfLine { #[offset(0)] diff --git a/tests/unit/out/refcount/copy_move_defaulted.rs b/tests/unit/out/refcount/copy_move_defaulted.rs index fb4d4c66e6..d2d204987c 100644 --- a/tests/unit/out/refcount/copy_move_defaulted.rs +++ b/tests/unit/out/refcount/copy_move_defaulted.rs @@ -12,7 +12,8 @@ pub struct Inner { #[offset(0)] pub x: i32, } -#[derive(Clone, Record, ByteRepr, VaArg, FnPtrArg, Destructor)] +#[derive(Clone, Record, ByteRepr, VaArg, FnPtrArg, CppFrom, Destructor)] +#[cpp_from(i32, new, value)] #[byte_size(16)] pub struct Explicit { #[offset(0)] @@ -67,7 +68,8 @@ impl Default for Implicit { } } } -#[derive(Clone, Record, ByteRepr, VaArg, FnPtrArg, MoveCtor, MoveAssign, Default)] +#[derive(Clone, Record, ByteRepr, VaArg, FnPtrArg, MoveCtor, CppFrom, MoveAssign, Default)] +#[cpp_from(i32, new, value)] #[byte_size(4)] pub struct DefaultCopyUserMove { #[offset(0)] @@ -85,7 +87,8 @@ impl DefaultCopyUserMove { __this } } -#[derive(Record, ByteRepr, VaArg, FnPtrArg, MoveCtor, CopyAssign, MoveAssign, Default)] +#[derive(Record, ByteRepr, VaArg, FnPtrArg, MoveCtor, CppFrom, CopyAssign, MoveAssign, Default)] +#[cpp_from(i32, new, value)] #[byte_size(4)] pub struct UserCopyDefaultMove { #[offset(0)] @@ -113,7 +116,8 @@ impl Clone for UserCopyDefaultMove { UserCopyDefaultMove::copy_from(__src.as_pointer()) } } -#[derive(Record, ByteRepr, FnPtrArg, MoveCtor, MoveAssign)] +#[derive(Record, ByteRepr, FnPtrArg, MoveCtor, CppFrom, MoveAssign)] +#[cpp_from(i32, new, value)] #[byte_size(64)] pub struct Buffer { #[offset(0)] @@ -219,7 +223,8 @@ impl Copyable { } } } -#[derive(Record, ByteRepr, FnPtrArg, MoveCtor, MoveAssign, Destructor, Default)] +#[derive(Record, ByteRepr, FnPtrArg, MoveCtor, CppFrom, MoveAssign, Destructor, Default)] +#[cpp_from(i32, new, value)] #[byte_size(32)] pub struct Holder { #[offset(0)] diff --git a/tests/unit/out/refcount/copy_move_deleted.rs b/tests/unit/out/refcount/copy_move_deleted.rs index e088db3b82..a853b47e90 100644 --- a/tests/unit/out/refcount/copy_move_deleted.rs +++ b/tests/unit/out/refcount/copy_move_deleted.rs @@ -6,7 +6,8 @@ use std::io::prelude::*; use std::io::{Read, Seek, Write}; use std::os::fd::AsFd; use std::rc::{Rc, Weak}; -#[derive(Record, ByteRepr, FnPtrArg, MoveCtor, MoveAssign, Default)] +#[derive(Record, ByteRepr, FnPtrArg, MoveCtor, CppFrom, MoveAssign, Default)] +#[cpp_from(i32, new, value)] #[byte_size(4)] pub struct NoCopy { #[offset(0)] diff --git a/tests/unit/out/refcount/default_function_arguments.rs b/tests/unit/out/refcount/default_function_arguments.rs index 955cd0f47d..05161592a2 100644 --- a/tests/unit/out/refcount/default_function_arguments.rs +++ b/tests/unit/out/refcount/default_function_arguments.rs @@ -14,7 +14,8 @@ pub fn baz_1(mut a: Ptr, b: Option>) -> bool { let mut b: Ptr = b.unwrap_or_else(|| Ptr::::null()); return ({ a } == { b }); } -#[derive(Clone, Record, ByteRepr, VaArg, FnPtrArg)] +#[derive(Clone, Record, ByteRepr, VaArg, FnPtrArg, CppFrom)] +#[cpp_from(i32, new, some_value)] #[byte_size(4)] pub struct Bar { #[offset(0)] diff --git a/tests/unit/out/refcount/fn_ptr.rs b/tests/unit/out/refcount/fn_ptr.rs index 885ca183f3..236c7d38f0 100644 --- a/tests/unit/out/refcount/fn_ptr.rs +++ b/tests/unit/out/refcount/fn_ptr.rs @@ -28,7 +28,8 @@ pub fn call_fn_5(mut f: FnPtr usize>, mut v: i32) -> usize { pub fn identity_hash_6(mut v: bool) -> usize { return (v as usize); } -#[derive(Clone, Record, ByteRepr, VaArg, FnPtrArg, Default)] +#[derive(Clone, Record, ByteRepr, VaArg, FnPtrArg, CppFrom, Default)] +#[cpp_from(FnPtr u64 > , new, ptr)] #[byte_size(8)] pub struct HashHolder_unsigned_long__ptr__bool__ { #[offset(0)] diff --git a/tests/unit/out/refcount/fn_ptr_struct.rs b/tests/unit/out/refcount/fn_ptr_struct.rs index 661face3dc..e5db915746 100644 --- a/tests/unit/out/refcount/fn_ptr_struct.rs +++ b/tests/unit/out/refcount/fn_ptr_struct.rs @@ -35,7 +35,8 @@ impl S { return (x + 3); } } -#[derive(Record, ByteRepr, FnPtrArg, MoveCtor, Default)] +#[derive(Record, ByteRepr, FnPtrArg, MoveCtor, CppFrom, Default)] +#[cpp_from(i32, new, value)] #[byte_size(4)] pub struct MoveOnly { #[offset(0)] diff --git a/tests/unit/out/refcount/forward_basic.rs b/tests/unit/out/refcount/forward_basic.rs index 43a6863f28..9d8e4a7581 100644 --- a/tests/unit/out/refcount/forward_basic.rs +++ b/tests/unit/out/refcount/forward_basic.rs @@ -9,7 +9,8 @@ use std::rc::{Rc, Weak}; pub type Overload = u32; pub const Overload_kLvalueOverload: Overload = 1; pub const Overload_kRvalueOverload: Overload = 2; -#[derive(Record, ByteRepr, VaArg, FnPtrArg, MoveCtor, Default)] +#[derive(Record, ByteRepr, VaArg, FnPtrArg, MoveCtor, CppFrom, Default)] +#[cpp_from(i32, new, value)] #[byte_size(12)] pub struct Tracked { #[offset(0)] @@ -74,7 +75,9 @@ impl Holder { } } } -#[derive(Clone, Record, ByteRepr, VaArg, FnPtrArg, MoveCtor, Default)] +#[derive(Clone, Record, ByteRepr, VaArg, FnPtrArg, MoveCtor, CppFrom, Default)] +#[cpp_from(Tracked, new_1, mut_ptr)] +#[cpp_from_move(Tracked, new_2, ptr)] #[byte_size(12)] pub struct Holder { #[offset(0)] diff --git a/tests/unit/out/refcount/forward_decltype.rs b/tests/unit/out/refcount/forward_decltype.rs index 75c79b963a..8b73ead5f0 100644 --- a/tests/unit/out/refcount/forward_decltype.rs +++ b/tests/unit/out/refcount/forward_decltype.rs @@ -9,7 +9,8 @@ use std::rc::{Rc, Weak}; pub type Overload = u32; pub const Overload_kLvalueOverload: Overload = 1; pub const Overload_kRvalueOverload: Overload = 2; -#[derive(Record, ByteRepr, VaArg, FnPtrArg, MoveCtor, Default)] +#[derive(Record, ByteRepr, VaArg, FnPtrArg, MoveCtor, CppFrom, Default)] +#[cpp_from(i32, new, value)] #[byte_size(12)] pub struct Tracked { #[offset(0)] diff --git a/tests/unit/out/refcount/forward_explicit.rs b/tests/unit/out/refcount/forward_explicit.rs index da69f55d02..0f1c4de973 100644 --- a/tests/unit/out/refcount/forward_explicit.rs +++ b/tests/unit/out/refcount/forward_explicit.rs @@ -11,7 +11,8 @@ pub const Overload_kLvalueOverload: Overload = 1; pub const Overload_kRvalueOverload: Overload = 2; pub const Overload_kIntLvalueOverload: Overload = 3; pub const Overload_kIntRvalueOverload: Overload = 4; -#[derive(Record, ByteRepr, VaArg, FnPtrArg, MoveCtor, Default)] +#[derive(Record, ByteRepr, VaArg, FnPtrArg, MoveCtor, CppFrom, Default)] +#[cpp_from(i32, new, value)] #[byte_size(12)] pub struct Tracked { #[offset(0)] diff --git a/tests/unit/out/refcount/forward_pack.rs b/tests/unit/out/refcount/forward_pack.rs index 9def6d5d6f..c0add9eab0 100644 --- a/tests/unit/out/refcount/forward_pack.rs +++ b/tests/unit/out/refcount/forward_pack.rs @@ -11,7 +11,8 @@ pub const Overload_kLvalueOverload: Overload = 1; pub const Overload_kRvalueOverload: Overload = 2; pub const Overload_kIntLvalueOverload: Overload = 3; pub const Overload_kIntRvalueOverload: Overload = 4; -#[derive(Record, ByteRepr, VaArg, FnPtrArg, MoveCtor, Default)] +#[derive(Record, ByteRepr, VaArg, FnPtrArg, MoveCtor, CppFrom, Default)] +#[cpp_from(i32, new, value)] #[byte_size(12)] pub struct Tracked { #[offset(0)] diff --git a/tests/unit/out/refcount/global_init_side_effect.rs b/tests/unit/out/refcount/global_init_side_effect.rs index 062c8aa6dc..41110c2d18 100644 --- a/tests/unit/out/refcount/global_init_side_effect.rs +++ b/tests/unit/out/refcount/global_init_side_effect.rs @@ -9,7 +9,8 @@ use std::rc::{Rc, Weak}; thread_local!( pub static total_0: Value = Rc::new(RefCell::new(0)); ); -#[derive(Clone, Record, ByteRepr, VaArg, FnPtrArg, Default)] +#[derive(Clone, Record, ByteRepr, VaArg, FnPtrArg, CppFrom, Default)] +#[cpp_from(i32, new, value)] #[byte_size(1)] pub struct S {} impl S { diff --git a/tests/unit/out/refcount/lambda_as_field.rs b/tests/unit/out/refcount/lambda_as_field.rs index 4507fd71fd..abd36c086b 100644 --- a/tests/unit/out/refcount/lambda_as_field.rs +++ b/tests/unit/out/refcount/lambda_as_field.rs @@ -63,7 +63,8 @@ pub struct Holder__lambda_at_lambda_as_field_cpp_51_12__ { #[offset(4)] pub calls: i32, } -#[derive(Record, ByteRepr, FnPtrArg, MoveCtor)] +#[derive(Record, ByteRepr, FnPtrArg, MoveCtor, CppFrom)] +#[cpp_from(FnPtr i32 > , new, value)] #[byte_size(8)] pub struct Moving__lambda_at_lambda_as_field_cpp_64_12__ { #[offset(0)] diff --git a/tests/unit/out/refcount/lambda_move_only_capture.rs b/tests/unit/out/refcount/lambda_move_only_capture.rs index fe42942aed..47e5ee9bad 100644 --- a/tests/unit/out/refcount/lambda_move_only_capture.rs +++ b/tests/unit/out/refcount/lambda_move_only_capture.rs @@ -6,7 +6,8 @@ use std::io::prelude::*; use std::io::{Read, Seek, Write}; use std::os::fd::AsFd; use std::rc::{Rc, Weak}; -#[derive(Record, ByteRepr, FnPtrArg, MoveCtor, Destructor, Default)] +#[derive(Record, ByteRepr, FnPtrArg, MoveCtor, CppFrom, Destructor, Default)] +#[cpp_from(i32, new, value)] #[byte_size(8)] pub struct Owner { #[offset(0)] diff --git a/tests/unit/out/refcount/map.rs b/tests/unit/out/refcount/map.rs index 51afb82e4b..7031aac499 100644 --- a/tests/unit/out/refcount/map.rs +++ b/tests/unit/out/refcount/map.rs @@ -388,8 +388,8 @@ fn main_0() -> i32 { > = Rc::new(RefCell::new(Map::new())); assert!(((*other_map.borrow()).len() == 0_usize)); let key0: Value<(Value, Value)> = Rc::new(RefCell::new(( - Rc::new(RefCell::new(1.try_into().expect("failed conversion"))), - Rc::new(RefCell::new(1.try_into().expect("failed conversion"))), + Rc::new(RefCell::new(1)), + Rc::new(RefCell::new((1 as i64))), ))); let mut value: f64 = 2_f64; Map::subscript(other_map.as_pointer(), key0.as_pointer()).write(value); diff --git a/tests/unit/out/refcount/map_key_copy_ctor.rs b/tests/unit/out/refcount/map_key_copy_ctor.rs index 1edf3a7ac3..f64a830b0e 100644 --- a/tests/unit/out/refcount/map_key_copy_ctor.rs +++ b/tests/unit/out/refcount/map_key_copy_ctor.rs @@ -15,7 +15,8 @@ thread_local!( thread_local!( pub static made_2: Value = Rc::new(RefCell::new(0)); ); -#[derive(Record, ByteRepr, VaArg, FnPtrArg, MoveCtor, Default)] +#[derive(Record, ByteRepr, VaArg, FnPtrArg, MoveCtor, CppFrom, Default)] +#[cpp_from(i32, new, value)] #[byte_size(4)] pub struct Key { #[offset(0)] diff --git a/tests/unit/out/refcount/max.rs b/tests/unit/out/refcount/max.rs index d39c7e6fad..fcd3341220 100644 --- a/tests/unit/out/refcount/max.rs +++ b/tests/unit/out/refcount/max.rs @@ -16,7 +16,8 @@ pub fn pick_2(mut i: i32) -> Ptr { (*calls_0.with(Value::clone).borrow_mut()).prefix_inc(); return (xs_1.with(|v| v.as_pointer()) as Ptr).offset(i); } -#[derive(Record, ByteRepr, VaArg, FnPtrArg, CopyAssign, Default)] +#[derive(Record, ByteRepr, VaArg, FnPtrArg, CppFrom, CopyAssign, Default)] +#[cpp_from(i32, new, value)] #[byte_size(4)] pub struct Bag { #[offset(0)] diff --git a/tests/unit/out/refcount/move_assign.rs b/tests/unit/out/refcount/move_assign.rs index cdf64fbb65..434943399c 100644 --- a/tests/unit/out/refcount/move_assign.rs +++ b/tests/unit/out/refcount/move_assign.rs @@ -6,7 +6,8 @@ use std::io::prelude::*; use std::io::{Read, Seek, Write}; use std::os::fd::AsFd; use std::rc::{Rc, Weak}; -#[derive(Record, ByteRepr, FnPtrArg, MoveCtor, MoveAssign, Default)] +#[derive(Record, ByteRepr, FnPtrArg, MoveCtor, CppFrom, MoveAssign, Default)] +#[cpp_from(i32, new, value)] #[byte_size(4)] pub struct MoveOnly { #[offset(0)] diff --git a/tests/unit/out/refcount/move_ctor.rs b/tests/unit/out/refcount/move_ctor.rs index fe40d4ca44..c3f03e4add 100644 --- a/tests/unit/out/refcount/move_ctor.rs +++ b/tests/unit/out/refcount/move_ctor.rs @@ -6,7 +6,8 @@ use std::io::prelude::*; use std::io::{Read, Seek, Write}; use std::os::fd::AsFd; use std::rc::{Rc, Weak}; -#[derive(Record, ByteRepr, FnPtrArg, MoveCtor, Default)] +#[derive(Record, ByteRepr, FnPtrArg, MoveCtor, CppFrom, Default)] +#[cpp_from(i32, new, value)] #[byte_size(4)] pub struct MoveOnly { #[offset(0)] @@ -50,7 +51,8 @@ impl Default for ConstMove { { ConstMove::new() } } } -#[derive(Record, ByteRepr, VaArg, FnPtrArg, MoveCtor, Default)] +#[derive(Record, ByteRepr, VaArg, FnPtrArg, MoveCtor, CppFrom, Default)] +#[cpp_from(i32, new, value)] #[byte_size(12)] pub struct ThrowingMove { #[offset(0)] @@ -95,7 +97,8 @@ impl Clone for ThrowingMove { ThrowingMove::copy_from(__src.as_pointer()) } } -#[derive(Record, ByteRepr, VaArg, FnPtrArg, MoveCtor, Default)] +#[derive(Record, ByteRepr, VaArg, FnPtrArg, MoveCtor, CppFrom, Default)] +#[cpp_from(i32, new, value)] #[byte_size(12)] pub struct NoexceptMove { #[offset(0)] diff --git a/tests/unit/out/refcount/move_this.rs b/tests/unit/out/refcount/move_this.rs index b84e960519..fbd3a5ecd5 100644 --- a/tests/unit/out/refcount/move_this.rs +++ b/tests/unit/out/refcount/move_this.rs @@ -6,7 +6,8 @@ use std::io::prelude::*; use std::io::{Read, Seek, Write}; use std::os::fd::AsFd; use std::rc::{Rc, Weak}; -#[derive(Record, ByteRepr, VaArg, FnPtrArg, MoveCtor, Default)] +#[derive(Record, ByteRepr, VaArg, FnPtrArg, MoveCtor, CppFrom, Default)] +#[cpp_from(i32, new, value)] #[byte_size(4)] pub struct Chain { #[offset(0)] diff --git a/tests/unit/out/refcount/operator_comparison_nonbool.rs b/tests/unit/out/refcount/operator_comparison_nonbool.rs index 3e9fe73ea9..dfb5f0bfcf 100644 --- a/tests/unit/out/refcount/operator_comparison_nonbool.rs +++ b/tests/unit/out/refcount/operator_comparison_nonbool.rs @@ -68,7 +68,8 @@ impl CppEq for Mixed { ((MixedImpl::operator_eq(__lhs, __rhs.clone())) != 0) } } -#[derive(Clone, Record, ByteRepr, VaArg, FnPtrArg, Default)] +#[derive(Clone, Record, ByteRepr, VaArg, FnPtrArg, CppFrom, Default)] +#[cpp_into(bool, to_bool)] #[byte_size(1)] pub struct MyBool { #[offset(0)] @@ -107,7 +108,8 @@ pub fn operator_eq_7(mut a: Boolish, mut b: Boolish) -> MyBool { pub fn operator_lt_6(mut a: Boolish, mut b: Boolish) -> MyBool { return MyBool::new({ (a.v < b.v) }); } -#[derive(Record, ByteRepr, FnPtrArg, Default)] +#[derive(Record, ByteRepr, FnPtrArg, CppFrom, Default)] +#[cpp_into(bool, to_bool)] #[byte_size(1)] pub struct RefBool { #[offset(0)] diff --git a/tests/unit/out/refcount/operator_comparison_noncopyable.rs b/tests/unit/out/refcount/operator_comparison_noncopyable.rs index ee1d62c80f..d45af15f2f 100644 --- a/tests/unit/out/refcount/operator_comparison_noncopyable.rs +++ b/tests/unit/out/refcount/operator_comparison_noncopyable.rs @@ -12,7 +12,8 @@ pub fn operator_eq_0(x: Ptr, y: Ptr) -> bool { pub fn operator_lt_1(x: Ptr, y: Ptr) -> bool { return ({ x.with(|__s| __s.data_) } < { y.with(|__s| __s.data_) }); } -#[derive(Record, ByteRepr, FnPtrArg, MoveCtor, Default)] +#[derive(Record, ByteRepr, FnPtrArg, MoveCtor, CppFrom, Default)] +#[cpp_from(i32, new, value)] #[byte_size(4)] pub struct S { #[offset(0)] diff --git a/tests/unit/out/refcount/operator_other_member.rs b/tests/unit/out/refcount/operator_other_member.rs index 5218bfa551..07a49e8dae 100644 --- a/tests/unit/out/refcount/operator_other_member.rs +++ b/tests/unit/out/refcount/operator_other_member.rs @@ -14,7 +14,8 @@ impl Static { return (a * b); } } -#[derive(Clone, Record, ByteRepr, VaArg, FnPtrArg, Default)] +#[derive(Clone, Record, ByteRepr, VaArg, FnPtrArg, CppFrom, Default)] +#[cpp_into(i32, to_i32)] #[byte_size(4)] pub struct S { #[offset(0)] diff --git a/tests/unit/out/refcount/overload_mangling.rs b/tests/unit/out/refcount/overload_mangling.rs index 3ad28effd8..797b83c793 100644 --- a/tests/unit/out/refcount/overload_mangling.rs +++ b/tests/unit/out/refcount/overload_mangling.rs @@ -61,10 +61,7 @@ fn main_0() -> i32 { (({ SImpl::pick_8( &s.as_pointer(), - ( - Rc::new(RefCell::new(1.try_into().expect("failed conversion"))), - Rc::new(RefCell::new(2.try_into().expect("failed conversion"))), - ), + (Rc::new(RefCell::new(1)), Rc::new(RefCell::new(2))), ) }) == 101) ); @@ -72,10 +69,7 @@ fn main_0() -> i32 { (({ SImpl::pick_9( &s.as_pointer(), - ( - Rc::new(RefCell::new(1.try_into().expect("failed conversion"))), - Rc::new(RefCell::new(2_i64.try_into().expect("failed conversion"))), - ), + (Rc::new(RefCell::new(1)), Rc::new(RefCell::new(2_i64))), ) }) == 102) ); @@ -90,8 +84,8 @@ fn main_0() -> i32 { assert!( (({ let _p: Value<(Value, Value)> = Rc::new(RefCell::new(( - Rc::new(RefCell::new(1.try_into().expect("failed conversion"))), - Rc::new(RefCell::new(2_i64.try_into().expect("failed conversion"))), + Rc::new(RefCell::new(1)), + Rc::new(RefCell::new(2_i64)), ))); SImpl::combine_13( &s.as_pointer(), @@ -106,8 +100,8 @@ fn main_0() -> i32 { assert!( (({ let _p: Value<(Value, Value)> = Rc::new(RefCell::new(( - Rc::new(RefCell::new(1.try_into().expect("failed conversion"))), - Rc::new(RefCell::new(2.try_into().expect("failed conversion"))), + Rc::new(RefCell::new(1)), + Rc::new(RefCell::new(2)), ))); SImpl::combine_14( &s.as_pointer(), diff --git a/tests/unit/out/refcount/pair.rs b/tests/unit/out/refcount/pair.rs index 4fd402bece..f35fe5c266 100644 --- a/tests/unit/out/refcount/pair.rs +++ b/tests/unit/out/refcount/pair.rs @@ -12,21 +12,24 @@ pub fn main() { } fn main_0() -> i32 { let p1: Value<(Value, Value)> = Rc::new(RefCell::new(( - Rc::new(RefCell::new(1.try_into().expect("failed conversion"))), - Rc::new(RefCell::new(2.try_into().expect("failed conversion"))), + Rc::new(RefCell::new((1 as f64))), + Rc::new(RefCell::new(2)), ))); assert!(((*(*p1.borrow()).0.borrow()) == 1_f64)); assert!(((*(*p1.borrow()).1.borrow()) == 2)); let p2: Value<(Value, Value)> = Rc::new(RefCell::new(( - Rc::new(RefCell::new(3.try_into().expect("failed conversion"))), - Rc::new(RefCell::new(4.try_into().expect("failed conversion"))), + Rc::new(RefCell::new((3 as f64))), + Rc::new(RefCell::new(4)), ))); assert!(((*(*p2.borrow()).0.borrow()) == 3_f64)); assert!(((*(*p2.borrow()).1.borrow()) == 4)); - let p3: Value<(Value, Value)> = Rc::new(RefCell::new(( - Rc::new(RefCell::new(5.try_into().expect("failed conversion"))), - Rc::new(RefCell::new(6.try_into().expect("failed conversion"))), - ))); + let p3: Value<(Value, Value)> = Rc::new(RefCell::new({ + let __a0 = (Rc::new(RefCell::new(5)), Rc::new(RefCell::new(6))); + ( + Rc::new(RefCell::new(((__a0.0.as_pointer().read()) as f64))), + Rc::new(RefCell::new((__a0.1.as_pointer().read()))), + ) + })); assert!(((*(*p3.borrow()).0.borrow()) == 5_f64)); assert!(((*(*p3.borrow()).1.borrow()) == 6)); let arr: Value> = Rc::new(RefCell::new(Box::new([1, 2]))); @@ -41,15 +44,20 @@ fn main_0() -> i32 { }) .collect::>(), )); - (*const_ptr_pairs.borrow_mut())[0_usize] = ( - Rc::new(RefCell::new( - (arr.as_pointer() as Ptr) - .offset((1) as isize) - .try_into() - .expect("failed conversion"), - )), - Rc::new(RefCell::new(n.try_into().expect("failed conversion"))), - ); + { + let __a1 = ( + Rc::new(RefCell::new( + (arr.as_pointer() as Ptr).offset((1) as isize), + )), + Rc::new(RefCell::new(n)), + ); + const_ptr_pairs.decay().offset(0_usize).write(( + Rc::new(RefCell::new( + as CppFrom>>::cpp_from_move(__a1.0.as_pointer()), + )), + Rc::new(RefCell::new(((__a1.1.as_pointer().read()) as u64))), + )) + }; assert!( (((*(*const_ptr_pairs.borrow())[0_usize].0.borrow()).read()) == 2) && ((*(*const_ptr_pairs.borrow())[0_usize].1.borrow()) == 2_u64) diff --git a/tests/unit/out/refcount/pair_converting_construction.rs b/tests/unit/out/refcount/pair_converting_construction.rs new file mode 100644 index 0000000000..902cffbfd0 --- /dev/null +++ b/tests/unit/out/refcount/pair_converting_construction.rs @@ -0,0 +1,342 @@ +extern crate libcc2rs; +use libcc2rs::*; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::io::prelude::*; +use std::io::{Read, Seek, Write}; +use std::os::fd::AsFd; +use std::rc::{Rc, Weak}; +#[derive(Clone, Record, ByteRepr, VaArg, FnPtrArg, CppFrom, Default)] +#[cpp_from(i32, new, value)] +#[byte_size(4)] +pub struct Celsius { + #[offset(0)] + pub degrees: i32, +} +impl Celsius { + pub fn new(mut d: i32) -> Self { + Self { degrees: d } + } +} +#[derive(Clone, Record, ByteRepr, VaArg, FnPtrArg, CppFrom, Default)] +#[cpp_into(i32, to_i32)] +#[byte_size(4)] +pub struct Meters { + #[offset(0)] + pub value: i32, +} +#[derive(Clone, Record, ByteRepr, VaArg, FnPtrArg, CppFrom, Default)] +#[cpp_from(Celsius, new, ptr)] +#[byte_size(4)] +pub struct Label { + #[offset(0)] + pub id: i32, +} +impl Label { + pub fn new(c: Ptr) -> Self { + Self { + id: c.with(|__s| __s.degrees), + } + } +} +#[derive(Clone, Record, ByteRepr, VaArg, FnPtrArg, CppFrom, Default)] +#[cpp_from(Celsius, new_1, ptr)] +#[cpp_from_move(Celsius, new_2, ptr)] +#[byte_size(8)] +pub struct Owner { + #[offset(0)] + pub taken: i32, + #[offset(4)] + pub copied: i32, +} +impl Owner { + pub fn new_1(c: Ptr) -> Self { + Self { + taken: 0, + copied: c.with(|__s| __s.degrees), + } + } + pub fn new_2(c: Ptr) -> Self { + Self { + taken: c.with(|__s| __s.degrees), + copied: 0, + } + } +} +#[derive(Clone, Record, ByteRepr, VaArg, FnPtrArg, CppFrom, Default)] +#[cpp_from(Celsius, new, value)] +#[byte_size(4)] +pub struct Holder { + #[offset(0)] + pub value: i32, +} +impl Holder { + pub fn new(mut c: Celsius) -> Self { + Self { value: c.degrees } + } +} +#[derive(Clone, Record, ByteRepr, VaArg, FnPtrArg, CppFrom)] +#[cpp_from(i32, new, some_value)] +#[byte_size(4)] +pub struct Fallback { + #[offset(0)] + pub value: i32, +} +impl Fallback { + pub fn new(v: Option) -> Self { + let mut v: i32 = v.unwrap_or_else(|| -1_i32); + Self { value: v } + } +} +impl Default for Fallback { + fn default() -> Self { + { Fallback::new(None) } + } +} +#[derive(Clone, Record, ByteRepr, VaArg, FnPtrArg, Default)] +#[byte_size(4)] +pub struct Counter { + #[offset(0)] + pub hits: i32, +} +#[derive(Clone, Record, ByteRepr, VaArg, FnPtrArg, CppFrom, Default)] +#[cpp_from(Counter, new, mut_ptr)] +#[byte_size(4)] +pub struct Observer { + #[offset(0)] + pub seen: i32, +} +impl Observer { + pub fn new(c: Ptr) -> Self { + let __this: Observer = Self { + seen: c.with(|__s| __s.hits), + }; + field!(c, hits).with_mut(|__v| __v.postfix_inc()); + __this + } +} +impl Tag { + pub fn new(u: Ptr) -> Self { + Self { + code: (u.with(|__s| __s.degrees) + 100), + } + } +} +#[derive(Clone, Record, ByteRepr, VaArg, FnPtrArg, CppFrom, Default)] +#[cpp_from(Celsius, new, ptr)] +#[byte_size(4)] +pub struct Tag { + #[offset(0)] + pub code: i32, +} +#[derive(Clone, Record, ByteRepr, VaArg, FnPtrArg, CppFrom, Default)] +#[cpp_from(Ptr< i8 > , new, value)] +#[byte_size(4)] +pub struct Name { + #[offset(0)] + pub len: i32, +} +impl Name { + pub fn new(mut s: Ptr) -> Self { + let __this: Value = Rc::new(RefCell::new(Self { len: 0 })); + let this: Ptr = __this.as_pointer(); + 'loop_: while ((elem!(s, this.with(|__s| __s.len)).read()) != 0) { + field!(this, len).with_mut(|__v| __v.prefix_inc()); + } + Rc::try_unwrap(__this).ok().unwrap().into_inner() + } +} +pub fn main() { + __cpp2rust_init_globals(); + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let widened: Value<(Value, Value)> = Rc::new(RefCell::new(( + Rc::new(RefCell::new((-1_i32 as i64))), + Rc::new(RefCell::new(2_u32)), + ))); + assert!(((*(*widened.borrow()).0.borrow()) == -1_i64)); + assert!(((*(*widened.borrow()).1.borrow()) == 2_u32)); + let from_ints: Value<(Value, Value)> = Rc::new(RefCell::new(( + Rc::new(RefCell::new(Celsius::new({ 1 }))), + Rc::new(RefCell::new(Celsius::new({ 2 }))), + ))); + assert!(({ (*(*from_ints.borrow()).0.borrow()).degrees } == 1)); + assert!(({ (*(*from_ints.borrow()).1.borrow()).degrees } == 2)); + let m: Value = Rc::new(RefCell::new(Meters { value: 7 })); + let from_operators: Value<(Value, Value)> = Rc::new(RefCell::new(( + Rc::new(RefCell::new(({ MetersImpl::to_i32(&m.as_pointer()) }))), + Rc::new(RefCell::new( + (({ MetersImpl::to_i32(&m.as_pointer()) }) as i64), + )), + ))); + assert!(((*(*from_operators.borrow()).0.borrow()) == 7)); + assert!(((*(*from_operators.borrow()).1.borrow()) == 7_i64)); + let from_moved_pair: Value<(Value, Value)> = Rc::new(RefCell::new({ + let __a0 = (Rc::new(RefCell::new(3)), Rc::new(RefCell::new(4))); + ( + Rc::new(RefCell::new(((__a0.0.as_pointer().read()) as i64))), + Rc::new(RefCell::new(((__a0.1.as_pointer().read()) as f64))), + ) + })); + assert!(((*(*from_moved_pair.borrow()).0.borrow()) == 3_i64)); + assert!(((*(*from_moved_pair.borrow()).1.borrow()) == 4_f64)); + let ints: Value<(Value, Value)> = Rc::new(RefCell::new(( + Rc::new(RefCell::new(5)), + Rc::new(RefCell::new(6)), + ))); + let from_copied_pair: Value<(Value, Value)> = Rc::new(RefCell::new({ + let __a0 = (*ints.borrow()).clone(); + ( + Rc::new(RefCell::new(>::cpp_from( + __a0.0.as_pointer(), + ))), + Rc::new(RefCell::new(((__a0.1.as_pointer().read()) as i64))), + ) + })); + assert!(({ (*(*from_copied_pair.borrow()).0.borrow()).degrees } == 5)); + assert!(((*(*from_copied_pair.borrow()).1.borrow()) == 6_i64)); + let meters: Value<(Value, Value)> = Rc::new(RefCell::new(( + Rc::new(RefCell::new(Meters { value: 8 })), + Rc::new(RefCell::new(Meters { value: 9 })), + ))); + let from_operator_pair: Value<(Value, Value)> = Rc::new(RefCell::new({ + let __a0 = (*meters.borrow()).clone(); + ( + Rc::new(RefCell::new(>::cpp_from( + __a0.0.as_pointer(), + ))), + Rc::new(RefCell::new(>::cpp_from( + __a0.1.as_pointer(), + ))), + ) + })); + assert!(((*(*from_operator_pair.borrow()).0.borrow()) == 8)); + assert!(((*(*from_operator_pair.borrow()).1.borrow()) == 9)); + let celsius: Value<(Value, Value)> = Rc::new(RefCell::new(( + Rc::new(RefCell::new(Celsius::new({ 10 }))), + Rc::new(RefCell::new(Celsius::new({ 11 }))), + ))); + let from_record_pair: Value<(Value