Skip to content

Commit ea550fb

Browse files
authored
Translate references to functions as function pointers (#486)
1 parent 1f2982c commit ea550fb

5 files changed

Lines changed: 154 additions & 0 deletions

File tree

‎cpp2rust/converter/converter.cpp‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,9 @@ bool Converter::VisitIncompleteArrayType(clang::IncompleteArrayType *type) {
274274

275275
bool Converter::VisitReferenceType(clang::ReferenceType *type) {
276276
auto pointee_type = type->getPointeeType();
277+
if (pointee_type->isFunctionType()) {
278+
return Convert(ctx_.getPointerType(pointee_type));
279+
}
277280
StrCat(pointee_type.isConstQualified() ? "*const" : "*mut");
278281
return Convert(pointee_type);
279282
}
@@ -4311,6 +4314,12 @@ std::string Converter::GetUnsafeTypeAsString(clang::QualType qual_type) const {
43114314
}
43124315

43134316
void Converter::ConvertVarInit(clang::QualType qual_type, clang::Expr *expr) {
4317+
if (qual_type->isFunctionReferenceType()) {
4318+
PushExprKind push(*this, ExprKind::AddrOf);
4319+
PushInitType init_type(*this, qual_type);
4320+
Convert(expr);
4321+
return;
4322+
}
43144323
if (qual_type->isReferenceType() && !IsReferenceType(expr)) {
43154324
if (llvm::isa<clang::MaterializeTemporaryExpr>(expr->IgnoreImpCasts())) {
43164325
StrCat(EmitMaterializedTempBinding(qual_type, expr));

‎cpp2rust/converter/models/converter_refcount.cpp‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,10 @@ bool ConverterRefCount::VisitIncompleteArrayType(
286286

287287
bool ConverterRefCount::VisitReferenceType(clang::ReferenceType *type) {
288288
auto pointee_type = type->getPointeeType();
289+
if (pointee_type->isFunctionType()) {
290+
PushConversionKind push(*this, ConversionKind::Unboxed);
291+
return Convert(ctx_.getPointerType(pointee_type));
292+
}
289293
if (pointee_type->isArrayType()) {
290294
// A reference to an array decays straight to a pointer to its first
291295
// element, the same way a by-value array parameter would, instead of

‎tests/unit/fn_ref.cpp‎

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#include <cassert>
2+
3+
static int square(int x) { return x * x; }
4+
5+
static int twice(int x) { return 2 * x; }
6+
7+
static int call_ref(int (&f)(int), int x) { return f(x); }
8+
9+
template <class F> static int call_deduced(F &f, int x) { return f(x); }
10+
11+
template <class F> static int call_forwarded(F &&f, int x) { return f(x); }
12+
13+
struct Holder {
14+
int (&f)(int);
15+
int run(int x) const { return f(x); }
16+
};
17+
18+
int main() {
19+
assert(call_ref(square, 3) == 9);
20+
assert(call_ref(twice, 3) == 6);
21+
22+
int (&r)(int) = square;
23+
assert(r(4) == 16);
24+
assert(call_ref(r, 5) == 25);
25+
26+
assert(call_deduced(twice, 7) == 14);
27+
assert(call_forwarded(square, 6) == 36);
28+
29+
Holder h{twice};
30+
assert(h.run(8) == 16);
31+
return 0;
32+
}

‎tests/unit/out/refcount/fn_ref.rs‎

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
extern crate libcc2rs;
2+
use libcc2rs::*;
3+
use std::cell::RefCell;
4+
use std::collections::BTreeMap;
5+
use std::io::prelude::*;
6+
use std::io::{Read, Seek, Write};
7+
use std::os::fd::AsFd;
8+
use std::rc::{Rc, Weak};
9+
pub fn square_0(mut x: i32) -> i32 {
10+
return (x * x);
11+
}
12+
pub fn twice_1(mut x: i32) -> i32 {
13+
return (2 * x);
14+
}
15+
pub fn call_ref_2(f: FnPtr<fn(i32) -> i32>, mut x: i32) -> i32 {
16+
return ({ f.call(x) });
17+
}
18+
pub fn call_deduced_3(f: FnPtr<fn(i32) -> i32>, mut x: i32) -> i32 {
19+
return ({ f.call(x) });
20+
}
21+
pub fn call_forwarded_4(f: FnPtr<fn(i32) -> i32>, mut x: i32) -> i32 {
22+
return ({ f.call(x) });
23+
}
24+
#[derive(Clone, Record, ByteRepr, VaArg, FnPtrArg, Default)]
25+
#[byte_size(8)]
26+
pub struct Holder {
27+
#[offset(0)]
28+
#[byte_size(8)]
29+
pub f: FnPtr<fn(i32) -> i32>,
30+
}
31+
pub fn main() {
32+
__cpp2rust_init_globals();
33+
std::process::exit(main_0());
34+
}
35+
fn main_0() -> i32 {
36+
assert!((({ call_ref_2(FnPtr::<fn(i32) -> i32>::new(square_0), 3,) }) == 9));
37+
assert!((({ call_ref_2(FnPtr::<fn(i32) -> i32>::new(twice_1), 3,) }) == 6));
38+
let r: FnPtr<fn(i32) -> i32> = FnPtr::<fn(i32) -> i32>::new(square_0);
39+
assert!((({ r.call(4,) }) == 16));
40+
assert!((({ call_ref_2((r).clone(), 5,) }) == 25));
41+
assert!((({ call_deduced_3(FnPtr::<fn(i32) -> i32>::new(twice_1), 7,) }) == 14));
42+
assert!((({ call_forwarded_4(FnPtr::<fn(i32) -> i32>::new(square_0), 6,) }) == 36));
43+
let h: Value<Holder> = Rc::new(RefCell::new(Holder {
44+
f: FnPtr::<fn(i32) -> i32>::new(twice_1),
45+
}));
46+
assert!((({ HolderImpl::run(&h.as_pointer(), 8,) }) == 16));
47+
return 0;
48+
}
49+
pub trait HolderImpl {
50+
fn run(&self, x: i32) -> i32;
51+
}
52+
impl HolderImpl for Ptr<Holder> {
53+
fn run(&self, mut x: i32) -> i32 {
54+
return ({ (*self).with(|__s| __s.f.clone()).call(x) });
55+
}
56+
}
57+
pub fn __cpp2rust_init_globals() {}

‎tests/unit/out/unsafe/fn_ref.rs‎

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
extern crate libc;
2+
use libc::*;
3+
extern crate libcc2rs;
4+
use libcc2rs::*;
5+
use std::collections::BTreeMap;
6+
use std::io::{Read, Seek, Write};
7+
use std::os::fd::{AsFd, FromRawFd, IntoRawFd};
8+
use std::rc::Rc;
9+
pub unsafe fn square_0(mut x: i32) -> i32 {
10+
return ((x) * (x));
11+
}
12+
pub unsafe fn twice_1(mut x: i32) -> i32 {
13+
return ((2) * (x));
14+
}
15+
pub unsafe fn call_ref_2(f: Option<unsafe fn(i32) -> i32>, mut x: i32) -> i32 {
16+
return (unsafe { (f).unwrap()(x) });
17+
}
18+
pub unsafe fn call_deduced_3(f: Option<unsafe fn(i32) -> i32>, mut x: i32) -> i32 {
19+
return (unsafe { (f).unwrap()(x) });
20+
}
21+
pub unsafe fn call_forwarded_4(f: Option<unsafe fn(i32) -> i32>, mut x: i32) -> i32 {
22+
return (unsafe { (f).unwrap()(x) });
23+
}
24+
#[repr(C)]
25+
#[derive(Copy, Clone, VaArg, FnPtrArg, Default)]
26+
pub struct Holder {
27+
pub f: Option<unsafe fn(i32) -> i32>,
28+
}
29+
impl Holder {
30+
pub unsafe fn run(&self, mut x: i32) -> i32 {
31+
return (unsafe { (self.f).unwrap()(x) });
32+
}
33+
}
34+
pub fn main() {
35+
unsafe {
36+
__cpp2rust_init_globals();
37+
std::process::exit(main_0() as i32);
38+
}
39+
}
40+
unsafe fn main_0() -> i32 {
41+
assert!(((unsafe { call_ref_2(Some(square_0), 3,) }) == (9)));
42+
assert!(((unsafe { call_ref_2(Some(twice_1), 3,) }) == (6)));
43+
let r: Option<unsafe fn(i32) -> i32> = Some(square_0);
44+
assert!(((unsafe { (r).unwrap()(4,) }) == (16)));
45+
assert!(((unsafe { call_ref_2(r, 5,) }) == (25)));
46+
assert!(((unsafe { call_deduced_3(Some(twice_1), 7,) }) == (14)));
47+
assert!(((unsafe { call_forwarded_4(Some(square_0), 6,) }) == (36)));
48+
let mut h: Holder = Holder { f: Some(twice_1) };
49+
assert!(((unsafe { Holder::run(&h, 8,) }) == (16)));
50+
return 0;
51+
}
52+
pub unsafe fn __cpp2rust_init_globals() {}

0 commit comments

Comments
 (0)