diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 99d7b036..a5c0a469 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -1816,6 +1816,20 @@ void Converter::ConvertFunctionToFunctionPointer( computed_expr_type_ = ComputedExprType::FreshPointer; } +std::string Converter::ConvertFnPtrCallee(clang::Expr *arg) { + PushExprKind push(*this, ExprKind::Callee); + Buffer buf(*this); + Convert(arg); + return std::move(buf).str(); +} + +std::string Converter::ConvertFnPtrPlaceholder(clang::Expr *arg) { + auto proto = + arg->getType()->getPointeeType()->getAs(); + return std::format("({} as {} {})", ConvertFnPtrCallee(arg), keyword_unsafe_, + ConvertFunctionPointerType(proto)); +} + Converter::CallInfo Converter::CollectCallInfo(clang::CallExpr *expr) { using Kind = CallArg::Kind; @@ -4607,22 +4621,20 @@ void Converter::PlaceholderCtx::dump() const { << ", declared_in_rule_as_rust_ptr: " << declared_in_rule_as_rust_ptr << ", access: " << static_cast(access) - << ", param_type: " << param_type + << ", arg_idx: " << arg_idx << ", materialize_idx: " << materialize_idx << '\n'; } std::string Converter::ConvertPlaceholder(clang::Expr *expr, clang::Expr *arg, const PlaceholderCtx &ph_ctx) { if (arg->getType()->isFunctionPointerType()) { - PushExprKind push(*this, ExprKind::Callee); - Buffer buf(*this); - Convert(arg); - return std::move(buf).str(); + return ConvertFnPtrPlaceholder(arg); } if (ph_ctx.declared_in_rule_as_rust_ptr && arg->getType()->isArrayType()) { - return std::format("({} as {})", ConvertFreshPointer(arg), - ph_ctx.param_type); + return std::format( + "({} as {})", ConvertFreshPointer(arg), + Mapper::GetParamType(GetCalleeOrExpr(expr), ph_ctx.arg_idx)); } if (ph_ctx.needs_materialization()) { @@ -4637,8 +4649,9 @@ std::string Converter::ConvertPlaceholder(clang::Expr *expr, clang::Expr *arg, } if (ph_ctx.needs_pointer_receiver()) { - return std::format("({} as {})", ConvertFreshObject(arg), - ph_ctx.param_type); + return std::format( + "({} as {})", ConvertFreshObject(arg), + Mapper::GetParamType(GetCalleeOrExpr(expr), ph_ctx.arg_idx)); } if (ph_ctx.needs_object_receiver()) { @@ -4717,7 +4730,7 @@ std::string Converter::ConvertIRFragment( bool is_receiver = HasReceiver(expr) && arg_idx == 0; PlaceholderCtx ph_ctx{ - .param_type = Mapper::GetParamType(GetCalleeOrExpr(expr), arg_idx), + .arg_idx = arg_idx, .implicit_convert_to = GetParamImplicitConvertTarget(expr, arg_idx), .materialize_ctx = ctx, .materialize_idx = diff --git a/cpp2rust/converter/converter.h b/cpp2rust/converter/converter.h index 6a4996cf..f2cb8c7b 100644 --- a/cpp2rust/converter/converter.h +++ b/cpp2rust/converter/converter.h @@ -221,7 +221,7 @@ class Converter : public clang::RecursiveASTVisitor { }; struct PlaceholderCtx { - std::string param_type; + unsigned arg_idx; std::optional implicit_convert_to; TempMaterializationCtx *materialize_ctx; int materialize_idx; // <0 = no idx, >=0 idx valid @@ -309,6 +309,9 @@ class Converter : public clang::RecursiveASTVisitor { virtual void ConvertFunctionToFunctionPointer(const clang::FunctionDecl *fn_decl); + std::string ConvertFnPtrCallee(clang::Expr *arg); + virtual std::string ConvertFnPtrPlaceholder(clang::Expr *arg); + // Option implements Copy virtual bool FunctionPointerImplementsCopy() const { return true; } diff --git a/cpp2rust/converter/mapper.cpp b/cpp2rust/converter/mapper.cpp index 4def2784..b5ad34e4 100644 --- a/cpp2rust/converter/mapper.cpp +++ b/cpp2rust/converter/mapper.cpp @@ -682,10 +682,9 @@ std::string InstantiateTemplate(const clang::Expr *expr, unsigned n) { if (!rule) { return text; } - for (auto &ty : subs) { - if (ty) { - ty = mapTypeStringRecursive(*ty); - } + auto &ty = subs.at(n - 1); + if (ty) { + ty = mapTypeStringRecursive(*ty); } return instantiateTgt(subs, text); } diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index 8b6b7a19..625e62fc 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -1287,6 +1287,10 @@ void ConverterRefCount::ConvertFunctionToFunctionPointer( computed_expr_type_ = ComputedExprType::FreshPointer; } +std::string ConverterRefCount::ConvertFnPtrPlaceholder(clang::Expr *arg) { + return ConvertFnPtrCallee(arg); +} + void ConverterRefCount::ConvertEqualsNullPtr(clang::Expr *expr) { StrCat('('); Convert(expr); diff --git a/cpp2rust/converter/models/converter_refcount.h b/cpp2rust/converter/models/converter_refcount.h index f588f6d1..790f7530 100644 --- a/cpp2rust/converter/models/converter_refcount.h +++ b/cpp2rust/converter/models/converter_refcount.h @@ -103,6 +103,8 @@ class ConverterRefCount final : public Converter { void ConvertFunctionToFunctionPointer(const clang::FunctionDecl *fn_decl) override; + std::string ConvertFnPtrPlaceholder(clang::Expr *arg) override; + // FnPtr does not implement Copy bool FunctionPointerImplementsCopy() const override { return false; } diff --git a/libcc2rs/src/callable.rs b/libcc2rs/src/callable.rs new file mode 100644 index 00000000..f35dcfdc --- /dev/null +++ b/libcc2rs/src/callable.rs @@ -0,0 +1,32 @@ +// Copyright (c) 2022-present INESC-ID. +// Distributed under the MIT license that can be found in the LICENSE file. + +macro_rules! callable { + ($name:ident; $($a:ident: $A:ident),*) => { + pub trait $name<$($A,)* R> { + fn call(&self, $($a: $A),*) -> R; + } + + impl $name<$($A,)* R> for F + where + F: Fn($($A),*) -> R, + { + #[inline] + fn call(&self, $($a: $A),*) -> R { + self($($a),*) + } + } + + impl<$($A,)* R> $name<$($A,)* R> for unsafe fn($($A),*) -> R { + #[inline] + fn call(&self, $($a: $A),*) -> R { + unsafe { self($($a),*) } + } + } + }; +} + +callable!(Callable0;); +callable!(Callable1; a1: A1); +callable!(Callable2; a1: A1, a2: A2); +callable!(Callable3; a1: A1, a2: A2, a3: A3); diff --git a/libcc2rs/src/lib.rs b/libcc2rs/src/lib.rs index fb1f9be0..06b1e779 100644 --- a/libcc2rs/src/lib.rs +++ b/libcc2rs/src/lib.rs @@ -21,6 +21,9 @@ pub use libc_shims::*; mod fn_ptr; pub use fn_ptr::FnPtr; +mod callable; +pub use callable::*; + mod inc; pub use inc::*; diff --git a/rules/algorithm/src.cpp b/rules/algorithm/src.cpp index 097b05cb..0d2946cd 100644 --- a/rules/algorithm/src.cpp +++ b/rules/algorithm/src.cpp @@ -9,6 +9,7 @@ struct T2 { friend bool operator<(T2 a, T2 b) { return false; } + bool operator()(const T2 &, const T2 &) const; }; struct T1 { @@ -91,14 +92,7 @@ template T1 f3(T1 first, T1 last, const T2 &value) { return std::find(first, last, value); } -// TODO -auto lambda = [](const T2 &a, const T2 &b) { return false; }; -void f6(T1 first, T1 last, decltype(lambda) comp) { - return std::stable_sort(first, last, comp); -} - -template -void f7(T1 first, T1 last, bool (*comp)(const T2 &, const T2 &)) { +void f6(T1 first, T1 last, T2 comp) { return std::stable_sort(first, last, comp); } @@ -126,14 +120,7 @@ std::ostream_iterator f13(std::string::iterator a0, return std::copy(a0, a1, a2); } -// TODO -auto lambda_nref = [](T2 a, T2 b) { return false; }; -void f14(T1 *first, T1 *last, decltype(lambda_nref) comp) { - return std::stable_sort(first, last, comp); -} - -template -void f15(T1 *first, T1 *last, bool (*comp)(T2, T2)) { +void f14(T1 *first, T1 *last, T2 comp) { return std::stable_sort(first, last, comp); } diff --git a/rules/algorithm/tgt_refcount.rs b/rules/algorithm/tgt_refcount.rs index 74866b39..66b8a801 100644 --- a/rules/algorithm/tgt_refcount.rs +++ b/rules/algorithm/tgt_refcount.rs @@ -38,16 +38,9 @@ fn f3(a0: Ptr, a1: Ptr, a2: T1) -> Ptr fn f6(a0: Ptr, a1: Ptr, a2: T2) where - T2: FnMut(Ptr, Ptr) -> bool, + T2: Callable2, Ptr, bool>, { - a0.sort_with_cmp(a1.get_offset(), a2) -} - -fn f7(a0: Ptr, a1: Ptr, a2: T2) -where - T2: FnMut(Ptr, Ptr) -> bool, -{ - a0.sort_with_cmp(a1.get_offset(), a2) + a0.sort_with_cmp(a1.get_offset(), |x, y| a2.call(x, y)) } fn f8(a0: Ptr, a1: Ptr) -> Ptr { @@ -109,17 +102,9 @@ fn f13(a0: Ptr, a1: Ptr, a2: &mut ::std::fs::File) -> ::std::fs::File { fn f14(a0: Ptr, a1: Ptr, a2: T2) where - T2: Fn(T1, T1) -> bool, -{ - let fun = |x: Ptr, y: Ptr| a2((x.read()).clone(), (y.read()).clone()); - a0.sort_with_cmp(a1.get_offset(), fun) -} - -fn f15(a0: Ptr, a1: Ptr, a2: T2) -where - T2: Fn(T1, T1) -> bool, + T2: Callable2, { - let fun = |x: Ptr, y: Ptr| a2((x.read()).clone(), (y.read()).clone()); + let fun = |x: Ptr, y: Ptr| a2.call((x.read()).clone(), (y.read()).clone()); a0.sort_with_cmp(a1.get_offset(), fun) } diff --git a/rules/algorithm/tgt_unsafe.rs b/rules/algorithm/tgt_unsafe.rs index 101a2060..dbf6650e 100644 --- a/rules/algorithm/tgt_unsafe.rs +++ b/rules/algorithm/tgt_unsafe.rs @@ -1,6 +1,7 @@ // Copyright (c) 2022-present INESC-ID. // Distributed under the MIT license that can be found in the LICENSE file. +use libcc2rs::*; use std::io::{Seek, Write}; unsafe fn f1(a0: *mut T1, a1: *mut T1) { @@ -27,31 +28,15 @@ unsafe fn f3(a0: *mut T1, a1: *mut T1, a2: T1) -> *mut T1 { it } -unsafe fn f6(a0: *mut T1, a1: *mut T1, a2: &mut T2) +unsafe fn f6(a0: *mut T1, a1: *mut T1, a2: T2) where - T2: FnMut(&T1, &T1) -> bool, + T2: Callable2<*const T1, *const T1, bool>, { let len = a1.offset_from(a0) as usize; ::std::slice::from_raw_parts_mut(a0, len).sort_by(|x, y| { - if (a2)(x, y) { + if a2.call(x as *const _, y as *const _) { std::cmp::Ordering::Less - } else if (a2)(y, x) { - std::cmp::Ordering::Greater - } else { - std::cmp::Ordering::Equal - } - }) -} - -unsafe fn f7(a0: *mut T1, a1: *mut T1, a2: &mut T2) -where - T2: FnMut(&T1, &T1) -> bool, -{ - let len = a1.offset_from(a0) as usize; - ::std::slice::from_raw_parts_mut(a0, len).sort_by(|x, y| { - if (a2)(x, y) { - std::cmp::Ordering::Less - } else if (a2)(y, x) { + } else if a2.call(y as *const _, x as *const _) { std::cmp::Ordering::Greater } else { std::cmp::Ordering::Equal @@ -113,31 +98,15 @@ unsafe fn f13( a2.try_clone().unwrap() } -unsafe fn f14(a0: *mut T1, a1: *mut T1, a2: &mut T2) -where - T2: FnMut(T1, T1) -> bool, -{ - let len = a1.offset_from(a0) as usize; - ::std::slice::from_raw_parts_mut(a0, len).sort_by(|x, y| { - if (a2)(*x, *y) { - std::cmp::Ordering::Less - } else if (a2)(*y, *x) { - std::cmp::Ordering::Greater - } else { - std::cmp::Ordering::Equal - } - }) -} - -unsafe fn f15(a0: *mut T1, a1: *mut T1, a2: &mut T2) +unsafe fn f14(a0: *mut T1, a1: *mut T1, a2: T2) where - T2: FnMut(T1, T1) -> bool, + T2: Callable2, { let len = a1.offset_from(a0) as usize; ::std::slice::from_raw_parts_mut(a0, len).sort_by(|x, y| { - if (a2)(*x, *y) { + if a2.call(*x, *y) { std::cmp::Ordering::Less - } else if (a2)(*y, *x) { + } else if a2.call(*y, *x) { std::cmp::Ordering::Greater } else { std::cmp::Ordering::Equal diff --git a/tests/unit/out/refcount/fn_ptr_stable_sort.rs b/tests/unit/out/refcount/fn_ptr_stable_sort.rs index be45ffe6..6ca928be 100644 --- a/tests/unit/out/refcount/fn_ptr_stable_sort.rs +++ b/tests/unit/out/refcount/fn_ptr_stable_sort.rs @@ -61,7 +61,7 @@ fn main_0() -> i32 { }); (v.as_pointer() as Ptr).sort_with_cmp( (v.as_pointer() as Ptr).to_end().get_offset(), - Compare_0, + |x, y| Compare_0.call(x, y), ); assert!( ((*(*(v.as_pointer() as Ptr) diff --git a/tests/unit/out/refcount/stable_sort.rs b/tests/unit/out/refcount/stable_sort.rs index 5da4a391..784fbf00 100644 --- a/tests/unit/out/refcount/stable_sort.rs +++ b/tests/unit/out/refcount/stable_sort.rs @@ -17,7 +17,8 @@ fn main_0() -> i32 { let x: Value = Rc::new(RefCell::new(x)); let y: Value = Rc::new(RefCell::new(y)); return ((*x.borrow()) < (*y.borrow())); - })((x.read()).clone(), (y.read()).clone()) + }) + .call((x.read()).clone(), (y.read()).clone()) }; (arr1.as_pointer() as Ptr).sort_with_cmp( (arr1.as_pointer() as Ptr) diff --git a/tests/unit/out/unsafe/fn_ptr_stable_sort.rs b/tests/unit/out/unsafe/fn_ptr_stable_sort.rs index a0fd886a..2165c81e 100644 --- a/tests/unit/out/unsafe/fn_ptr_stable_sort.rs +++ b/tests/unit/out/unsafe/fn_ptr_stable_sort.rs @@ -28,9 +28,13 @@ unsafe fn main_0() -> i32 { { let len = v.as_mut_ptr().add(v.len()).offset_from(v.as_mut_ptr()) as usize; ::std::slice::from_raw_parts_mut(v.as_mut_ptr(), len).sort_by(|x, y| { - if (Compare_0)(x, y) { + if (Compare_0 as unsafe fn(*const Item, *const Item) -> bool) + .call(x as *const _, y as *const _) + { std::cmp::Ordering::Less - } else if (Compare_0)(y, x) { + } else if (Compare_0 as unsafe fn(*const Item, *const Item) -> bool) + .call(y as *const _, x as *const _) + { std::cmp::Ordering::Greater } else { std::cmp::Ordering::Equal diff --git a/tests/unit/out/unsafe/qsort_bsearch.rs b/tests/unit/out/unsafe/qsort_bsearch.rs index 2a1ff8a6..c3fa5eb6 100644 --- a/tests/unit/out/unsafe/qsort_bsearch.rs +++ b/tests/unit/out/unsafe/qsort_bsearch.rs @@ -25,7 +25,10 @@ unsafe fn main_0() -> i32 { Some(std::mem::transmute::< *const (), unsafe extern "C" fn(*const ::libc::c_void, *const ::libc::c_void) -> i32, - >(cmp_int_0 as *const ())), + >( + (cmp_int_0 as unsafe fn(*const ::libc::c_void, *const ::libc::c_void) -> i32) + as *const (), + )), ); let mut i: i32 = 0; 'loop_: while ((((i) < (7)) as i32) != 0) { @@ -41,7 +44,10 @@ unsafe fn main_0() -> i32 { Some(std::mem::transmute::< *const (), unsafe extern "C" fn(*const ::libc::c_void, *const ::libc::c_void) -> i32, - >(cmp_int_0 as *const ())), + >( + (cmp_int_0 as unsafe fn(*const ::libc::c_void, *const ::libc::c_void) -> i32) + as *const (), + )), ) as *mut i32); assert!((((!((hit).is_null())) as i32) != 0)); assert!(((((*hit) == (7)) as i32) != 0)); @@ -54,7 +60,10 @@ unsafe fn main_0() -> i32 { Some(std::mem::transmute::< *const (), unsafe extern "C" fn(*const ::libc::c_void, *const ::libc::c_void) -> i32, - >(cmp_int_0 as *const ())), + >( + (cmp_int_0 as unsafe fn(*const ::libc::c_void, *const ::libc::c_void) -> i32) + as *const (), + )), ) as *mut i32); assert!(((((miss).is_null()) as i32) != 0)); return 0; diff --git a/tests/unit/out/unsafe/stable_sort.rs b/tests/unit/out/unsafe/stable_sort.rs index 7427395a..da3cd9de 100644 --- a/tests/unit/out/unsafe/stable_sort.rs +++ b/tests/unit/out/unsafe/stable_sort.rs @@ -21,12 +21,14 @@ unsafe fn main_0() -> i32 { ::std::slice::from_raw_parts_mut(arr1.as_mut_ptr(), len).sort_by(|x, y| { if (|x: i32, y: i32| { return ((x) < (y)); - })(*x, *y) + }) + .call(*x, *y) { std::cmp::Ordering::Less } else if (|x: i32, y: i32| { return ((x) < (y)); - })(*y, *x) + }) + .call(*y, *x) { std::cmp::Ordering::Greater } else {