proc_macro: don't pass a client-side function pointer through the server.
This commit is contained in:
parent
56fd680cf9
commit
78a83b0d5f
8 changed files with 217 additions and 134 deletions
|
@ -294,50 +294,57 @@ fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> P<ast::Item> {
|
||||||
// that we generate expressions. The position of each NodeId
|
// that we generate expressions. The position of each NodeId
|
||||||
// in the 'proc_macros' Vec corresponds to its position
|
// in the 'proc_macros' Vec corresponds to its position
|
||||||
// in the static array that will be generated
|
// in the static array that will be generated
|
||||||
let decls = {
|
let decls = macros
|
||||||
let local_path = |cx: &ExtCtxt<'_>, sp: Span, name| {
|
.iter()
|
||||||
cx.expr_path(cx.path(sp.with_ctxt(span.ctxt()), vec![name]))
|
.map(|m| {
|
||||||
};
|
let harness_span = span;
|
||||||
let proc_macro_ty_method_path = |cx: &ExtCtxt<'_>, method| {
|
let span = match m {
|
||||||
cx.expr_path(cx.path(span, vec![proc_macro, bridge, client, proc_macro_ty, method]))
|
ProcMacro::Derive(m) => m.span,
|
||||||
};
|
ProcMacro::Attr(m) | ProcMacro::Bang(m) => m.span,
|
||||||
let attr_or_bang = |cx: &mut ExtCtxt<'_>, ca: &ProcMacroDef, ident| {
|
};
|
||||||
cx.resolver.declare_proc_macro(ca.id);
|
let local_path = |cx: &ExtCtxt<'_>, name| cx.expr_path(cx.path(span, vec![name]));
|
||||||
cx.expr_call(
|
let proc_macro_ty_method_path = |cx: &ExtCtxt<'_>, method| {
|
||||||
span,
|
cx.expr_path(cx.path(
|
||||||
proc_macro_ty_method_path(cx, ident),
|
span.with_ctxt(harness_span.ctxt()),
|
||||||
vec![
|
vec![proc_macro, bridge, client, proc_macro_ty, method],
|
||||||
cx.expr_str(ca.span, ca.function_name.name),
|
))
|
||||||
local_path(cx, ca.span, ca.function_name),
|
};
|
||||||
],
|
match m {
|
||||||
)
|
|
||||||
};
|
|
||||||
macros
|
|
||||||
.iter()
|
|
||||||
.map(|m| match m {
|
|
||||||
ProcMacro::Derive(cd) => {
|
ProcMacro::Derive(cd) => {
|
||||||
cx.resolver.declare_proc_macro(cd.id);
|
cx.resolver.declare_proc_macro(cd.id);
|
||||||
cx.expr_call(
|
cx.expr_call(
|
||||||
span,
|
span,
|
||||||
proc_macro_ty_method_path(cx, custom_derive),
|
proc_macro_ty_method_path(cx, custom_derive),
|
||||||
vec![
|
vec![
|
||||||
cx.expr_str(cd.span, cd.trait_name),
|
cx.expr_str(span, cd.trait_name),
|
||||||
cx.expr_vec_slice(
|
cx.expr_vec_slice(
|
||||||
span,
|
span,
|
||||||
cd.attrs
|
cd.attrs.iter().map(|&s| cx.expr_str(span, s)).collect::<Vec<_>>(),
|
||||||
.iter()
|
|
||||||
.map(|&s| cx.expr_str(cd.span, s))
|
|
||||||
.collect::<Vec<_>>(),
|
|
||||||
),
|
),
|
||||||
local_path(cx, cd.span, cd.function_name),
|
local_path(cx, cd.function_name),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
ProcMacro::Attr(ca) => attr_or_bang(cx, &ca, attr),
|
ProcMacro::Attr(ca) | ProcMacro::Bang(ca) => {
|
||||||
ProcMacro::Bang(ca) => attr_or_bang(cx, &ca, bang),
|
cx.resolver.declare_proc_macro(ca.id);
|
||||||
})
|
let ident = match m {
|
||||||
.collect()
|
ProcMacro::Attr(_) => attr,
|
||||||
};
|
ProcMacro::Bang(_) => bang,
|
||||||
|
ProcMacro::Derive(_) => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
cx.expr_call(
|
||||||
|
span,
|
||||||
|
proc_macro_ty_method_path(cx, ident),
|
||||||
|
vec![
|
||||||
|
cx.expr_str(span, ca.function_name.name),
|
||||||
|
local_path(cx, ca.function_name),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
let decls_static = cx
|
let decls_static = cx
|
||||||
.item_static(
|
.item_static(
|
||||||
|
|
|
@ -14,7 +14,7 @@ use rustc_span::{Span, DUMMY_SP};
|
||||||
const EXEC_STRATEGY: pm::bridge::server::SameThread = pm::bridge::server::SameThread;
|
const EXEC_STRATEGY: pm::bridge::server::SameThread = pm::bridge::server::SameThread;
|
||||||
|
|
||||||
pub struct BangProcMacro {
|
pub struct BangProcMacro {
|
||||||
pub client: pm::bridge::client::Client<fn(pm::TokenStream) -> pm::TokenStream>,
|
pub client: pm::bridge::client::Client<pm::TokenStream, pm::TokenStream>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl base::BangProcMacro for BangProcMacro {
|
impl base::BangProcMacro for BangProcMacro {
|
||||||
|
@ -42,7 +42,7 @@ impl base::BangProcMacro for BangProcMacro {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct AttrProcMacro {
|
pub struct AttrProcMacro {
|
||||||
pub client: pm::bridge::client::Client<fn(pm::TokenStream, pm::TokenStream) -> pm::TokenStream>,
|
pub client: pm::bridge::client::Client<(pm::TokenStream, pm::TokenStream), pm::TokenStream>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl base::AttrProcMacro for AttrProcMacro {
|
impl base::AttrProcMacro for AttrProcMacro {
|
||||||
|
@ -73,7 +73,7 @@ impl base::AttrProcMacro for AttrProcMacro {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct DeriveProcMacro {
|
pub struct DeriveProcMacro {
|
||||||
pub client: pm::bridge::client::Client<fn(pm::TokenStream) -> pm::TokenStream>,
|
pub client: pm::bridge::client::Client<pm::TokenStream, pm::TokenStream>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MultiItemModifier for DeriveProcMacro {
|
impl MultiItemModifier for DeriveProcMacro {
|
||||||
|
|
|
@ -357,22 +357,33 @@ impl Bridge<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A client-side "global object" (usually a function pointer),
|
/// A client-side RPC entry-point, which may be using a different `proc_macro`
|
||||||
/// which may be using a different `proc_macro` from the one
|
/// from the one used by the server, but can be invoked compatibly.
|
||||||
/// used by the server, but can be interacted with compatibly.
|
|
||||||
///
|
///
|
||||||
/// N.B., `F` must have FFI-friendly memory layout (e.g., a pointer).
|
/// Note that the (phantom) `I` ("input") and `O` ("output") type parameters
|
||||||
/// The call ABI of function pointers used for `F` doesn't
|
/// decorate the `Client<I, O>` with the RPC "interface" of the entry-point, but
|
||||||
/// need to match between server and client, since it's only
|
/// do not themselves participate in ABI, at all, only facilitate type-checking.
|
||||||
/// passed between them and (eventually) called by the client.
|
///
|
||||||
|
/// E.g. `Client<TokenStream, TokenStream>` is the common proc macro interface,
|
||||||
|
/// used for `#[proc_macro] fn foo(input: TokenStream) -> TokenStream`,
|
||||||
|
/// indicating that the RPC input and output will be serialized token streams,
|
||||||
|
/// and forcing the use of APIs that take/return `S::TokenStream`, server-side.
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Copy, Clone)]
|
pub struct Client<I, O> {
|
||||||
pub struct Client<F> {
|
|
||||||
// FIXME(eddyb) use a reference to the `static COUNTERS`, instead of
|
// FIXME(eddyb) use a reference to the `static COUNTERS`, instead of
|
||||||
// a wrapper `fn` pointer, once `const fn` can reference `static`s.
|
// a wrapper `fn` pointer, once `const fn` can reference `static`s.
|
||||||
pub(super) get_handle_counters: extern "C" fn() -> &'static HandleCounters,
|
pub(super) get_handle_counters: extern "C" fn() -> &'static HandleCounters,
|
||||||
pub(super) run: extern "C" fn(Bridge<'_>, F) -> Buffer,
|
|
||||||
pub(super) f: F,
|
pub(super) run: extern "C" fn(Bridge<'_>) -> Buffer,
|
||||||
|
|
||||||
|
pub(super) _marker: PhantomData<fn(I) -> O>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I, O> Copy for Client<I, O> {}
|
||||||
|
impl<I, O> Clone for Client<I, O> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
*self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Client-side helper for handling client panics, entering the bridge,
|
/// Client-side helper for handling client panics, entering the bridge,
|
||||||
|
@ -419,31 +430,31 @@ fn run_client<A: for<'a, 's> DecodeMut<'a, 's, ()>, R: Encode<()>>(
|
||||||
buf
|
buf
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Client<fn(crate::TokenStream) -> crate::TokenStream> {
|
impl Client<crate::TokenStream, crate::TokenStream> {
|
||||||
pub const fn expand1(f: fn(crate::TokenStream) -> crate::TokenStream) -> Self {
|
pub const fn expand1(f: impl Fn(crate::TokenStream) -> crate::TokenStream + Copy) -> Self {
|
||||||
extern "C" fn run(
|
Client {
|
||||||
bridge: Bridge<'_>,
|
get_handle_counters: HandleCounters::get,
|
||||||
f: impl FnOnce(crate::TokenStream) -> crate::TokenStream,
|
run: super::selfless_reify::reify_to_extern_c_fn_hrt_bridge(move |bridge| {
|
||||||
) -> Buffer {
|
run_client(bridge, |input| f(crate::TokenStream(input)).0)
|
||||||
run_client(bridge, |input| f(crate::TokenStream(input)).0)
|
}),
|
||||||
|
_marker: PhantomData,
|
||||||
}
|
}
|
||||||
Client { get_handle_counters: HandleCounters::get, run, f }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Client<fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream> {
|
impl Client<(crate::TokenStream, crate::TokenStream), crate::TokenStream> {
|
||||||
pub const fn expand2(
|
pub const fn expand2(
|
||||||
f: fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream,
|
f: impl Fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream + Copy,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
extern "C" fn run(
|
Client {
|
||||||
bridge: Bridge<'_>,
|
get_handle_counters: HandleCounters::get,
|
||||||
f: impl FnOnce(crate::TokenStream, crate::TokenStream) -> crate::TokenStream,
|
run: super::selfless_reify::reify_to_extern_c_fn_hrt_bridge(move |bridge| {
|
||||||
) -> Buffer {
|
run_client(bridge, |(input, input2)| {
|
||||||
run_client(bridge, |(input, input2)| {
|
f(crate::TokenStream(input), crate::TokenStream(input2)).0
|
||||||
f(crate::TokenStream(input), crate::TokenStream(input2)).0
|
})
|
||||||
})
|
}),
|
||||||
|
_marker: PhantomData,
|
||||||
}
|
}
|
||||||
Client { get_handle_counters: HandleCounters::get, run, f }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -453,17 +464,17 @@ pub enum ProcMacro {
|
||||||
CustomDerive {
|
CustomDerive {
|
||||||
trait_name: &'static str,
|
trait_name: &'static str,
|
||||||
attributes: &'static [&'static str],
|
attributes: &'static [&'static str],
|
||||||
client: Client<fn(crate::TokenStream) -> crate::TokenStream>,
|
client: Client<crate::TokenStream, crate::TokenStream>,
|
||||||
},
|
},
|
||||||
|
|
||||||
Attr {
|
Attr {
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
client: Client<fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream>,
|
client: Client<(crate::TokenStream, crate::TokenStream), crate::TokenStream>,
|
||||||
},
|
},
|
||||||
|
|
||||||
Bang {
|
Bang {
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
client: Client<fn(crate::TokenStream) -> crate::TokenStream>,
|
client: Client<crate::TokenStream, crate::TokenStream>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -479,21 +490,21 @@ impl ProcMacro {
|
||||||
pub const fn custom_derive(
|
pub const fn custom_derive(
|
||||||
trait_name: &'static str,
|
trait_name: &'static str,
|
||||||
attributes: &'static [&'static str],
|
attributes: &'static [&'static str],
|
||||||
expand: fn(crate::TokenStream) -> crate::TokenStream,
|
expand: impl Fn(crate::TokenStream) -> crate::TokenStream + Copy,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
ProcMacro::CustomDerive { trait_name, attributes, client: Client::expand1(expand) }
|
ProcMacro::CustomDerive { trait_name, attributes, client: Client::expand1(expand) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn attr(
|
pub const fn attr(
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
expand: fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream,
|
expand: impl Fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream + Copy,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
ProcMacro::Attr { name, client: Client::expand2(expand) }
|
ProcMacro::Attr { name, client: Client::expand2(expand) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn bang(
|
pub const fn bang(
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
expand: fn(crate::TokenStream) -> crate::TokenStream,
|
expand: impl Fn(crate::TokenStream) -> crate::TokenStream + Copy,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
ProcMacro::Bang { name, client: Client::expand1(expand) }
|
ProcMacro::Bang { name, client: Client::expand1(expand) }
|
||||||
}
|
}
|
||||||
|
|
|
@ -208,6 +208,8 @@ mod handle;
|
||||||
mod rpc;
|
mod rpc;
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
mod scoped_cell;
|
mod scoped_cell;
|
||||||
|
#[allow(unsafe_code)]
|
||||||
|
mod selfless_reify;
|
||||||
#[forbid(unsafe_code)]
|
#[forbid(unsafe_code)]
|
||||||
pub mod server;
|
pub mod server;
|
||||||
|
|
||||||
|
|
83
library/proc_macro/src/bridge/selfless_reify.rs
Normal file
83
library/proc_macro/src/bridge/selfless_reify.rs
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
//! Abstraction for creating `fn` pointers from any callable that *effectively*
|
||||||
|
//! has the equivalent of implementing `Default`, even if the compiler neither
|
||||||
|
//! provides `Default` nor allows reifying closures (i.e. creating `fn` pointers)
|
||||||
|
//! other than those with absolutely no captures.
|
||||||
|
//!
|
||||||
|
//! More specifically, for a closure-like type to be "effectively `Default`":
|
||||||
|
//! * it must be a ZST (zero-sized type): no information contained within, so
|
||||||
|
//! that `Default`'s return value (if it were implemented) is unambiguous
|
||||||
|
//! * it must be `Copy`: no captured "unique ZST tokens" or any other similar
|
||||||
|
//! types that would make duplicating values at will unsound
|
||||||
|
//! * combined with the ZST requirement, this confers a kind of "telecopy"
|
||||||
|
//! ability: similar to `Copy`, but without keeping the value around, and
|
||||||
|
//! instead "reconstructing" it (a noop given it's a ZST) when needed
|
||||||
|
//! * it must be *provably* inhabited: no captured uninhabited types or any
|
||||||
|
//! other types that cannot be constructed by the user of this abstraction
|
||||||
|
//! * the proof is a value of the closure-like type itself, in a sense the
|
||||||
|
//! "seed" for the "telecopy" process made possible by ZST + `Copy`
|
||||||
|
//! * this requirement is the only reason an abstraction limited to a specific
|
||||||
|
//! usecase is required: ZST + `Copy` can be checked with *at worst* a panic
|
||||||
|
//! at the "attempted `::default()` call" time, but that doesn't guarantee
|
||||||
|
//! that the value can be soundly created, and attempting to use the typical
|
||||||
|
//! "proof ZST token" approach leads yet again to having a ZST + `Copy` type
|
||||||
|
//! that is not proof of anything without a value (i.e. isomorphic to a
|
||||||
|
//! newtype of the type it's trying to prove the inhabitation of)
|
||||||
|
//!
|
||||||
|
//! A more flexible (and safer) solution to the general problem could exist once
|
||||||
|
//! `const`-generic parameters can have type parameters in their types:
|
||||||
|
//!
|
||||||
|
//! ```rust,ignore (needs future const-generics)
|
||||||
|
//! extern "C" fn ffi_wrapper<
|
||||||
|
//! A, R,
|
||||||
|
//! F: Fn(A) -> R,
|
||||||
|
//! const f: F, // <-- this `const`-generic is not yet allowed
|
||||||
|
//! >(arg: A) -> R {
|
||||||
|
//! f(arg)
|
||||||
|
//! }
|
||||||
|
//! ```
|
||||||
|
|
||||||
|
use std::mem;
|
||||||
|
|
||||||
|
// FIXME(eddyb) this could be `trait` impls except for the `const fn` requirement.
|
||||||
|
macro_rules! define_reify_functions {
|
||||||
|
($(
|
||||||
|
fn $name:ident $(<$($param:ident),*>)?
|
||||||
|
for $(extern $abi:tt)? fn($($arg:ident: $arg_ty:ty),*) -> $ret_ty:ty;
|
||||||
|
)+) => {
|
||||||
|
$(pub const fn $name<
|
||||||
|
$($($param,)*)?
|
||||||
|
F: Fn($($arg_ty),*) -> $ret_ty + Copy
|
||||||
|
>(f: F) -> $(extern $abi)? fn($($arg_ty),*) -> $ret_ty {
|
||||||
|
// FIXME(eddyb) describe the `F` type (e.g. via `type_name::<F>`) once panic
|
||||||
|
// formatting becomes possible in `const fn`.
|
||||||
|
assert!(mem::size_of::<F>() == 0, "selfless_reify: closure must be zero-sized");
|
||||||
|
|
||||||
|
$(extern $abi)? fn wrapper<
|
||||||
|
$($($param,)*)?
|
||||||
|
F: Fn($($arg_ty),*) -> $ret_ty + Copy
|
||||||
|
>($($arg: $arg_ty),*) -> $ret_ty {
|
||||||
|
let f = unsafe {
|
||||||
|
// SAFETY: `F` satisfies all criteria for "out of thin air"
|
||||||
|
// reconstructability (see module-level doc comment).
|
||||||
|
mem::MaybeUninit::<F>::uninit().assume_init()
|
||||||
|
};
|
||||||
|
f($($arg),*)
|
||||||
|
}
|
||||||
|
let _f_proof = f;
|
||||||
|
wrapper::<
|
||||||
|
$($($param,)*)?
|
||||||
|
F
|
||||||
|
>
|
||||||
|
})+
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
define_reify_functions! {
|
||||||
|
fn _reify_to_extern_c_fn_unary<A, R> for extern "C" fn(arg: A) -> R;
|
||||||
|
|
||||||
|
// HACK(eddyb) this abstraction is used with `for<'a> fn(Bridge<'a>) -> T`
|
||||||
|
// but that doesn't work with just `reify_to_extern_c_fn_unary` because of
|
||||||
|
// the `fn` pointer type being "higher-ranked" (i.e. the `for<'a>` binder).
|
||||||
|
// FIXME(eddyb) try to remove the lifetime from `Bridge`, that'd help.
|
||||||
|
fn reify_to_extern_c_fn_hrt_bridge<R> for extern "C" fn(bridge: super::Bridge<'_>) -> R;
|
||||||
|
}
|
|
@ -118,12 +118,11 @@ macro_rules! define_dispatcher_impl {
|
||||||
with_api!(Self, self_, define_dispatcher_impl);
|
with_api!(Self, self_, define_dispatcher_impl);
|
||||||
|
|
||||||
pub trait ExecutionStrategy {
|
pub trait ExecutionStrategy {
|
||||||
fn run_bridge_and_client<D: Copy + Send + 'static>(
|
fn run_bridge_and_client(
|
||||||
&self,
|
&self,
|
||||||
dispatcher: &mut impl DispatcherTrait,
|
dispatcher: &mut impl DispatcherTrait,
|
||||||
input: Buffer,
|
input: Buffer,
|
||||||
run_client: extern "C" fn(Bridge<'_>, D) -> Buffer,
|
run_client: extern "C" fn(Bridge<'_>) -> Buffer,
|
||||||
client_data: D,
|
|
||||||
force_show_panics: bool,
|
force_show_panics: bool,
|
||||||
) -> Buffer;
|
) -> Buffer;
|
||||||
}
|
}
|
||||||
|
@ -131,25 +130,21 @@ pub trait ExecutionStrategy {
|
||||||
pub struct SameThread;
|
pub struct SameThread;
|
||||||
|
|
||||||
impl ExecutionStrategy for SameThread {
|
impl ExecutionStrategy for SameThread {
|
||||||
fn run_bridge_and_client<D: Copy + Send + 'static>(
|
fn run_bridge_and_client(
|
||||||
&self,
|
&self,
|
||||||
dispatcher: &mut impl DispatcherTrait,
|
dispatcher: &mut impl DispatcherTrait,
|
||||||
input: Buffer,
|
input: Buffer,
|
||||||
run_client: extern "C" fn(Bridge<'_>, D) -> Buffer,
|
run_client: extern "C" fn(Bridge<'_>) -> Buffer,
|
||||||
client_data: D,
|
|
||||||
force_show_panics: bool,
|
force_show_panics: bool,
|
||||||
) -> Buffer {
|
) -> Buffer {
|
||||||
let mut dispatch = |buf| dispatcher.dispatch(buf);
|
let mut dispatch = |buf| dispatcher.dispatch(buf);
|
||||||
|
|
||||||
run_client(
|
run_client(Bridge {
|
||||||
Bridge {
|
cached_buffer: input,
|
||||||
cached_buffer: input,
|
dispatch: (&mut dispatch).into(),
|
||||||
dispatch: (&mut dispatch).into(),
|
force_show_panics,
|
||||||
force_show_panics,
|
_marker: marker::PhantomData,
|
||||||
_marker: marker::PhantomData,
|
})
|
||||||
},
|
|
||||||
client_data,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,12 +154,11 @@ impl ExecutionStrategy for SameThread {
|
||||||
pub struct CrossThread1;
|
pub struct CrossThread1;
|
||||||
|
|
||||||
impl ExecutionStrategy for CrossThread1 {
|
impl ExecutionStrategy for CrossThread1 {
|
||||||
fn run_bridge_and_client<D: Copy + Send + 'static>(
|
fn run_bridge_and_client(
|
||||||
&self,
|
&self,
|
||||||
dispatcher: &mut impl DispatcherTrait,
|
dispatcher: &mut impl DispatcherTrait,
|
||||||
input: Buffer,
|
input: Buffer,
|
||||||
run_client: extern "C" fn(Bridge<'_>, D) -> Buffer,
|
run_client: extern "C" fn(Bridge<'_>) -> Buffer,
|
||||||
client_data: D,
|
|
||||||
force_show_panics: bool,
|
force_show_panics: bool,
|
||||||
) -> Buffer {
|
) -> Buffer {
|
||||||
use std::sync::mpsc::channel;
|
use std::sync::mpsc::channel;
|
||||||
|
@ -178,15 +172,12 @@ impl ExecutionStrategy for CrossThread1 {
|
||||||
res_rx.recv().unwrap()
|
res_rx.recv().unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
run_client(
|
run_client(Bridge {
|
||||||
Bridge {
|
cached_buffer: input,
|
||||||
cached_buffer: input,
|
dispatch: (&mut dispatch).into(),
|
||||||
dispatch: (&mut dispatch).into(),
|
force_show_panics,
|
||||||
force_show_panics,
|
_marker: marker::PhantomData,
|
||||||
_marker: marker::PhantomData,
|
})
|
||||||
},
|
|
||||||
client_data,
|
|
||||||
)
|
|
||||||
});
|
});
|
||||||
|
|
||||||
for b in req_rx {
|
for b in req_rx {
|
||||||
|
@ -200,12 +191,11 @@ impl ExecutionStrategy for CrossThread1 {
|
||||||
pub struct CrossThread2;
|
pub struct CrossThread2;
|
||||||
|
|
||||||
impl ExecutionStrategy for CrossThread2 {
|
impl ExecutionStrategy for CrossThread2 {
|
||||||
fn run_bridge_and_client<D: Copy + Send + 'static>(
|
fn run_bridge_and_client(
|
||||||
&self,
|
&self,
|
||||||
dispatcher: &mut impl DispatcherTrait,
|
dispatcher: &mut impl DispatcherTrait,
|
||||||
input: Buffer,
|
input: Buffer,
|
||||||
run_client: extern "C" fn(Bridge<'_>, D) -> Buffer,
|
run_client: extern "C" fn(Bridge<'_>) -> Buffer,
|
||||||
client_data: D,
|
|
||||||
force_show_panics: bool,
|
force_show_panics: bool,
|
||||||
) -> Buffer {
|
) -> Buffer {
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
@ -231,15 +221,12 @@ impl ExecutionStrategy for CrossThread2 {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let r = run_client(
|
let r = run_client(Bridge {
|
||||||
Bridge {
|
cached_buffer: input,
|
||||||
cached_buffer: input,
|
dispatch: (&mut dispatch).into(),
|
||||||
dispatch: (&mut dispatch).into(),
|
force_show_panics,
|
||||||
force_show_panics,
|
_marker: marker::PhantomData,
|
||||||
_marker: marker::PhantomData,
|
});
|
||||||
},
|
|
||||||
client_data,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Wake up the server so it can exit the dispatch loop.
|
// Wake up the server so it can exit the dispatch loop.
|
||||||
drop(state2);
|
drop(state2);
|
||||||
|
@ -268,14 +255,12 @@ fn run_server<
|
||||||
S: Server,
|
S: Server,
|
||||||
I: Encode<HandleStore<MarkedTypes<S>>>,
|
I: Encode<HandleStore<MarkedTypes<S>>>,
|
||||||
O: for<'a, 's> DecodeMut<'a, 's, HandleStore<MarkedTypes<S>>>,
|
O: for<'a, 's> DecodeMut<'a, 's, HandleStore<MarkedTypes<S>>>,
|
||||||
D: Copy + Send + 'static,
|
|
||||||
>(
|
>(
|
||||||
strategy: &impl ExecutionStrategy,
|
strategy: &impl ExecutionStrategy,
|
||||||
handle_counters: &'static client::HandleCounters,
|
handle_counters: &'static client::HandleCounters,
|
||||||
server: S,
|
server: S,
|
||||||
input: I,
|
input: I,
|
||||||
run_client: extern "C" fn(Bridge<'_>, D) -> Buffer,
|
run_client: extern "C" fn(Bridge<'_>) -> Buffer,
|
||||||
client_data: D,
|
|
||||||
force_show_panics: bool,
|
force_show_panics: bool,
|
||||||
) -> Result<O, PanicMessage> {
|
) -> Result<O, PanicMessage> {
|
||||||
let mut dispatcher =
|
let mut dispatcher =
|
||||||
|
@ -284,18 +269,12 @@ fn run_server<
|
||||||
let mut buf = Buffer::new();
|
let mut buf = Buffer::new();
|
||||||
input.encode(&mut buf, &mut dispatcher.handle_store);
|
input.encode(&mut buf, &mut dispatcher.handle_store);
|
||||||
|
|
||||||
buf = strategy.run_bridge_and_client(
|
buf = strategy.run_bridge_and_client(&mut dispatcher, buf, run_client, force_show_panics);
|
||||||
&mut dispatcher,
|
|
||||||
buf,
|
|
||||||
run_client,
|
|
||||||
client_data,
|
|
||||||
force_show_panics,
|
|
||||||
);
|
|
||||||
|
|
||||||
Result::decode(&mut &buf[..], &mut dispatcher.handle_store)
|
Result::decode(&mut &buf[..], &mut dispatcher.handle_store)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl client::Client<fn(crate::TokenStream) -> crate::TokenStream> {
|
impl client::Client<crate::TokenStream, crate::TokenStream> {
|
||||||
pub fn run<S: Server>(
|
pub fn run<S: Server>(
|
||||||
&self,
|
&self,
|
||||||
strategy: &impl ExecutionStrategy,
|
strategy: &impl ExecutionStrategy,
|
||||||
|
@ -303,21 +282,20 @@ impl client::Client<fn(crate::TokenStream) -> crate::TokenStream> {
|
||||||
input: S::TokenStream,
|
input: S::TokenStream,
|
||||||
force_show_panics: bool,
|
force_show_panics: bool,
|
||||||
) -> Result<S::TokenStream, PanicMessage> {
|
) -> Result<S::TokenStream, PanicMessage> {
|
||||||
let client::Client { get_handle_counters, run, f } = *self;
|
let client::Client { get_handle_counters, run, _marker } = *self;
|
||||||
run_server(
|
run_server(
|
||||||
strategy,
|
strategy,
|
||||||
get_handle_counters(),
|
get_handle_counters(),
|
||||||
server,
|
server,
|
||||||
<MarkedTypes<S> as Types>::TokenStream::mark(input),
|
<MarkedTypes<S> as Types>::TokenStream::mark(input),
|
||||||
run,
|
run,
|
||||||
f,
|
|
||||||
force_show_panics,
|
force_show_panics,
|
||||||
)
|
)
|
||||||
.map(<MarkedTypes<S> as Types>::TokenStream::unmark)
|
.map(<MarkedTypes<S> as Types>::TokenStream::unmark)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl client::Client<fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream> {
|
impl client::Client<(crate::TokenStream, crate::TokenStream), crate::TokenStream> {
|
||||||
pub fn run<S: Server>(
|
pub fn run<S: Server>(
|
||||||
&self,
|
&self,
|
||||||
strategy: &impl ExecutionStrategy,
|
strategy: &impl ExecutionStrategy,
|
||||||
|
@ -326,7 +304,7 @@ impl client::Client<fn(crate::TokenStream, crate::TokenStream) -> crate::TokenSt
|
||||||
input2: S::TokenStream,
|
input2: S::TokenStream,
|
||||||
force_show_panics: bool,
|
force_show_panics: bool,
|
||||||
) -> Result<S::TokenStream, PanicMessage> {
|
) -> Result<S::TokenStream, PanicMessage> {
|
||||||
let client::Client { get_handle_counters, run, f } = *self;
|
let client::Client { get_handle_counters, run, _marker } = *self;
|
||||||
run_server(
|
run_server(
|
||||||
strategy,
|
strategy,
|
||||||
get_handle_counters(),
|
get_handle_counters(),
|
||||||
|
@ -336,7 +314,6 @@ impl client::Client<fn(crate::TokenStream, crate::TokenStream) -> crate::TokenSt
|
||||||
<MarkedTypes<S> as Types>::TokenStream::mark(input2),
|
<MarkedTypes<S> as Types>::TokenStream::mark(input2),
|
||||||
),
|
),
|
||||||
run,
|
run,
|
||||||
f,
|
|
||||||
force_show_panics,
|
force_show_panics,
|
||||||
)
|
)
|
||||||
.map(<MarkedTypes<S> as Types>::TokenStream::unmark)
|
.map(<MarkedTypes<S> as Types>::TokenStream::unmark)
|
||||||
|
|
|
@ -8,6 +8,6 @@ extern crate proc_macro;
|
||||||
|
|
||||||
#[proc_macro_derive(A)]
|
#[proc_macro_derive(A)]
|
||||||
pub unsafe extern "C" fn foo(a: i32, b: u32) -> u32 {
|
pub unsafe extern "C" fn foo(a: i32, b: u32) -> u32 {
|
||||||
//~^ ERROR: mismatched types
|
//~^ ERROR: expected a `Fn<(proc_macro::TokenStream,)>` closure, found `unsafe extern "C" fn
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,20 +1,23 @@
|
||||||
error[E0308]: mismatched types
|
error[E0277]: expected a `Fn<(proc_macro::TokenStream,)>` closure, found `unsafe extern "C" fn(i32, u32) -> u32 {foo}`
|
||||||
--> $DIR/signature.rs:10:1
|
--> $DIR/signature.rs:10:1
|
||||||
|
|
|
|
||||||
LL | / pub unsafe extern "C" fn foo(a: i32, b: u32) -> u32 {
|
LL | / pub unsafe extern "C" fn foo(a: i32, b: u32) -> u32 {
|
||||||
LL | |
|
LL | |
|
||||||
LL | | loop {}
|
LL | | loop {}
|
||||||
LL | | }
|
LL | | }
|
||||||
| |_^ expected normal fn, found unsafe fn
|
| | ^
|
||||||
|
| | |
|
||||||
|
| |_call the function in a closure: `|| unsafe { /* code */ }`
|
||||||
|
| required by a bound introduced by this call
|
||||||
|
|
|
|
||||||
= note: expected fn pointer `fn(proc_macro::TokenStream) -> proc_macro::TokenStream`
|
= help: the trait `Fn<(proc_macro::TokenStream,)>` is not implemented for `unsafe extern "C" fn(i32, u32) -> u32 {foo}`
|
||||||
found fn item `unsafe extern "C" fn(i32, u32) -> u32 {foo}`
|
= note: unsafe function cannot be called generically without an unsafe block
|
||||||
note: associated function defined here
|
note: required by a bound in `ProcMacro::custom_derive`
|
||||||
--> $SRC_DIR/proc_macro/src/bridge/client.rs:LL:COL
|
--> $SRC_DIR/proc_macro/src/bridge/client.rs:LL:COL
|
||||||
|
|
|
|
||||||
LL | pub const fn custom_derive(
|
LL | expand: impl Fn(crate::TokenStream) -> crate::TokenStream + Copy,
|
||||||
| ^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `ProcMacro::custom_derive`
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0308`.
|
For more information about this error, try `rustc --explain E0277`.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue