diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 99da6e93..0aeea072 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -1361,6 +1361,16 @@ std::optional Converter::TryPluginConvert(clang::CallExpr *call) { return std::nullopt; } +void Converter::ConvertVariadicArg(clang::Expr *arg) { + if (arg->getType()->isFunctionPointerType()) { + PushParen p(*this); + Convert(arg); + StrCat(".map_or(::std::ptr::null_mut(), |f| f as *mut ::libc::c_void)"); + return; + } + Convert(arg); +} + void Converter::ConvertVAArgCall(clang::CallExpr *expr) { if (IsBuiltinVaStart(expr)) { StrCat(ToString(expr->getArg(0)->IgnoreImpCasts()), @@ -1571,7 +1581,7 @@ void Converter::ConvertGenericCallExpr(clang::CallExpr *expr) { StrCat("& ["); for (unsigned i = num_named_params; i < num_args; ++i) { auto *arg = expr->getArg(i + arg_begin); - Convert(arg); + ConvertVariadicArg(arg); StrCat(".into()", token::kComma); } StrCat(']'); @@ -2598,6 +2608,18 @@ bool Converter::VisitVAArgExpr(clang::VAArgExpr *expr) { if (auto *cast = clang::dyn_cast(va_list_expr)) { va_list_expr = cast->getSubExpr(); } + if (expr->getType()->isFunctionPointerType()) { + StrCat("std::mem::transmute::<*mut ::libc::c_void", token::kComma); + Convert(expr->getType()); + StrCat('>'); + PushParen paren(*this); + { + PushExprKind push(*this, ExprKind::RValue); + Convert(va_list_expr); + } + StrCat(".arg::<*mut ::libc::c_void>()"); + return false; + } Convert(va_list_expr); StrCat(".arg::<"); Convert(expr->getType()); diff --git a/cpp2rust/converter/converter.h b/cpp2rust/converter/converter.h index 4b9fec39..a5d8822f 100644 --- a/cpp2rust/converter/converter.h +++ b/cpp2rust/converter/converter.h @@ -224,6 +224,8 @@ class Converter : public clang::RecursiveASTVisitor { void ConvertVAArgCall(clang::CallExpr *expr); + virtual void ConvertVariadicArg(clang::Expr *arg); + virtual bool VisitCallExpr(clang::CallExpr *expr); virtual bool VisitIntegerLiteral(clang::IntegerLiteral *expr); diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index 28ec755d..3bc4b98f 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -1602,6 +1602,8 @@ bool ConverterRefCount::VisitImplicitValueInitExpr( return Converter::VisitImplicitValueInitExpr(expr); } +void ConverterRefCount::ConvertVariadicArg(clang::Expr *arg) { Convert(arg); } + bool ConverterRefCount::VisitVAArgExpr(clang::VAArgExpr *expr) { auto va_list_expr = expr->getSubExpr(); if (auto *cast = clang::dyn_cast(va_list_expr)) { diff --git a/cpp2rust/converter/models/converter_refcount.h b/cpp2rust/converter/models/converter_refcount.h index a435982a..d890586a 100644 --- a/cpp2rust/converter/models/converter_refcount.h +++ b/cpp2rust/converter/models/converter_refcount.h @@ -116,6 +116,8 @@ class ConverterRefCount final : public Converter { bool VisitVAArgExpr(clang::VAArgExpr *expr) override; + void ConvertVariadicArg(clang::Expr *arg) override; + void ConvertArrayCXXConstructExpr(clang::CXXConstructExpr *expr) override; bool VisitCXXDefaultArgExpr(clang::CXXDefaultArgExpr *expr) override; diff --git a/libcc2rs/src/va_args.rs b/libcc2rs/src/va_args.rs index be21764f..157dcadc 100644 --- a/libcc2rs/src/va_args.rs +++ b/libcc2rs/src/va_args.rs @@ -121,3 +121,18 @@ impl VaArgGet for crate::rc::Ptr { } } } + +impl From> for VaArg { + fn from(v: crate::FnPtr) -> Self { + VaArg::Ptr(v.to_any()) + } +} + +impl VaArgGet for crate::FnPtr { + fn get(v: &VaArg) -> Self { + match v { + VaArg::Ptr(any) => any.cast_fn::().expect("VaArgGet: FnPtr type mismatch"), + _ => panic!("VaArgGet: expected FnPtr"), + } + } +} diff --git a/tests/unit/out/refcount/va_arg_fn_ptr.rs b/tests/unit/out/refcount/va_arg_fn_ptr.rs new file mode 100644 index 00000000..007862b4 --- /dev/null +++ b/tests/unit/out/refcount/va_arg_fn_ptr.rs @@ -0,0 +1,81 @@ +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 square_0(x: i32) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + return ((*x.borrow()) * (*x.borrow())); +} +pub fn negate_1(x: i32) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + return -(*x.borrow()); +} +pub fn add_2(a: i32, b: i32) -> i32 { + let a: Value = Rc::new(RefCell::new(a)); + let b: Value = Rc::new(RefCell::new(b)); + return ((*a.borrow()) + (*b.borrow())); +} +pub fn apply_unary_3(x: i32, __args: &[VaArg]) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + let ap: Value = Rc::new(RefCell::new(VaList::default())); + (*ap.borrow_mut()) = VaList::new(__args); + let fn_: Value i32>> = Rc::new(RefCell::new( + ((*ap.borrow_mut()).arg:: i32>>()).clone(), + )); + let result: Value = Rc::new(RefCell::new( + ({ + let _arg0: i32 = (*x.borrow()); + (*(*fn_.borrow()))(_arg0) + }), + )); + return (*result.borrow()); +} +pub fn apply_binary_4(a: i32, b: i32, __args: &[VaArg]) -> i32 { + let a: Value = Rc::new(RefCell::new(a)); + let b: Value = Rc::new(RefCell::new(b)); + let ap: Value = Rc::new(RefCell::new(VaList::default())); + (*ap.borrow_mut()) = VaList::new(__args); + let fn_: Value i32>> = Rc::new(RefCell::new( + ((*ap.borrow_mut()).arg:: i32>>()).clone(), + )); + let result: Value = Rc::new(RefCell::new( + ({ + let _arg0: i32 = (*a.borrow()); + let _arg1: i32 = (*b.borrow()); + (*(*fn_.borrow()))(_arg0, _arg1) + }), + )); + return (*result.borrow()); +} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + assert!( + (((({ + let _x: i32 = 5; + apply_unary_3(_x, &[FnPtr:: i32>::new(square_0).into()]) + }) == 25) as i32) + != 0) + ); + assert!( + (((({ + let _x: i32 = 7; + apply_unary_3(_x, &[FnPtr:: i32>::new(negate_1).into()]) + }) == -7_i32) as i32) + != 0) + ); + assert!( + (((({ + let _a: i32 = 3; + let _b: i32 = 4; + apply_binary_4(_a, _b, &[FnPtr:: i32>::new(add_2).into()]) + }) == 7) as i32) + != 0) + ); + return 0; +} diff --git a/tests/unit/out/unsafe/va_arg_fn_ptr.rs b/tests/unit/out/unsafe/va_arg_fn_ptr.rs new file mode 100644 index 00000000..1c2ce83d --- /dev/null +++ b/tests/unit/out/unsafe/va_arg_fn_ptr.rs @@ -0,0 +1,93 @@ +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 square_0(mut x: i32) -> i32 { + return ((x) * (x)); +} +pub unsafe fn negate_1(mut x: i32) -> i32 { + return -x; +} +pub unsafe fn add_2(mut a: i32, mut b: i32) -> i32 { + return ((a) + (b)); +} +pub unsafe fn apply_unary_3(mut x: i32, __args: &[VaArg]) -> i32 { + let mut ap: VaList = VaList::default(); + ap = VaList::new(__args); + let mut fn_: Option i32> = std::mem::transmute::< + *mut ::libc::c_void, + Option i32>, + >(ap.arg::<*mut ::libc::c_void>()); + let mut result: i32 = (unsafe { + let _arg0: i32 = x; + (fn_).unwrap()(_arg0) + }); + return result; +} +pub unsafe fn apply_binary_4(mut a: i32, mut b: i32, __args: &[VaArg]) -> i32 { + let mut ap: VaList = VaList::default(); + ap = VaList::new(__args); + let mut fn_: Option i32> = std::mem::transmute::< + *mut ::libc::c_void, + Option i32>, + >(ap.arg::<*mut ::libc::c_void>()); + let mut result: i32 = (unsafe { + let _arg0: i32 = a; + let _arg1: i32 = b; + (fn_).unwrap()(_arg0, _arg1) + }); + return result; +} +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + assert!( + ((((unsafe { + let _x: i32 = 5; + apply_unary_3( + _x, + &[ + (Some(square_0).map_or(::std::ptr::null_mut(), |f| f as *mut ::libc::c_void)) + .into(), + ], + ) + }) == (25)) as i32) + != 0) + ); + assert!( + ((((unsafe { + let _x: i32 = 7; + apply_unary_3( + _x, + &[ + (Some(negate_1).map_or(::std::ptr::null_mut(), |f| f as *mut ::libc::c_void)) + .into(), + ], + ) + }) == (-7_i32)) as i32) + != 0) + ); + assert!( + ((((unsafe { + let _a: i32 = 3; + let _b: i32 = 4; + apply_binary_4( + _a, + _b, + &[ + (Some(add_2).map_or(::std::ptr::null_mut(), |f| f as *mut ::libc::c_void)) + .into(), + ], + ) + }) == (7)) as i32) + != 0) + ); + return 0; +} diff --git a/tests/unit/va_arg_fn_ptr.c b/tests/unit/va_arg_fn_ptr.c new file mode 100644 index 00000000..bf547808 --- /dev/null +++ b/tests/unit/va_arg_fn_ptr.c @@ -0,0 +1,34 @@ +#include +#include + +typedef int (*unary)(int); +typedef int (*binary)(int, int); + +int square(int x) { return x * x; } +int negate(int x) { return -x; } +int add(int a, int b) { return a + b; } + +int apply_unary(int x, ...) { + va_list ap; + va_start(ap, x); + unary fn = va_arg(ap, unary); + int result = fn(x); + va_end(ap); + return result; +} + +int apply_binary(int a, int b, ...) { + va_list ap; + va_start(ap, b); + binary fn = va_arg(ap, binary); + int result = fn(a, b); + va_end(ap); + return result; +} + +int main() { + assert(apply_unary(5, square) == 25); + assert(apply_unary(7, negate) == -7); + assert(apply_binary(3, 4, add) == 7); + return 0; +}