Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 23 additions & 1 deletion cpp2rust/converter/converter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1361,6 +1361,16 @@ std::optional<std::string> 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()),
Expand Down Expand Up @@ -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(']');
Expand Down Expand Up @@ -2598,6 +2608,18 @@ bool Converter::VisitVAArgExpr(clang::VAArgExpr *expr) {
if (auto *cast = clang::dyn_cast<clang::ImplicitCastExpr>(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());
Expand Down
2 changes: 2 additions & 0 deletions cpp2rust/converter/converter.h
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,8 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {

void ConvertVAArgCall(clang::CallExpr *expr);

virtual void ConvertVariadicArg(clang::Expr *arg);

virtual bool VisitCallExpr(clang::CallExpr *expr);

virtual bool VisitIntegerLiteral(clang::IntegerLiteral *expr);
Expand Down
2 changes: 2 additions & 0 deletions cpp2rust/converter/models/converter_refcount.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<clang::ImplicitCastExpr>(va_list_expr)) {
Expand Down
2 changes: 2 additions & 0 deletions cpp2rust/converter/models/converter_refcount.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
15 changes: 15 additions & 0 deletions libcc2rs/src/va_args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,3 +121,18 @@ impl<T: 'static> VaArgGet for crate::rc::Ptr<T> {
}
}
}

impl<T: 'static> From<crate::FnPtr<T>> for VaArg {
fn from(v: crate::FnPtr<T>) -> Self {
VaArg::Ptr(v.to_any())
}
}

impl<T: 'static> VaArgGet for crate::FnPtr<T> {
fn get(v: &VaArg) -> Self {
match v {
VaArg::Ptr(any) => any.cast_fn::<T>().expect("VaArgGet: FnPtr type mismatch"),
_ => panic!("VaArgGet: expected FnPtr"),
}
}
}
81 changes: 81 additions & 0 deletions tests/unit/out/refcount/va_arg_fn_ptr.rs
Original file line number Diff line number Diff line change
@@ -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<i32> = Rc::new(RefCell::new(x));
return ((*x.borrow()) * (*x.borrow()));
}
pub fn negate_1(x: i32) -> i32 {
let x: Value<i32> = Rc::new(RefCell::new(x));
return -(*x.borrow());
}
pub fn add_2(a: i32, b: i32) -> i32 {
let a: Value<i32> = Rc::new(RefCell::new(a));
let b: Value<i32> = Rc::new(RefCell::new(b));
return ((*a.borrow()) + (*b.borrow()));
}
pub fn apply_unary_3(x: i32, __args: &[VaArg]) -> i32 {
let x: Value<i32> = Rc::new(RefCell::new(x));
let ap: Value<VaList> = Rc::new(RefCell::new(VaList::default()));
(*ap.borrow_mut()) = VaList::new(__args);
let fn_: Value<FnPtr<fn(i32) -> i32>> = Rc::new(RefCell::new(
((*ap.borrow_mut()).arg::<FnPtr<fn(i32) -> i32>>()).clone(),
));
let result: Value<i32> = 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<i32> = Rc::new(RefCell::new(a));
let b: Value<i32> = Rc::new(RefCell::new(b));
let ap: Value<VaList> = Rc::new(RefCell::new(VaList::default()));
(*ap.borrow_mut()) = VaList::new(__args);
let fn_: Value<FnPtr<fn(i32, i32) -> i32>> = Rc::new(RefCell::new(
((*ap.borrow_mut()).arg::<FnPtr<fn(i32, i32) -> i32>>()).clone(),
));
let result: Value<i32> = 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::<fn(i32) -> i32>::new(square_0).into()])
}) == 25) as i32)
!= 0)
);
assert!(
(((({
let _x: i32 = 7;
apply_unary_3(_x, &[FnPtr::<fn(i32) -> 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::<fn(i32, i32) -> i32>::new(add_2).into()])
}) == 7) as i32)
!= 0)
);
return 0;
}
93 changes: 93 additions & 0 deletions tests/unit/out/unsafe/va_arg_fn_ptr.rs
Original file line number Diff line number Diff line change
@@ -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<unsafe fn(i32) -> i32> = std::mem::transmute::<
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is Option needed here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We translate functions pointers to Option<fn> in unsafe. Option is needed to encode nullability

*mut ::libc::c_void,
Option<unsafe fn(i32) -> 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<unsafe fn(i32, i32) -> i32> = std::mem::transmute::<
*mut ::libc::c_void,
Option<unsafe fn(i32, i32) -> 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;
}
34 changes: 34 additions & 0 deletions tests/unit/va_arg_fn_ptr.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#include <assert.h>
#include <stdarg.h>

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;
}
Loading