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
2 changes: 1 addition & 1 deletion cpp2rust/converter/converter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4340,8 +4340,8 @@ Converter::GetStructAttributes(const clang::RecordDecl *decl) {

if (RecordImplementsClone(decl)) {
struct_attrs.emplace_back("VaArg");
struct_attrs.emplace_back("FnPtrArg");
}
struct_attrs.emplace_back("FnPtrArg");

if (RecordDerivesDefault(decl)) {
struct_attrs.emplace_back("Default");
Expand Down
2 changes: 1 addition & 1 deletion cpp2rust/converter/models/converter_refcount.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2579,8 +2579,8 @@ ConverterRefCount::GetStructAttributes(const clang::RecordDecl *decl) {

if (RecordImplementsClone(decl)) {
attrs.emplace_back("VaArg");
attrs.emplace_back("FnPtrArg");
}
attrs.emplace_back("FnPtrArg");

if (RecordDerivesDefault(decl)) {
attrs.emplace_back("Default");
Expand Down
2 changes: 1 addition & 1 deletion cpp2rust/converter/printer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ std::string ToRustName(std::string name) {

std::string_view stem(name);
stem = stem.substr(0, stem.find_last_not_of('_') + 1);
if (stem == "Ptr" || stem == "Value") {
if (stem == "Ptr" || stem == "Value" || stem == "Box") {
name += '_';
}
return name;
Expand Down
10 changes: 6 additions & 4 deletions docs/src/runtime/fn-ptr.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,12 @@ The code generator can build an adapter when the arguments and return type of
the two function types have the same representation. Otherwise it passes `None`,
and calling through the cast pointer panics with `ub:`.

A cast to a different type is the only operation that allocates: the pointer
then also keeps the function it was created with, type-erased, so that casting
back to that type can restore it. Equality compares the address of the function
the pointer was created with.
A cast to a different type allocates: the pointer then also keeps the function
it was created with, type-erased, so that casting back to that type can restore
it. A call through the adapter moves each pointer or record argument through a
heap cell, so a value without a copy constructor can be passed too; direct calls
never allocate. Equality compares the address of the function the pointer was
created with.

Casting a function pointer to `void *` is `to_any`, and `AnyPtr::cast_fn::<T>`
recovers it. `reinterpret_cast` on an `AnyPtr` holding a function currently
Expand Down
6 changes: 3 additions & 3 deletions libcc2rs-macros/src/fn_ptr_arg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ pub fn expand(input: TokenStream) -> TokenStream {
quote::quote! {
impl #impl_generics ::libcc2rs::FnPtrArg for #name #ty_generics #where_clause {
#[inline]
fn to_repr(&self) -> ::libcc2rs::ArgRepr<'_> {
::libcc2rs::ArgRepr::Record(self)
fn to_repr(self) -> ::libcc2rs::ArgRepr {
::libcc2rs::ArgRepr::Record(Box::new(self))
}
fn from_repr(r: &::libcc2rs::ArgRepr) -> Self {
fn from_repr(r: ::libcc2rs::ArgRepr) -> Self {
::libcc2rs::record_from_repr(r)
}
}
Expand Down
28 changes: 11 additions & 17 deletions libcc2rs/src/fn_ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ impl_fn_sig!();
// Build a trampoline adaptor for a function pointer of one type to be called
// through a different type.
trait Adapted: Any {
fn call_adapted(&self, args: ArgList<'_>, sink: &mut dyn FnMut(ArgRepr<'_>));
fn call_adapted(&self, args: ArgList) -> ArgRepr;

fn copy_from(&self) -> Option<Rc<dyn Adapted>> {
None
Expand All @@ -63,10 +63,9 @@ trait Adapted: Any {
}

impl<T: FnSig> Adapted for T {
fn call_adapted(&self, args: ArgList<'_>, sink: &mut dyn FnMut(ArgRepr<'_>)) {
let converted_args = T::Args::from_list(&args);
let result = self.call_direct(converted_args);
sink(result.to_repr());
fn call_adapted(&self, args: ArgList) -> ArgRepr {
let converted_args = T::Args::from_list(args);
self.call_direct(converted_args).to_repr()
}
}

Expand Down Expand Up @@ -96,10 +95,9 @@ struct LambdaUnsafe<L, C> {
struct Closure<T: FnSig>(Box<dyn Lambda<T>>);

impl<T: FnSig> Adapted for Closure<T> {
fn call_adapted(&self, args: ArgList<'_>, sink: &mut dyn FnMut(ArgRepr<'_>)) {
let converted_args = T::Args::from_list(&args);
let result = self.0.call(converted_args);
sink(result.to_repr());
fn call_adapted(&self, args: ArgList) -> ArgRepr {
let converted_args = T::Args::from_list(args);
self.0.call(converted_args).to_repr()
}

fn copy_from(&self) -> Option<Rc<dyn Adapted>> {
Expand Down Expand Up @@ -167,11 +165,7 @@ impl<T: FnSig> FnPtr<T> {
if let Some(closure) = closure.downcast_ref::<Closure<T>>() {
return closure.0.call(args);
}
let mut result = None;
original.call_adapted(args.to_list(), &mut |repr| {
result = Some(T::Ret::from_repr(&repr));
});
return result.expect("ub: calling through incompatible fn pointer type");
return T::Ret::from_repr(original.call_adapted(args.to_list()));
}
panic!("ub: calling through incompatible fn pointer type");
}
Expand Down Expand Up @@ -407,10 +401,10 @@ impl<T: FnSig> ByteRepr for FnPtr<T> {}

impl<T: FnSig> FnPtrArg for FnPtr<T> {
#[inline]
fn to_repr(&self) -> ArgRepr<'_> {
ArgRepr::Record(self)
fn to_repr(self) -> ArgRepr {
ArgRepr::Record(Box::new(self))
}
fn from_repr(r: &ArgRepr) -> Self {
fn from_repr(r: ArgRepr) -> Self {
record_from_repr(r)
}
}
Expand Down
Loading
Loading