Skip to content

Commit 9b131b1

Browse files
committed
Move PtrKind::Fn into FnPtr
1 parent f35afcf commit 9b131b1

17 files changed

Lines changed: 290 additions & 220 deletions

cpp2rust/converter/models/converter_refcount.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ ConverterRefCount::GetFnTypeString(const clang::FunctionProtoType *proto) {
230230

231231
bool ConverterRefCount::VisitPointerType(clang::PointerType *type) {
232232
if (auto proto = type->getPointeeType()->getAs<clang::FunctionProtoType>()) {
233-
StrCat(std::format("Ptr<{}>", GetFnTypeString(proto)));
233+
StrCat(std::format("FnPtr<{}>", GetFnTypeString(proto)));
234234
return false;
235235
}
236236

@@ -1017,7 +1017,7 @@ bool ConverterRefCount::VisitImplicitCastExpr(clang::ImplicitCastExpr *expr) {
10171017

10181018
if (expr->getCastKind() == clang::CastKind::CK_NullToPointer &&
10191019
expr->getType()->isFunctionPointerType()) {
1020-
StrCat("Ptr::null()");
1020+
StrCat("FnPtr::null()");
10211021
computed_expr_type_ = ComputedExprType::FreshPointer;
10221022
return false;
10231023
}
@@ -1027,12 +1027,12 @@ bool ConverterRefCount::VisitImplicitCastExpr(clang::ImplicitCastExpr *expr) {
10271027

10281028
void ConverterRefCount::EmitFnPtrCall(clang::Expr *callee) {
10291029
Convert(callee);
1030-
StrCat(".call_fn()");
1030+
StrCat(".call()");
10311031
}
10321032

10331033
std::string ConverterRefCount::GetFunctionPointerDefaultAsString(
10341034
clang::QualType qual_type) {
1035-
return "Ptr::null()";
1035+
return "FnPtr::null()";
10361036
}
10371037

10381038
void ConverterRefCount::ConvertEqualsNullPtr(clang::Expr *expr) {
@@ -1066,7 +1066,7 @@ bool ConverterRefCount::VisitFunctionPointerCast(
10661066
}
10671067
}
10681068

1069-
StrCat(std::format("{}.cast_fn::<{}>({})", ToString(expr->getSubExpr()),
1069+
StrCat(std::format("{}.cast::<{}>({})", ToString(expr->getSubExpr()),
10701070
fn_type, adapter));
10711071
} else if (expr->getSubExpr()->getType()->isFunctionPointerType() ||
10721072
expr->getType()->isVoidPointerType()) {
@@ -1077,7 +1077,7 @@ bool ConverterRefCount::VisitFunctionPointerCast(
10771077
auto target_proto =
10781078
expr->getType()->getPointeeType()->getAs<clang::FunctionProtoType>();
10791079
auto fn_type = GetFnTypeString(target_proto);
1080-
StrCat(std::format("{}.cast::<{}>().expect(\"ub:wrong fn type\")",
1080+
StrCat(std::format("{}.cast_fn::<{}>().expect(\"ub:wrong fn type\")",
10811081
ToString(expr->getSubExpr()), fn_type));
10821082
} else {
10831083
assert(0 && "Unhandled function pointer cast");
@@ -1614,10 +1614,10 @@ void ConverterRefCount::ConvertVarInit(clang::QualType qual_type,
16141614
Buffer buf(*this);
16151615
PushConversionKind push(*this, ConversionKind::Unboxed);
16161616
if (qual_type->isFunctionPointerType() && lambda->capture_size() == 0) {
1617-
StrCat(std::format("Ptr::from_fn(("));
1617+
StrCat("fn_ptr_anon!((");
16181618
VisitLambdaExpr(lambda);
16191619
StrCat(std::format(
1620-
") as {}, 0)",
1620+
"), {})",
16211621
GetFnTypeString(qual_type->getPointeeType()
16221622
->getAs<clang::FunctionProtoType>())));
16231623
} else {

libcc2rs/src/fn_ptr.rs

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
// Copyright (c) 2022-present INESC-ID.
2+
// Distributed under the MIT license that can be found in the LICENSE file.
3+
4+
use std::any::{Any, TypeId};
5+
use std::marker::PhantomData;
6+
use std::rc::Rc;
7+
8+
use crate::rc::{AnyPtr, ErasedPtr};
9+
use crate::reinterpret::ByteRepr;
10+
11+
#[derive(Clone)]
12+
pub(crate) struct FnState {
13+
addr: usize,
14+
cast_history: Vec<Option<Rc<dyn Any>>>,
15+
}
16+
17+
pub struct FnPtr<T> {
18+
state: Option<Rc<FnState>>,
19+
// FnPtr does not use T, hence wrap in PhantomData
20+
_marker: PhantomData<T>,
21+
}
22+
23+
impl<T> FnPtr<T> {
24+
#[inline]
25+
pub fn null() -> Self {
26+
FnPtr {
27+
state: None,
28+
_marker: PhantomData,
29+
}
30+
}
31+
32+
#[inline]
33+
pub fn is_null(&self) -> bool {
34+
self.state.is_none()
35+
}
36+
}
37+
38+
impl<T: 'static> FnPtr<T> {
39+
pub fn new(f: T, addr: usize) -> Self {
40+
FnPtr {
41+
state: Some(Rc::new(FnState {
42+
addr,
43+
cast_history: vec![Some(Rc::new(f))],
44+
})),
45+
_marker: PhantomData,
46+
}
47+
}
48+
49+
pub fn cast<U: 'static>(&self, adapter: Option<U>) -> FnPtr<U> {
50+
let state = self.state.as_ref().expect("ub: null fn pointer cast");
51+
52+
for (i, entry) in state.cast_history.iter().enumerate() {
53+
if let Some(ref rc) = entry {
54+
if (*rc).as_ref().type_id() == TypeId::of::<U>() {
55+
return FnPtr {
56+
state: Some(Rc::new(FnState {
57+
addr: state.addr,
58+
cast_history: state.cast_history[..=i].to_vec(),
59+
})),
60+
_marker: PhantomData,
61+
};
62+
}
63+
}
64+
}
65+
66+
let mut new_stack = state.cast_history.clone();
67+
new_stack.push(adapter.map(|a| Rc::new(a) as Rc<dyn Any>));
68+
69+
FnPtr {
70+
state: Some(Rc::new(FnState {
71+
addr: state.addr,
72+
cast_history: new_stack,
73+
})),
74+
_marker: PhantomData,
75+
}
76+
}
77+
78+
pub fn call(&self) -> T
79+
where
80+
T: Copy,
81+
{
82+
let state = self.state.as_ref().expect("ub: null fn pointer call");
83+
let entry = state
84+
.cast_history
85+
.last()
86+
.expect("empty fn pointer cast_history");
87+
match entry {
88+
Some(rc) => *rc
89+
.downcast_ref::<T>()
90+
.expect("ub: fn pointer type mismatch"),
91+
None => panic!("ub: calling through incompatible fn pointer type"),
92+
}
93+
}
94+
}
95+
96+
impl<T> Clone for FnPtr<T> {
97+
fn clone(&self) -> Self {
98+
FnPtr {
99+
state: self.state.clone(),
100+
_marker: PhantomData,
101+
}
102+
}
103+
}
104+
105+
impl<T> Default for FnPtr<T> {
106+
fn default() -> Self {
107+
Self::null()
108+
}
109+
}
110+
111+
impl<T> PartialEq for FnPtr<T> {
112+
fn eq(&self, other: &Self) -> bool {
113+
match (&self.state, &other.state) {
114+
(None, None) => true,
115+
(Some(a), Some(b)) => a.addr == b.addr,
116+
_ => false,
117+
}
118+
}
119+
}
120+
121+
impl<T> Eq for FnPtr<T> {}
122+
123+
impl<T> std::fmt::Debug for FnPtr<T> {
124+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
125+
match &self.state {
126+
None => write!(f, "FnPtr(null)"),
127+
Some(s) => write!(f, "FnPtr(0x{:x})", s.addr),
128+
}
129+
}
130+
}
131+
132+
impl<T: 'static> ByteRepr for FnPtr<T> {}
133+
134+
impl<T: 'static> ErasedPtr for FnPtr<T> {
135+
fn pointee_type_id(&self) -> TypeId {
136+
TypeId::of::<T>()
137+
}
138+
fn memcpy(&self, _src: &dyn ErasedPtr, _len: usize) {
139+
panic!("memcpy not supported on fn pointer");
140+
}
141+
fn as_any(&self) -> &dyn Any {
142+
self
143+
}
144+
fn equals(&self, other: &dyn ErasedPtr) -> Option<bool> {
145+
if self.pointee_type_id() != other.pointee_type_id() {
146+
return None;
147+
}
148+
other.as_any().downcast_ref::<FnPtr<T>>().map(|o| self == o)
149+
}
150+
}
151+
152+
impl<T: 'static> FnPtr<T> {
153+
pub fn to_any(&self) -> AnyPtr {
154+
AnyPtr {
155+
ptr: Rc::new(self.clone()),
156+
}
157+
}
158+
}
159+
160+
impl AnyPtr {
161+
pub fn cast_fn<T: 'static>(&self) -> Option<FnPtr<T>> {
162+
self.ptr.as_any().downcast_ref::<FnPtr<T>>().cloned()
163+
}
164+
}

libcc2rs/src/lib.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,25 @@ pub use reinterpret::ByteRepr;
77
#[macro_export]
88
macro_rules! fn_ptr {
99
($f:expr, $ty:ty) => {
10-
$crate::Ptr::from_fn($f as $ty, $f as *const () as usize)
10+
$crate::FnPtr::new($f as $ty, $f as *const () as usize)
11+
};
12+
}
13+
14+
// Lambda: no stable address, use 0. TODO: assign unique addr per lambda site so distinct
15+
// lambdas don't compare equal.
16+
#[macro_export]
17+
macro_rules! fn_ptr_anon {
18+
($f:expr, $ty:ty) => {
19+
$crate::FnPtr::new($f as $ty, 0)
1120
};
1221
}
1322

1423
mod rc;
1524
pub use rc::*;
1625

26+
mod fn_ptr;
27+
pub use fn_ptr::FnPtr;
28+
1729
mod inc;
1830
pub use inc::*;
1931

0 commit comments

Comments
 (0)