diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index fd404b357..0dd1debc5 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -170,6 +170,10 @@ bool Converter::VisitBuiltinType(clang::BuiltinType *type) { bool Converter::VisitRecordType(clang::RecordType *type) { auto *decl = type->getDecl(); if (auto lambda = AsLambdaClass(clang::QualType(type, 0))) { + if (lambda->isGenericLambda()) { + StrCat("FnPtr"); + return false; + } auto proto = lambda->getLambdaCallOperator() ->getType() ->castAs(); @@ -1877,7 +1881,8 @@ bool Converter::VisitCallExpr(clang::CallExpr *expr) { expr->getCalleeDecl()); conversion && conversion->getParent()->isLambda()) { ConvertLambdaToFunctionPointer(clang::cast(expr) - ->getImplicitObjectArgument()); + ->getImplicitObjectArgument(), + conversion); return false; } @@ -1958,16 +1963,31 @@ bool Converter::VisitCallExpr(clang::CallExpr *expr) { return false; } -void Converter::ConvertLambdaToFunctionPointer(clang::Expr *lambda) { +void Converter::ConvertLambdaToFunctionPointer( + clang::Expr *lambda, const clang::CXXConversionDecl *conversion) { StrCat("Some"); PushParen paren(*this); - ConvertLambdaClosure(AsLambdaClass(lambda->getType())); + ConvertLambdaClosure(AsLambdaClass(lambda->getType()), + AsLambdaCallOperator(conversion)); computed_expr_type_ = ComputedExprType::FreshPointer; } -void Converter::EmitFnPtrCall(clang::Expr *callee) { - if (AsLambdaClass(callee->getType())) { - StrCat(ConvertRValue(callee), ".call"); +void Converter::ConvertLambdaCall(clang::CallExpr *expr, + const clang::CXXRecordDecl *lambda) { + StrCat(ConvertRValue(GetCallee(expr))); + if (lambda->isGenericLambda()) { + auto call_operator = expr->getDirectCallee(); + auto proto = call_operator->getType()->castAs(); + StrCat(std::format(".spec::<{}>({})", ConvertFunctionPointerType(proto), + GetLambdaSpecializationIndex(call_operator))); + } + StrCat(".call"); +} + +void Converter::EmitFnPtrCall(clang::CallExpr *expr) { + auto callee = GetCallee(expr); + if (auto lambda = AsLambdaClass(callee->getType())) { + ConvertLambdaCall(expr, lambda); return; } { @@ -2014,8 +2034,9 @@ Converter::CallInfo Converter::CollectCallInfo(clang::CallExpr *expr) { auto callee = GetCallee(expr); unsigned arg_begin = 0; if (auto op_call = llvm::dyn_cast(expr)) { - if (clang::isa_and_nonnull( - op_call->getDirectCallee())) { + if (auto method = clang::dyn_cast_or_null( + op_call->getDirectCallee()); + method && !method->isExplicitObjectMemberFunction()) { arg_begin = 1; } } @@ -2221,7 +2242,7 @@ void Converter::EmitCall(CallInfo &&info) { EmitHoistedArgs(info); if (info.is_fn_ptr_call) { - EmitFnPtrCall(GetCallee(info.expr)); + EmitFnPtrCall(info.expr); } else if (info.is_libc_passthrough) { auto *direct_callee = info.expr->getDirectCallee(); assert(direct_callee); @@ -3926,12 +3947,15 @@ bool Converter::VisitConstantExpr(clang::ConstantExpr *expr) { bool Converter::VisitLambdaExpr(clang::LambdaExpr *expr) { auto decl = expr->getLambdaClass(); - if (decl->captures().empty()) { + if (decl->captures().empty() && !decl->isGenericLambda()) { ConvertCapturelessLambda(decl); return false; } StrCat(LambdaMacro()); PushParen paren(*this); + if (decl->isGenericLambda()) { + StrCat("Generic", token::kComma); + } { PushBrace captures(*this); auto init = expr->capture_init_begin(); @@ -3939,19 +3963,21 @@ bool Converter::VisitLambdaExpr(clang::LambdaExpr *expr) { ConvertLambdaCapture(field, *init++); } } - StrCat(token::kComma); - ConvertLambdaClosure(decl); + ForEachLambdaCallOperator(decl, [&](clang::CXXMethodDecl *call_operator) { + StrCat(token::kComma); + ConvertLambdaClosure(decl, call_operator); + }); computed_expr_type_ = ComputedExprType::FreshValue; return false; } void Converter::ConvertCapturelessLambda(const clang::CXXRecordDecl *decl) { - auto proto = decl->getLambdaCallOperator() - ->getType() - ->castAs(); + assert(!decl->isGenericLambda()); + auto call_operator = decl->getLambdaCallOperator(); + auto proto = call_operator->getType()->castAs(); StrCat(std::format("FnPtr::<{}>::new", ConvertFunctionPointerType(proto))); PushParen paren(*this); - ConvertLambdaClosure(decl); + ConvertLambdaClosure(decl, call_operator); computed_expr_type_ = ComputedExprType::FreshValue; } @@ -3964,8 +3990,8 @@ void Converter::ConvertLambdaCapture(const clang::FieldDecl *field, StrCat(token::kSemiColon); } -void Converter::ConvertLambdaClosure(const clang::CXXRecordDecl *decl) { - auto call_operator = decl->getLambdaCallOperator(); +void Converter::ConvertLambdaClosure(const clang::CXXRecordDecl *decl, + clang::CXXMethodDecl *call_operator) { StrCat('|'); for (auto p : call_operator->parameters()) { StrCat(GetNamedDeclAsString(p), token::kColon, ToString(p->getType()), @@ -3975,7 +4001,7 @@ void Converter::ConvertLambdaClosure(const clang::CXXRecordDecl *decl) { ConvertFunctionReturnType(call_operator); PushBrace body(*this); std::optional unsafe_brace; - if (decl->captures().empty()) { + if (decl->captures().empty() && !decl->isGenericLambda()) { StrCat(keyword_unsafe_); unsafe_brace.emplace(*this); } diff --git a/cpp2rust/converter/converter.h b/cpp2rust/converter/converter.h index fc40844e9..179207599 100644 --- a/cpp2rust/converter/converter.h +++ b/cpp2rust/converter/converter.h @@ -329,9 +329,14 @@ class Converter : public clang::RecursiveASTVisitor { void ConvertGenericCallExpr(clang::CallExpr *expr); - virtual void EmitFnPtrCall(clang::Expr *callee); + virtual void EmitFnPtrCall(clang::CallExpr *expr); - virtual void ConvertLambdaToFunctionPointer(clang::Expr *lambda); + void ConvertLambdaCall(clang::CallExpr *expr, + const clang::CXXRecordDecl *lambda); + + virtual void + ConvertLambdaToFunctionPointer(clang::Expr *lambda, + const clang::CXXConversionDecl *conversion); virtual void ConvertFunctionToFunctionPointer(const clang::FunctionDecl *fn_decl); @@ -479,7 +484,8 @@ class Converter : public clang::RecursiveASTVisitor { virtual void ConvertLambdaCapture(const clang::FieldDecl *field, clang::Expr *init); - void ConvertLambdaClosure(const clang::CXXRecordDecl *decl); + void ConvertLambdaClosure(const clang::CXXRecordDecl *decl, + clang::CXXMethodDecl *call_operator); virtual bool VisitImplicitValueInitExpr(clang::ImplicitValueInitExpr *expr); virtual bool VisitCXXScalarValueInitExpr(clang::CXXScalarValueInitExpr *expr); diff --git a/cpp2rust/converter/converter_lib.cpp b/cpp2rust/converter/converter_lib.cpp index f33d1a809..d00c67ec3 100644 --- a/cpp2rust/converter/converter_lib.cpp +++ b/cpp2rust/converter/converter_lib.cpp @@ -1174,6 +1174,58 @@ AsLambdaOperatorCall(const clang::FunctionDecl *fn) { return method; } +void ForEachLambdaCallOperator( + const clang::CXXRecordDecl *decl, + llvm::function_ref fn) { + if (!decl->isGenericLambda()) { + fn(decl->getLambdaCallOperator()); + return; + } + for (auto spec : decl->getDependentLambdaCallOperator()->specializations()) { + fn(clang::cast(spec)); + } +} + +clang::CXXMethodDecl * +AsLambdaCallOperator(const clang::CXXConversionDecl *conversion) { + auto decl = conversion->getParent(); + if (!decl->isGenericLambda()) { + return decl->getLambdaCallOperator(); + } + auto args = conversion->getTemplateSpecializationArgs()->asArray(); + clang::CXXMethodDecl *found = nullptr; + ForEachLambdaCallOperator(decl, [&](clang::CXXMethodDecl *op) { + auto op_args = op->getTemplateSpecializationArgs()->asArray(); + if (llvm::equal(args, op_args, + [](const clang::TemplateArgument &a, + const clang::TemplateArgument &b) { + return a.structurallyEquals(b); + })) { + found = op; + } + }); + if (!found) { + llvm::report_fatal_error("no call operator matches the lambda conversion"); + } + return found; +} + +unsigned +GetLambdaSpecializationIndex(const clang::FunctionDecl *call_operator) { + std::optional index; + unsigned i = 0; + ForEachLambdaCallOperator( + clang::cast(call_operator)->getParent(), + [&](const clang::CXXMethodDecl *op) { + if (op->getCanonicalDecl() == call_operator->getCanonicalDecl()) { + index = i; + } + ++i; + }); + assert(index); + return *index; +} + const clang::LambdaCapture *AsLambdaCapture(const clang::FieldDecl *field) { auto decl = clang::dyn_cast(field->getParent()); if (!decl || !decl->isLambda()) { @@ -1689,6 +1741,10 @@ clang::Expr *GetCallee(clang::CallExpr *expr) { return op_call->getArg(0); } } + if (auto member_call = clang::dyn_cast(expr); + member_call && AsLambdaOperatorCall(member_call->getMethodDecl())) { + return member_call->getImplicitObjectArgument(); + } return expr->getCallee(); } diff --git a/cpp2rust/converter/converter_lib.h b/cpp2rust/converter/converter_lib.h index b3a8c68c7..c619b9f31 100644 --- a/cpp2rust/converter/converter_lib.h +++ b/cpp2rust/converter/converter_lib.h @@ -214,6 +214,15 @@ const clang::CXXRecordDecl *AsLambdaClass(clang::QualType type); const clang::CXXMethodDecl *AsLambdaOperatorCall(const clang::FunctionDecl *fn); +void ForEachLambdaCallOperator( + const clang::CXXRecordDecl *decl, + llvm::function_ref fn); + +clang::CXXMethodDecl * +AsLambdaCallOperator(const clang::CXXConversionDecl *conversion); + +unsigned GetLambdaSpecializationIndex(const clang::FunctionDecl *call_operator); + const clang::LambdaCapture *AsLambdaCapture(const clang::FieldDecl *field); bool IsLambdaCopyOrMoveConstructor(const clang::CXXConstructorDecl *ctor); diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index 2658e835a..9a5f74873 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -1311,7 +1311,8 @@ bool ConverterRefCount::VisitCallExpr(clang::CallExpr *expr) { expr->getCalleeDecl()); conversion && conversion->getParent()->isLambda()) { ConvertLambdaToFunctionPointer(clang::cast(expr) - ->getImplicitObjectArgument()); + ->getImplicitObjectArgument(), + conversion); return false; } @@ -1546,9 +1547,10 @@ bool ConverterRefCount::VisitImplicitCastExpr(clang::ImplicitCastExpr *expr) { return Converter::VisitImplicitCastExpr(expr); } -void ConverterRefCount::EmitFnPtrCall(clang::Expr *callee) { - if (AsLambdaClass(callee->getType())) { - StrCat(ConvertRValue(callee), ".call"); +void ConverterRefCount::EmitFnPtrCall(clang::CallExpr *expr) { + auto callee = GetCallee(expr); + if (auto lambda = AsLambdaClass(callee->getType())) { + ConvertLambdaCall(expr, lambda); return; } Convert(callee); @@ -1572,8 +1574,16 @@ void ConverterRefCount::ConvertLambdaCapture(const clang::FieldDecl *field, Converter::ConvertLambdaCapture(field, init); } -void ConverterRefCount::ConvertLambdaToFunctionPointer(clang::Expr *lambda) { +void ConverterRefCount::ConvertLambdaToFunctionPointer( + clang::Expr *lambda, const clang::CXXConversionDecl *conversion) { StrCat(ConvertFreshRValue(lambda)); + auto decl = AsLambdaClass(lambda->getType()); + if (decl->isGenericLambda()) { + auto call_operator = AsLambdaCallOperator(conversion); + auto proto = call_operator->getType()->castAs(); + StrCat(std::format(".spec::<{}>({})", ConvertFunctionPointerType(proto), + GetLambdaSpecializationIndex(call_operator))); + } } void ConverterRefCount::ConvertFunctionToFunctionPointer( diff --git a/cpp2rust/converter/models/converter_refcount.h b/cpp2rust/converter/models/converter_refcount.h index a181c1eae..e76995a74 100644 --- a/cpp2rust/converter/models/converter_refcount.h +++ b/cpp2rust/converter/models/converter_refcount.h @@ -113,7 +113,7 @@ class ConverterRefCount final : public Converter { void ConvertPrintf(clang::CallExpr *expr) override; - void EmitFnPtrCall(clang::Expr *callee) override; + void EmitFnPtrCall(clang::CallExpr *expr) override; bool VisitLambdaExpr(clang::LambdaExpr *expr) override; @@ -124,7 +124,8 @@ class ConverterRefCount final : public Converter { void ConvertLambdaCapture(const clang::FieldDecl *field, clang::Expr *init) override; - void ConvertLambdaToFunctionPointer(clang::Expr *lambda) override; + void ConvertLambdaToFunctionPointer( + clang::Expr *lambda, const clang::CXXConversionDecl *conversion) override; void ConvertFunctionToFunctionPointer(const clang::FunctionDecl *fn_decl) override; diff --git a/libcc2rs-macros/src/lambda.rs b/libcc2rs-macros/src/lambda.rs index e5664c4b0..782797482 100644 --- a/libcc2rs-macros/src/lambda.rs +++ b/libcc2rs-macros/src/lambda.rs @@ -9,17 +9,38 @@ use syn::parse::{Parse, ParseStream}; use syn::{Block, Error, ExprClosure, Pat, Result, Stmt, Token, parse_macro_input}; struct Lambda { + is_generic: bool, captures: Block, - closure: ExprClosure, + closures: Vec, } impl Parse for Lambda { fn parse(input: ParseStream) -> Result { + let is_generic = input.peek(syn::Ident); + if is_generic { + let marker: Ident = input.parse()?; + if marker != "Generic" { + return Err(Error::new(marker.span(), "expected `Generic`")); + } + input.parse::()?; + } let captures = input.parse()?; input.parse::()?; - let closure = input.parse()?; - input.parse::>()?; - Ok(Lambda { captures, closure }) + let mut closures = vec![input.parse()?]; + while input.parse::>()?.is_some() && !input.is_empty() { + closures.push(input.parse()?); + } + if !is_generic && closures.len() != 1 { + return Err(Error::new_spanned( + &closures[1], + "a non-generic lambda has one closure", + )); + } + Ok(Lambda { + is_generic, + captures, + closures, + }) } } @@ -137,28 +158,49 @@ fn expand_lambda(lambda: Lambda, is_unsafe: bool) -> Result = names.iter().map(|name| name.to_string()).collect(); + let mut calls = Vec::new(); + let mut sigs = Vec::new(); + let mut call_names = Vec::new(); + for (i, closure) in lambda.closures.iter().enumerate() { + let mut params = Vec::new(); + let mut param_types = Vec::new(); + for input in &closure.inputs { + let Pat::Type(pat) = input else { + return Err(Error::new_spanned(input, "expected a typed parameter")); + }; + params.push(pat); + param_types.push(&pat.ty); + } + let output = &closure.output; + let body = &closure.body; + let body = rewrite_captures(quote! { #body }, &captured, false)?; + let (receiver, body) = if is_unsafe { + (quote! { &mut self }, quote! { unsafe { #body } }) + } else { + (quote! { &self }, body) }; - params.push(pat); - param_types.push(&pat.ty); + let call_name = if lambda.is_generic { + Ident::new(&format!("call_{i}"), proc_macro2::Span::call_site()) + } else { + Ident::new("call", proc_macro2::Span::call_site()) + }; + calls.push(quote! { + #[allow(unused_unsafe, clippy::too_many_arguments)] + fn #call_name(#receiver #(, #params)*) #output { + #body + } + }); + sigs.push(quote! { fn(#(#param_types),*) #output }); + call_names.push((call_name, closure.inputs.len())); } - - let output = &lambda.closure.output; - let body = &lambda.closure.body; - let captured = names.iter().map(|name| name.to_string()).collect(); - let body = rewrite_captures(quote! { #body }, &captured, false)?; // The copy and move constructors of the lambda copy and move each // capture, and its destructor destroys them in reverse order, as chosen // from their types by the traits in libcc2rs::__capture. let reversed: Vec<_> = names.iter().rev().collect(); - let (receiver, body, destroy, constructor, copy_from, move_from) = if is_unsafe { + let (receiver, destroy, constructor, copy_from, move_from) = if is_unsafe { ( quote! { &mut self }, - quote! { unsafe { #body } }, quote! { use ::libcc2rs::__capture::{DestroyNoneUnsafe as _, DestroyWithDtorUnsafe as _}; unsafe { @@ -192,7 +234,6 @@ fn expand_lambda(lambda: Lambda, is_unsafe: bool) -> Result Result Self { #copy_from @@ -239,12 +277,76 @@ fn expand_lambda(lambda: Lambda, is_unsafe: bool) -> Result::#constructor( - __Lambda { #(#names: #inits,)* }, - __Lambda::call, - __Lambda::copy_from, - __Lambda::move_from, - __Lambda::destroy, + }; + let lambda_init = quote! { __Lambda { #(#names: #inits,)* } }; + + if !lambda.is_generic { + let sig = &sigs[0]; + return Ok(quote! {{ + #lambda_struct + ::libcc2rs::FnPtr::<#sig>::#constructor( + #lambda_init, + __Lambda::call, + __Lambda::copy_from, + __Lambda::move_from, + __Lambda::destroy, + ) + }}); + } + + let mut specs = Vec::new(); + for (sig, (call_name, arity)) in sigs.iter().zip(&call_names) { + let args: Vec = (0..*arity) + .map(|i| Ident::new(&format!("__a{i}"), proc_macro2::Span::call_site())) + .collect(); + let call = if is_unsafe { + quote! { + |__l: &mut ::std::rc::Rc<::std::cell::UnsafeCell<__Lambda>> #(, #args)*| { + unsafe { &mut *__l.get() }.#call_name(#(#args),*) + } + } + } else { + quote! { + |__l: &::std::rc::Rc<__Lambda> #(, #args)*| __l.#call_name(#(#args),*) + } + }; + specs.push(quote! { + ::std::rc::Rc::new(::libcc2rs::FnPtr::<#sig>::#constructor( + ::std::rc::Rc::clone(__l), + #call, + |__l| ::std::rc::Rc::clone(__l), + |__l| ::std::rc::Rc::clone(__l), + |_| {}, + )) as ::std::rc::Rc + }); + } + let (shared, copy_from, move_from, destroy) = if is_unsafe { + ( + quote! { ::std::rc::Rc::new(::std::cell::UnsafeCell::new(#lambda_init)) }, + quote! { |__l| ::std::rc::Rc::new(::std::cell::UnsafeCell::new( + unsafe { &mut *__l.get() }.copy_from() + )) }, + quote! { |__l| ::std::rc::Rc::new(::std::cell::UnsafeCell::new( + unsafe { &mut *__l.get() }.move_from() + )) }, + quote! { |__l| unsafe { &mut *__l.get() }.destroy() }, + ) + } else { + ( + quote! { ::std::rc::Rc::new(#lambda_init) }, + quote! { |__l| ::std::rc::Rc::new(__l.copy_from()) }, + quote! { |__l| ::std::rc::Rc::new(__l.move_from()) }, + quote! { |__l| __l.destroy() }, + ) + }; + Ok(quote! {{ + #lambda_struct + ::libcc2rs::FnPtr::<::libcc2rs::Generic>::from_generic_lambda( + #shared, + |__l| vec![#(#specs),*], + #copy_from, + #move_from, + #destroy, ) }}) } diff --git a/libcc2rs/src/fn_ptr.rs b/libcc2rs/src/fn_ptr.rs index d2a84d958..8aaf3d8a6 100644 --- a/libcc2rs/src/fn_ptr.rs +++ b/libcc2rs/src/fn_ptr.rs @@ -60,6 +60,10 @@ trait Adapted: Any { } fn destroy(&self) {} + + fn specializations(&self) -> &[Rc] { + panic!("ub: not a generic lambda"); + } } impl Adapted for T { @@ -373,6 +377,96 @@ macro_rules! impl_fn_ptr_call { } impl_fn_ptr_call!(); +#[derive(Clone, Copy)] +pub struct Generic; + +impl FnSig for Generic { + type Args = (); + type Ret = (); + fn fn_addr(&self) -> usize { + panic!("ub: a generic lambda has no single function address"); + } + fn call_direct(self, _args: ()) { + panic!("ub: calling a generic lambda without a signature"); + } +} + +struct GenericLambda { + captures: Captures, + specializations: Vec>, + make_specializations: fn(&Captures) -> Vec>, + copy_from: fn(&Captures) -> Captures, + move_from: fn(&Captures) -> Captures, + destroy: fn(&Captures), +} + +impl GenericLambda { + fn with_captures(&self, captures: Captures) -> Rc { + Rc::new(GenericLambda { + specializations: (self.make_specializations)(&captures), + captures, + make_specializations: self.make_specializations, + copy_from: self.copy_from, + move_from: self.move_from, + destroy: self.destroy, + }) + } +} + +impl Adapted for GenericLambda { + fn call_adapted(&self, _args: ArgList) -> ArgRepr { + panic!("ub: calling a generic lambda without a signature"); + } + + fn copy_from(&self) -> Option> { + Some(self.with_captures((self.copy_from)(&self.captures))) + } + + fn move_from(&self) -> Option> { + Some(self.with_captures((self.move_from)(&self.captures))) + } + + fn destroy(&self) { + (self.destroy)(&self.captures) + } + + fn specializations(&self) -> &[Rc] { + &self.specializations + } +} + +impl FnPtr { + pub fn from_generic_lambda( + captures: Captures, + make_specializations: fn(&Captures) -> Vec>, + copy_from: fn(&Captures) -> Captures, + move_from: fn(&Captures) -> Captures, + destroy: fn(&Captures), + ) -> Self { + let lambda: Rc = Rc::new(GenericLambda { + specializations: make_specializations(&captures), + captures, + make_specializations, + copy_from, + move_from, + destroy, + }); + FnPtr { + addr: Rc::as_ptr(&lambda) as *const () as usize, + current: None, + original: Some(lambda), + } + } + + pub fn spec(&self, index: usize) -> FnPtr { + assert!(!self.is_null(), "ub: null fn pointer call"); + self.original.as_ref().unwrap().specializations()[index] + .downcast_ref::>() + .expect("ub: calling through incompatible fn pointer type") + .clone() + } +} + impl Clone for FnPtr { fn clone(&self) -> Self { FnPtr { diff --git a/libcc2rs/src/lib.rs b/libcc2rs/src/lib.rs index b95481870..d7ae29fa1 100644 --- a/libcc2rs/src/lib.rs +++ b/libcc2rs/src/lib.rs @@ -35,7 +35,7 @@ mod fn_ptr_arg; pub use fn_ptr_arg::{ArgRepr, FnPtrArg, record_from_repr}; mod fn_ptr; -pub use fn_ptr::FnPtr; +pub use fn_ptr::{FnPtr, Generic}; mod capture; pub use capture::{Destructor, DestructorUnsafe, MoveCtor, MoveCtorUnsafe}; diff --git a/tests/unit/lambda_as_template_argument.cpp b/tests/unit/lambda_as_template_argument.cpp index 0385de50b..9242ee4c9 100644 --- a/tests/unit/lambda_as_template_argument.cpp +++ b/tests/unit/lambda_as_template_argument.cpp @@ -1,4 +1,4 @@ -// translation-fail +// ADDITIONAL_COMPILE_FLAGS: -std=c++23 #include template int apply_int(F fn, int x) { return fn(x); } diff --git a/tests/unit/lambda_generic.cpp b/tests/unit/lambda_generic.cpp index 11030e47c..389826471 100644 --- a/tests/unit/lambda_generic.cpp +++ b/tests/unit/lambda_generic.cpp @@ -1,4 +1,4 @@ -// translation-fail +// ADDITIONAL_COMPILE_FLAGS: -std=c++23 #include int main() { diff --git a/tests/unit/lambda_generic_explicit_args.cpp b/tests/unit/lambda_generic_explicit_args.cpp index 85717e5fc..00af09643 100644 --- a/tests/unit/lambda_generic_explicit_args.cpp +++ b/tests/unit/lambda_generic_explicit_args.cpp @@ -1,4 +1,4 @@ -// translation-fail +// ADDITIONAL_COMPILE_FLAGS: -std=c++23 #include struct Val { diff --git a/tests/unit/lambda_generic_to_fn_ptr.cpp b/tests/unit/lambda_generic_to_fn_ptr.cpp index 21d8670f5..c97373fe2 100644 --- a/tests/unit/lambda_generic_to_fn_ptr.cpp +++ b/tests/unit/lambda_generic_to_fn_ptr.cpp @@ -1,4 +1,4 @@ -// translation-fail +// ADDITIONAL_COMPILE_FLAGS: -std=c++23 #include int main() { diff --git a/tests/unit/lambda_self_recursive.cpp b/tests/unit/lambda_self_recursive.cpp index 0c85c5a56..f05b0c654 100644 --- a/tests/unit/lambda_self_recursive.cpp +++ b/tests/unit/lambda_self_recursive.cpp @@ -1,5 +1,4 @@ // ADDITIONAL_COMPILE_FLAGS: -std=c++23 -// translation-fail #include int main() { 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..1733f28f8 --- /dev/null +++ b/tests/unit/out/refcount/lambda_as_template_argument.rs @@ -0,0 +1,108 @@ +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_int_0(fn_: FnPtr i32>, mut x: i32) -> i32 { + let fn_: Value i32>> = Rc::new(RefCell::new(fn_)); + return ({ (*fn_.borrow()).call(x) }); +} +pub fn apply_int_1(fn_: FnPtr, mut x: i32) -> i32 { + let fn_: Value> = Rc::new(RefCell::new(fn_)); + return ({ (*fn_.borrow()).spec:: i32>(0).call(x) }); +} +pub fn apply_int_2(fn_: FnPtr, mut x: i32) -> i32 { + let fn_: Value> = Rc::new(RefCell::new(fn_)); + return ({ (*fn_.borrow()).spec:: i32>(0).call(x) }); +} +pub fn apply_int_3(fn_: FnPtr, mut x: i32) -> i32 { + let fn_: Value> = Rc::new(RefCell::new(fn_)); + return ({ (*fn_.borrow()).spec:: i32>(0).call(x) }); +} +pub fn apply_double_4(fn_: FnPtr, mut x: f64) -> f64 { + let fn_: Value> = Rc::new(RefCell::new(fn_)); + return ({ (*fn_.borrow()).spec:: f64>(1).call(x) }); +} +pub fn apply_double_5(fn_: FnPtr, mut x: f64) -> f64 { + let fn_: Value> = Rc::new(RefCell::new(fn_)); + return ({ (*fn_.borrow()).spec:: f64>(1).call(x) }); +} +pub fn apply_twice_6(fn_: FnPtr i32>, mut x: i32) -> i32 { + let fn_: Value i32>> = Rc::new(RefCell::new(fn_)); + return ({ + let _x: i32 = ({ (*fn_.borrow()).call(x) }); + (*fn_.borrow()).call(_x) + }) + .clone(); +} +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 i32>> = Rc::new(RefCell::new(lambda!( + { + let factor: Value = Rc::new(RefCell::new((*factor.borrow()))); + }, + |x: i32| -> i32 { + return (x * (*factor.borrow())); + } + ))); + assert!((({ apply_twice_6((*scale.borrow()).copy_from(), 4,) }) == 36)); + assert!( + (({ + apply_int_0( + FnPtr:: i32>::new(|x: i32| -> i32 { + { + return -x; + } + }), + 9, + ) + }) == -9_i32) + ); + let generic_scale: Value> = Rc::new(RefCell::new(lambda!( + Generic, + { + let factor: Value = Rc::new(RefCell::new((*factor.borrow()))); + }, + |x: i32| -> i32 { + return (x * (*factor.borrow())); + }, + |x: f64| -> f64 { + return (x * ((*factor.borrow()) as f64)); + } + ))); + assert!((({ apply_int_1((*generic_scale.borrow()).copy_from(), 4,) }) == 12)); + assert!((({ apply_double_4((*generic_scale.borrow()).copy_from(), 1.5_f64,) }) == 4.5_f64)); + assert!( + (({ + apply_int_2( + lambda!(Generic, {}, |x: i32| -> i32 { + return -x; + }), + 9, + ) + }) == -9_i32) + ); + let offset: Value> = Rc::new(RefCell::new(lambda!( + Generic, + { + let factor: Value = Rc::new(RefCell::new((*factor.borrow()))); + }, + |x: i32| -> i32 { + return (x + (*factor.borrow())); + }, + |x: f64| -> f64 { + return (x + ((*factor.borrow()) as f64)); + } + ))); + assert!((({ apply_int_3((*offset.borrow()).copy_from(), 4,) }) == 7)); + assert!((({ apply_double_5((*offset.borrow()).copy_from(), 1.5_f64,) }) == 4.5_f64)); + return 0; +} +pub fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/refcount/lambda_generic.rs b/tests/unit/out/refcount/lambda_generic.rs new file mode 100644 index 000000000..e94e309b3 --- /dev/null +++ b/tests/unit/out/refcount/lambda_generic.rs @@ -0,0 +1,108 @@ +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 twice: Value> = Rc::new(RefCell::new(lambda!( + Generic, + {}, + |x: i32| -> i32 { + return (x + x); + }, + |x: f64| -> f64 { + return (x + x); + } + ))); + assert!((({ (*twice.borrow()).spec:: i32>(0).call(4,) }) == 8)); + assert!((({ (*twice.borrow()).spec:: f64>(1).call(1.5_f64,) }) == 3_f64)); + let base: Value = Rc::new(RefCell::new(10)); + let add_base: Value> = Rc::new(RefCell::new(lambda!( + Generic, + { + let base: Value = Rc::new(RefCell::new((*base.borrow()))); + }, + |x: i32| -> i32 { + return (x + (*base.borrow())); + }, + |x: f64| -> f64 { + return (x + ((*base.borrow()) as f64)); + } + ))); + assert!((({ (*add_base.borrow()).spec:: i32>(0).call(5,) }) == 15)); + assert!( + (({ + (*add_base.borrow()).spec:: f64>(1).call(2.5_f64) + }) == 12.5_f64) + ); + let total: Value = Rc::new(RefCell::new(0)); + let accumulate: Value> = Rc::new(RefCell::new(lambda!( + Generic, + { + let total: Ptr = total.as_pointer(); + }, + |x: i32, y: i32| { + { + let __rhs = (x * y); + total.with_mut(|__v| *__v = *__v + __rhs) + }; + }, + |x: u32, y: u32| { + total.write({ (((total.read()) as u32).wrapping_add((x).wrapping_mul(y))) as i32 }); + } + ))); + ({ (*accumulate.borrow()).spec::(0).call(2, 3) }); + ({ + (*accumulate.borrow()) + .spec::(1) + .call(4_u32, 5_u32) + }); + assert!(((*total.borrow()) == 26)); + let sub: Value> = Rc::new(RefCell::new(lambda!( + Generic, + {}, + |x: i32, y: i32| -> i32 { + return (x - y); + }, + |x: f64, y: f64| -> f64 { + return (x - y); + } + ))); + assert!((({ (*sub.borrow()).spec:: i32>(0).call(9, 4,) }) == 5)); + assert!( + (({ + (*sub.borrow()) + .spec:: f64>(1) + .call(2.5_f64, 1_f64) + }) == 1.5_f64) + ); + let mixed: Value> = Rc::new(RefCell::new(lambda!( + Generic, + { + let base: Value = Rc::new(RefCell::new((*base.borrow()))); + }, + |x: i32, y: i32| -> i32 { + return ((x * y) + (*base.borrow())); + }, + |x: i32, y: f64| -> f64 { + return (((x as f64) * y) + ((*base.borrow()) as f64)); + } + ))); + assert!((({ (*mixed.borrow()).spec:: i32>(0).call(2, 3,) }) == 16)); + assert!( + (({ + (*mixed.borrow()) + .spec:: f64>(1) + .call(2, 0.5_f64) + }) == 11_f64) + ); + return 0; +} +pub fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/refcount/lambda_generic_explicit_args.rs b/tests/unit/out/refcount/lambda_generic_explicit_args.rs new file mode 100644 index 000000000..4dfae14d3 --- /dev/null +++ b/tests/unit/out/refcount/lambda_generic_explicit_args.rs @@ -0,0 +1,108 @@ +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, Default)] +#[byte_size(4)] +pub struct Val { + #[offset(0)] + pub x: i32, +} +pub fn sum_0(mut a: Val, mut b: Val) -> i32 { + return (a.x + b.x); +} +pub fn main() { + __cpp2rust_init_globals(); + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let total: Value = Rc::new(RefCell::new(0)); + let tally: Value> = Rc::new(RefCell::new(lambda!( + Generic, + { + let total: Ptr = total.as_pointer(); + }, + || { + total.write({ + (((total.read()) as usize).wrapping_add( + ((::std::mem::size_of::() as usize) + .wrapping_add((::std::mem::size_of::() as usize)) + as usize), + )) as i32 + }); + }, + || { + total.write({ + (((total.read()) as usize).wrapping_add( + ((::std::mem::size_of::() as usize) + .wrapping_add((::std::mem::size_of::() as usize)) + as usize), + )) as i32 + }); + } + ))); + ({ (*tally.borrow()).spec::(0).call() }); + ({ (*tally.borrow()).spec::(1).call() }); + assert!(((*total.borrow()) == 7)); + let v: Value = Rc::new(RefCell::new(Val { x: 5 })); + let acc: Value = Rc::new(RefCell::new(0)); + let pick: Value> = Rc::new(RefCell::new(lambda!( + Generic, + { + let v: Ptr = v.as_pointer(); + let acc: Ptr = acc.as_pointer(); + }, + || { + { + let __rhs = ({ + let _a: Val = (*v.upgrade().deref()).clone(); + let _b: Val = (*v.upgrade().deref()).clone(); + sum_0(_a, _b) + }); + acc.with_mut(|__v| *__v = *__v + __rhs) + }; + }, + || { + { + let __rhs = ({ + let _a: Val = (*v.upgrade().deref()).clone(); + let _b: Val = (*v.upgrade().deref()).clone(); + sum_0(_a, _b) + }); + acc.with_mut(|__v| *__v = *__v + __rhs) + }; + }, + || { + { + let __rhs = ({ + let _a: Val = (*v.upgrade().deref()).clone(); + let _b: Val = (*v.upgrade().deref()).clone(); + sum_0(_a, _b) + }); + acc.with_mut(|__v| *__v = *__v + __rhs) + }; + } + ))); + ({ (*pick.borrow()).spec::(0).call() }); + ({ (*pick.borrow()).spec::(1).call() }); + ({ (*pick.borrow()).spec::(2).call() }); + assert!(((*acc.borrow()) == 30)); + let cast_to: Value> = Rc::new(RefCell::new(lambda!( + Generic, + {}, + |x: i32| -> i32 { + return ((x as i32) / 2); + }, + |x: i32| -> f64 { + return ((x as f64) / 2_f64); + } + ))); + assert!((({ (*cast_to.borrow()).spec:: i32>(0).call(5,) }) == 2)); + assert!((({ (*cast_to.borrow()).spec:: f64>(1).call(5,) }) == 2.5_f64)); + return 0; +} +pub fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/refcount/lambda_generic_to_fn_ptr.rs b/tests/unit/out/refcount/lambda_generic_to_fn_ptr.rs new file mode 100644 index 000000000..3616dd703 --- /dev/null +++ b/tests/unit/out/refcount/lambda_generic_to_fn_ptr.rs @@ -0,0 +1,44 @@ +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 negate: Value> = Rc::new(RefCell::new(lambda!( + Generic, + {}, + |x: i32| -> i32 { + return -x; + }, + |x: f64| -> f64 { + return -x; + } + ))); + let mut fi: FnPtr i32> = (*negate.borrow()).clone().spec:: i32>(0); + let mut fd: FnPtr f64> = (*negate.borrow()).clone().spec:: f64>(1); + assert!((({ fi.call(3,) }) == -3_i32)); + assert!((({ fd.call(1.5_f64,) }) == -1.5_f64)); + let square: Value> = Rc::new(RefCell::new(lambda!( + Generic, + {}, + |x: i32| -> i32 { + return (x * x); + }, + |x: f64| -> f64 { + return (x * x); + } + ))); + let mut si: FnPtr i32> = (*square.borrow()).clone().spec:: i32>(0); + let mut sd: FnPtr f64> = (*square.borrow()).clone().spec:: f64>(1); + assert!((({ si.call(3,) }) == 9)); + assert!((({ sd.call(1.5_f64,) }) == 2.25_f64)); + return 0; +} +pub fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/refcount/lambda_self_recursive.rs b/tests/unit/out/refcount/lambda_self_recursive.rs new file mode 100644 index 000000000..4753be5a1 --- /dev/null +++ b/tests/unit/out/refcount/lambda_self_recursive.rs @@ -0,0 +1,104 @@ +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 fact: Value> = + Rc::new(RefCell::new(lambda!(Generic, {}, |self_: FnPtr< + Generic, + >, + n: i32| + -> i32 { + let self_: Value> = Rc::new(RefCell::new(self_)); + if (n <= 1) { + return 1; + } + return (n + * ({ + let _self_: FnPtr = (*self_.borrow()).clone(); + (*self_.borrow()) + .spec::, i32) -> i32>(0) + .call(_self_, (n - 1)) + })); + }))); + assert!( + (({ + let _self_: FnPtr = (*fact.borrow()).clone(); + (*fact.borrow()) + .spec::, i32) -> i32>(0) + .call(_self_, 5) + }) == 120) + ); + let calls: Value = Rc::new(RefCell::new(0)); + let fib: Value> = Rc::new(RefCell::new(lambda!( + Generic, + { + let calls: Ptr = calls.as_pointer(); + }, + |self_: Ptr>, n: i32| -> i32 { + calls.with_mut(|__v| __v.postfix_inc()); + if (n <= 2) { + return 1; + } + return (({ + let _self_: Ptr> = (self_).clone(); + let _n: i32 = (n - 1); + (*self_.upgrade().deref()) + .spec::>, i32) -> i32>(0) + .call(_self_, _n) + }) + ({ + let _self_: Ptr> = (self_).clone(); + let _n: i32 = (n - 2); + (*self_.upgrade().deref()) + .spec::>, i32) -> i32>(0) + .call(_self_, _n) + })); + } + ))); + assert!( + (({ + let _self_: Ptr> = fib.as_pointer(); + (*fib.borrow()) + .spec::>, i32) -> i32>(0) + .call(_self_, 6) + }) == 8) + ); + assert!(((*calls.borrow()) == 15)); + let depth: Value = Rc::new(RefCell::new(0)); + let count_down: Value> = Rc::new(RefCell::new(lambda!( + Generic, + { + let depth: Ptr = depth.as_pointer(); + }, + |self_: Ptr>, n: i32| { + if (n == 0) { + return; + } + depth.with_mut(|__v| __v.postfix_inc()); + ({ + let _self_: Ptr> = (self_).clone(); + let _n: i32 = (n - 1); + (*self_.upgrade().deref()) + .spec::>, i32)>(0) + .call(_self_, _n) + }); + } + ))); + ({ + let _self_: Ptr> = count_down.as_pointer(); + (*count_down.borrow()) + .spec::>, i32)>(0) + .call(_self_, 4) + }); + assert!(((*depth.borrow()) == 4)); + return 0; +} +pub 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..8e9afd495 --- /dev/null +++ b/tests/unit/out/unsafe/lambda_as_template_argument.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; +pub unsafe fn apply_int_0(mut fn_: FnPtr i32>, mut x: i32) -> i32 { + return (unsafe { fn_.call(x) }); +} +pub unsafe fn apply_int_1(mut fn_: FnPtr, mut x: i32) -> i32 { + return (unsafe { fn_.spec:: i32>(0).call(x) }); +} +pub unsafe fn apply_int_2(mut fn_: FnPtr, mut x: i32) -> i32 { + return (unsafe { fn_.spec:: i32>(0).call(x) }); +} +pub unsafe fn apply_int_3(mut fn_: FnPtr, mut x: i32) -> i32 { + return (unsafe { fn_.spec:: i32>(0).call(x) }); +} +pub unsafe fn apply_double_4(mut fn_: FnPtr, mut x: f64) -> f64 { + return (unsafe { fn_.spec:: f64>(1).call(x) }); +} +pub unsafe fn apply_double_5(mut fn_: FnPtr, mut x: f64) -> f64 { + return (unsafe { fn_.spec:: f64>(1).call(x) }); +} +pub unsafe fn apply_twice_6(mut fn_: FnPtr i32>, mut x: i32) -> i32 { + return (unsafe { + let _x: i32 = (unsafe { fn_.call(x) }); + fn_.call(_x) + }); +} +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: FnPtr i32> = lambda_unsafe!( + { + let factor: i32 = factor; + }, + |x: i32| -> i32 { + return ((x) * (factor)); + } + ); + assert!(((unsafe { apply_twice_6(scale.copy_from(), 4,) }) == (36))); + assert!( + ((unsafe { + apply_int_0( + FnPtr:: i32>::new(|x: i32| -> i32 { + unsafe { + return -x; + } + }), + 9, + ) + }) == (-9_i32)) + ); + let mut generic_scale: FnPtr = lambda_unsafe!( + Generic, + { + let factor: i32 = factor; + }, + |x: i32| -> i32 { + return ((x) * (factor)); + }, + |x: f64| -> f64 { + return ((x) * (factor as f64)); + } + ); + assert!(((unsafe { apply_int_1(generic_scale.copy_from(), 4,) }) == (12))); + assert!(((unsafe { apply_double_4(generic_scale.copy_from(), 1.5_f64,) }) == (4.5_f64))); + assert!( + ((unsafe { + apply_int_2( + lambda_unsafe!(Generic, {}, |x: i32| -> i32 { + return -x; + }), + 9, + ) + }) == (-9_i32)) + ); + let mut offset: FnPtr = lambda_unsafe!( + Generic, + { + let factor: i32 = factor; + }, + |x: i32| -> i32 { + return ((x) + (factor)); + }, + |x: f64| -> f64 { + return ((x) + (factor as f64)); + } + ); + assert!(((unsafe { apply_int_3(offset.copy_from(), 4,) }) == (7))); + assert!(((unsafe { apply_double_5(offset.copy_from(), 1.5_f64,) }) == (4.5_f64))); + return 0; +} +pub unsafe fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/unsafe/lambda_generic.rs b/tests/unit/out/unsafe/lambda_generic.rs new file mode 100644 index 000000000..4bcaa4021 --- /dev/null +++ b/tests/unit/out/unsafe/lambda_generic.rs @@ -0,0 +1,87 @@ +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 twice: FnPtr = lambda_unsafe!( + Generic, + {}, + |x: i32| -> i32 { + return ((x) + (x)); + }, + |x: f64| -> f64 { + return ((x) + (x)); + } + ); + assert!(((unsafe { twice.spec:: i32>(0).call(4,) }) == (8))); + assert!(((unsafe { twice.spec:: f64>(1).call(1.5_f64,) }) == (3_f64))); + let mut base: i32 = 10; + let mut add_base: FnPtr = lambda_unsafe!( + Generic, + { + let base: i32 = base; + }, + |x: i32| -> i32 { + return ((x) + (base)); + }, + |x: f64| -> f64 { + return ((x) + (base as f64)); + } + ); + assert!(((unsafe { add_base.spec:: i32>(0).call(5,) }) == (15))); + assert!(((unsafe { add_base.spec:: f64>(1).call(2.5_f64,) }) == (12.5_f64))); + let mut total: i32 = 0; + let mut accumulate: FnPtr = lambda_unsafe!( + Generic, + { + let total: *mut i32 = &mut total; + }, + |x: i32, y: i32| { + (*total) += ((x) * (y)); + }, + |x: u32, y: u32| { + (*total) = (((*total) as u32).wrapping_add((x).wrapping_mul(y))) as i32; + } + ); + (unsafe { accumulate.spec::(0).call(2, 3) }); + (unsafe { accumulate.spec::(1).call(4_u32, 5_u32) }); + assert!(((total) == (26))); + let mut sub: FnPtr = lambda_unsafe!( + Generic, + {}, + |x: i32, y: i32| -> i32 { + return ((x) - (y)); + }, + |x: f64, y: f64| -> f64 { + return ((x) - (y)); + } + ); + assert!(((unsafe { sub.spec:: i32>(0).call(9, 4,) }) == (5))); + assert!(((unsafe { sub.spec:: f64>(1).call(2.5_f64, 1_f64,) }) == (1.5_f64))); + let mut mixed: FnPtr = lambda_unsafe!( + Generic, + { + let base: i32 = base; + }, + |x: i32, y: i32| -> i32 { + return (((x) * (y)) + (base)); + }, + |x: i32, y: f64| -> f64 { + return (((x as f64) * (y)) + (base as f64)); + } + ); + assert!(((unsafe { mixed.spec:: i32>(0).call(2, 3,) }) == (16))); + assert!(((unsafe { mixed.spec:: f64>(1).call(2, 0.5_f64,) }) == (11_f64))); + return 0; +} +pub unsafe fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/unsafe/lambda_generic_explicit_args.rs b/tests/unit/out/unsafe/lambda_generic_explicit_args.rs new file mode 100644 index 000000000..2c9b02f55 --- /dev/null +++ b/tests/unit/out/unsafe/lambda_generic_explicit_args.rs @@ -0,0 +1,96 @@ +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, VaArg, FnPtrArg, Default)] +pub struct Val { + pub x: i32, +} +pub unsafe fn sum_0(mut a: Val, mut b: Val) -> i32 { + return ((a.x) + (b.x)); +} +pub fn main() { + unsafe { + __cpp2rust_init_globals(); + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut total: i32 = 0; + let mut tally: FnPtr = lambda_unsafe!( + Generic, + { + let total: *mut i32 = &mut total; + }, + || { + (*total) = (((*total) as usize).wrapping_add( + ((::std::mem::size_of::() as usize) + .wrapping_add((::std::mem::size_of::() as usize)) + as usize), + )) as i32; + }, + || { + (*total) = (((*total) as usize).wrapping_add( + ((::std::mem::size_of::() as usize) + .wrapping_add((::std::mem::size_of::() as usize)) + as usize), + )) as i32; + } + ); + (unsafe { tally.spec::(0).call() }); + (unsafe { tally.spec::(1).call() }); + assert!(((total) == (7))); + let mut v: Val = Val { x: 5 }; + let mut acc: i32 = 0; + let mut pick: FnPtr = lambda_unsafe!( + Generic, + { + let v: *mut Val = &mut v; + let acc: *mut i32 = &mut acc; + }, + || { + (*acc) += (unsafe { + let _a: Val = (*v); + let _b: Val = (*v); + sum_0(_a, _b) + }); + }, + || { + (*acc) += (unsafe { + let _a: Val = (*v); + let _b: Val = (*v); + sum_0(_a, _b) + }); + }, + || { + (*acc) += (unsafe { + let _a: Val = (*v); + let _b: Val = (*v); + sum_0(_a, _b) + }); + } + ); + (unsafe { pick.spec::(0).call() }); + (unsafe { pick.spec::(1).call() }); + (unsafe { pick.spec::(2).call() }); + assert!(((acc) == (30))); + let mut cast_to: FnPtr = lambda_unsafe!( + Generic, + {}, + |x: i32| -> i32 { + return ((x as i32) / (2)); + }, + |x: i32| -> f64 { + return ((x as f64) / (2_f64)); + } + ); + assert!(((unsafe { cast_to.spec:: i32>(0).call(5,) }) == (2))); + assert!(((unsafe { cast_to.spec:: f64>(1).call(5,) }) == (2.5_f64))); + return 0; +} +pub unsafe fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/unsafe/lambda_generic_to_fn_ptr.rs b/tests/unit/out/unsafe/lambda_generic_to_fn_ptr.rs new file mode 100644 index 000000000..78dd373ec --- /dev/null +++ b/tests/unit/out/unsafe/lambda_generic_to_fn_ptr.rs @@ -0,0 +1,54 @@ +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 negate: FnPtr = lambda_unsafe!( + Generic, + {}, + |x: i32| -> i32 { + return -x; + }, + |x: f64| -> f64 { + return -x; + } + ); + let mut fi: Option i32> = Some(|x: i32| -> i32 { + return -x; + }); + let mut fd: Option f64> = Some(|x: f64| -> f64 { + return -x; + }); + assert!(((unsafe { (fi).unwrap()(3,) }) == (-3_i32))); + assert!(((unsafe { (fd).unwrap()(1.5_f64,) }) == (-1.5_f64))); + let mut square: FnPtr = lambda_unsafe!( + Generic, + {}, + |x: i32| -> i32 { + return ((x) * (x)); + }, + |x: f64| -> f64 { + return ((x) * (x)); + } + ); + let mut si: Option i32> = Some(|x: i32| -> i32 { + return ((x) * (x)); + }); + let mut sd: Option f64> = Some(|x: f64| -> f64 { + return ((x) * (x)); + }); + assert!(((unsafe { (si).unwrap()(3,) }) == (9))); + assert!(((unsafe { (sd).unwrap()(1.5_f64,) }) == (2.25_f64))); + return 0; +} +pub unsafe fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/unsafe/lambda_self_recursive.rs b/tests/unit/out/unsafe/lambda_self_recursive.rs new file mode 100644 index 000000000..7f95fb6c6 --- /dev/null +++ b/tests/unit/out/unsafe/lambda_self_recursive.rs @@ -0,0 +1,99 @@ +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 fact: FnPtr = + lambda_unsafe!(Generic, {}, |self_: FnPtr, n: i32| -> i32 { + if ((n) <= (1)) { + return 1; + } + return ((n) + * (unsafe { + let _self_: FnPtr = self_.clone(); + self_ + .spec::, i32) -> i32>(0) + .call(_self_, ((n) - (1))) + })); + }); + assert!( + ((unsafe { + let _self_: FnPtr = fact.clone(); + fact.spec::, i32) -> i32>(0) + .call(_self_, 5) + }) == (120)) + ); + let mut calls: i32 = 0; + let mut fib: FnPtr = lambda_unsafe!( + Generic, + { + let calls: *mut i32 = &mut calls; + }, + |self_: *mut FnPtr, n: i32| -> i32 { + (*calls).postfix_inc(); + if ((n) <= (2)) { + return 1; + } + return ((unsafe { + let _self_: *mut FnPtr = self_; + let _n: i32 = ((n) - (1)); + (*self_) + .spec::, i32) -> i32>(0) + .call(_self_, _n) + }) + (unsafe { + let _self_: *mut FnPtr = self_; + let _n: i32 = ((n) - (2)); + (*self_) + .spec::, i32) -> i32>(0) + .call(_self_, _n) + })); + } + ); + assert!( + ((unsafe { + let _self_: *mut FnPtr = &mut fib; + fib.spec::, i32) -> i32>(0) + .call(_self_, 6) + }) == (8)) + ); + assert!(((calls) == (15))); + let mut depth: i32 = 0; + let mut count_down: FnPtr = lambda_unsafe!( + Generic, + { + let depth: *mut i32 = &mut depth; + }, + |self_: *const FnPtr, n: i32| { + if ((n) == (0)) { + return; + } + (*depth).postfix_inc(); + (unsafe { + let _self_: *const FnPtr = self_; + let _n: i32 = ((n) - (1)); + (*self_) + .spec::, i32)>(0) + .call(_self_, _n) + }); + } + ); + (unsafe { + let _self_: *const FnPtr = &count_down; + count_down + .spec::, i32)>(0) + .call(_self_, 4) + }); + assert!(((depth) == (4))); + return 0; +} +pub unsafe fn __cpp2rust_init_globals() {}