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
9 changes: 9 additions & 0 deletions cpp2rust/converter/converter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,9 @@ bool Converter::VisitIncompleteArrayType(clang::IncompleteArrayType *type) {

bool Converter::VisitReferenceType(clang::ReferenceType *type) {
auto pointee_type = type->getPointeeType();
if (pointee_type->isFunctionType()) {
return Convert(ctx_.getPointerType(pointee_type));
}
StrCat(pointee_type.isConstQualified() ? "*const" : "*mut");
return Convert(pointee_type);
}
Expand Down Expand Up @@ -4299,6 +4302,12 @@ std::string Converter::GetUnsafeTypeAsString(clang::QualType qual_type) const {
}

void Converter::ConvertVarInit(clang::QualType qual_type, clang::Expr *expr) {
if (qual_type->isFunctionReferenceType()) {
PushExprKind push(*this, ExprKind::AddrOf);
PushInitType init_type(*this, qual_type);
Convert(expr);
return;
}
if (qual_type->isReferenceType() && !IsReferenceType(expr)) {
if (llvm::isa<clang::MaterializeTemporaryExpr>(expr->IgnoreImpCasts())) {
StrCat(EmitMaterializedTempBinding(qual_type, expr));
Expand Down
4 changes: 4 additions & 0 deletions cpp2rust/converter/models/converter_refcount.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,10 @@ bool ConverterRefCount::VisitIncompleteArrayType(

bool ConverterRefCount::VisitReferenceType(clang::ReferenceType *type) {
auto pointee_type = type->getPointeeType();
if (pointee_type->isFunctionType()) {
PushConversionKind push(*this, ConversionKind::Unboxed);
return Convert(ctx_.getPointerType(pointee_type));
}
if (pointee_type->isArrayType()) {
// A reference to an array decays straight to a pointer to its first
// element, the same way a by-value array parameter would, instead of
Expand Down
32 changes: 32 additions & 0 deletions tests/unit/fn_ref.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#include <cassert>

static int square(int x) { return x * x; }

static int twice(int x) { return 2 * x; }

static int call_ref(int (&f)(int), int x) { return f(x); }

template <class F> static int call_deduced(F &f, int x) { return f(x); }

template <class F> static int call_forwarded(F &&f, int x) { return f(x); }

struct Holder {
int (&f)(int);
int run(int x) const { return f(x); }
};

int main() {
assert(call_ref(square, 3) == 9);
assert(call_ref(twice, 3) == 6);

int (&r)(int) = square;
assert(r(4) == 16);
assert(call_ref(r, 5) == 25);

assert(call_deduced(twice, 7) == 14);
assert(call_forwarded(square, 6) == 36);

Holder h{twice};
assert(h.run(8) == 16);
return 0;
}
57 changes: 57 additions & 0 deletions tests/unit/out/refcount/fn_ref.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
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(mut x: i32) -> i32 {
return (x * x);
}
pub fn twice_1(mut x: i32) -> i32 {
return (2 * x);
}
pub fn call_ref_2(f: FnPtr<fn(i32) -> i32>, mut x: i32) -> i32 {
return ({ f.call(x) });
}
pub fn call_deduced_3(f: FnPtr<fn(i32) -> i32>, mut x: i32) -> i32 {
return ({ f.call(x) });
}
pub fn call_forwarded_4(f: FnPtr<fn(i32) -> i32>, mut x: i32) -> i32 {
return ({ f.call(x) });
}
#[derive(Clone, Record, ByteRepr, VaArg, FnPtrArg, Default)]
#[byte_size(8)]
pub struct Holder {
#[offset(0)]
#[byte_size(8)]
pub f: FnPtr<fn(i32) -> i32>,
}
pub fn main() {
__cpp2rust_init_globals();
std::process::exit(main_0());
}
fn main_0() -> i32 {
assert!((({ call_ref_2(FnPtr::<fn(i32) -> i32>::new(square_0), 3,) }) == 9));
assert!((({ call_ref_2(FnPtr::<fn(i32) -> i32>::new(twice_1), 3,) }) == 6));
let r: FnPtr<fn(i32) -> i32> = FnPtr::<fn(i32) -> i32>::new(square_0);
assert!((({ r.call(4,) }) == 16));
assert!((({ call_ref_2((r).clone(), 5,) }) == 25));
assert!((({ call_deduced_3(FnPtr::<fn(i32) -> i32>::new(twice_1), 7,) }) == 14));
assert!((({ call_forwarded_4(FnPtr::<fn(i32) -> i32>::new(square_0), 6,) }) == 36));
let h: Value<Holder> = Rc::new(RefCell::new(Holder {
f: FnPtr::<fn(i32) -> i32>::new(twice_1),
}));
assert!((({ HolderImpl::run(&h.as_pointer(), 8,) }) == 16));
return 0;
}
pub trait HolderImpl {
fn run(&self, x: i32) -> i32;
}
impl HolderImpl for Ptr<Holder> {
fn run(&self, mut x: i32) -> i32 {
return ({ (*self).with(|__s| __s.f.clone()).call(x) });
}
}
pub fn __cpp2rust_init_globals() {}
52 changes: 52 additions & 0 deletions tests/unit/out/unsafe/fn_ref.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
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 twice_1(mut x: i32) -> i32 {
return ((2) * (x));
}
pub unsafe fn call_ref_2(f: Option<unsafe fn(i32) -> i32>, mut x: i32) -> i32 {
return (unsafe { (f).unwrap()(x) });
}
pub unsafe fn call_deduced_3(f: Option<unsafe fn(i32) -> i32>, mut x: i32) -> i32 {
return (unsafe { (f).unwrap()(x) });
}
pub unsafe fn call_forwarded_4(f: Option<unsafe fn(i32) -> i32>, mut x: i32) -> i32 {
return (unsafe { (f).unwrap()(x) });
}
#[repr(C)]
#[derive(Copy, Clone, VaArg, FnPtrArg, Default)]
pub struct Holder {
pub f: Option<unsafe fn(i32) -> i32>,
}
impl Holder {
pub unsafe fn run(&self, mut x: i32) -> i32 {
return (unsafe { (self.f).unwrap()(x) });
}
}
pub fn main() {
unsafe {
__cpp2rust_init_globals();
std::process::exit(main_0() as i32);
}
}
unsafe fn main_0() -> i32 {
assert!(((unsafe { call_ref_2(Some(square_0), 3,) }) == (9)));
assert!(((unsafe { call_ref_2(Some(twice_1), 3,) }) == (6)));
let r: Option<unsafe fn(i32) -> i32> = Some(square_0);
assert!(((unsafe { (r).unwrap()(4,) }) == (16)));
assert!(((unsafe { call_ref_2(r, 5,) }) == (25)));
assert!(((unsafe { call_deduced_3(Some(twice_1), 7,) }) == (14)));
assert!(((unsafe { call_forwarded_4(Some(square_0), 6,) }) == (36)));
let mut h: Holder = Holder { f: Some(twice_1) };
assert!(((unsafe { Holder::run(&h, 8,) }) == (16)));
return 0;
}
pub unsafe fn __cpp2rust_init_globals() {}
Loading