Auto merge of #14063 - Veykril:proc-macro-abi-1-58, r=Veykril

feat: Remove support for 1.58 proc-macro abi

This seems old enough that we can drop the support for it now, the less ABIs we have the less work it is adjusting our span implementation.

Extracted from https://github.com/rust-lang/rust-analyzer/pull/14061, will rebase that over this once merged.
This commit is contained in:
bors 2023-01-31 11:17:29 +00:00
commit 577e839c0d
14 changed files with 0 additions and 4186 deletions

View file

@ -1,104 +0,0 @@
//! Macro ABI for version 1.58 of rustc
#[allow(dead_code)]
#[doc(hidden)]
mod proc_macro;
#[allow(dead_code)]
#[doc(hidden)]
mod ra_server;
use libloading::Library;
use proc_macro_api::ProcMacroKind;
use super::PanicMessage;
pub(crate) struct Abi {
exported_macros: Vec<proc_macro::bridge::client::ProcMacro>,
}
impl From<proc_macro::bridge::PanicMessage> for PanicMessage {
fn from(p: proc_macro::bridge::PanicMessage) -> Self {
Self { message: p.as_str().map(|s| s.to_string()) }
}
}
impl Abi {
pub unsafe fn from_lib(lib: &Library, symbol_name: String) -> Result<Abi, libloading::Error> {
let macros: libloading::Symbol<'_, &&[proc_macro::bridge::client::ProcMacro]> =
lib.get(symbol_name.as_bytes())?;
Ok(Self { exported_macros: macros.to_vec() })
}
pub fn expand(
&self,
macro_name: &str,
macro_body: &tt::Subtree,
attributes: Option<&tt::Subtree>,
) -> Result<tt::Subtree, PanicMessage> {
let parsed_body = ra_server::TokenStream::with_subtree(macro_body.clone());
let parsed_attributes = attributes.map_or(ra_server::TokenStream::new(), |attr| {
ra_server::TokenStream::with_subtree(attr.clone())
});
for proc_macro in &self.exported_macros {
match proc_macro {
proc_macro::bridge::client::ProcMacro::CustomDerive {
trait_name, client, ..
} if *trait_name == macro_name => {
let res = client.run(
&proc_macro::bridge::server::SameThread,
ra_server::RustAnalyzer::default(),
parsed_body,
true,
);
return res.map(|it| it.into_subtree()).map_err(PanicMessage::from);
}
proc_macro::bridge::client::ProcMacro::Bang { name, client }
if *name == macro_name =>
{
let res = client.run(
&proc_macro::bridge::server::SameThread,
ra_server::RustAnalyzer::default(),
parsed_body,
true,
);
return res.map(|it| it.into_subtree()).map_err(PanicMessage::from);
}
proc_macro::bridge::client::ProcMacro::Attr { name, client }
if *name == macro_name =>
{
let res = client.run(
&proc_macro::bridge::server::SameThread,
ra_server::RustAnalyzer::default(),
parsed_attributes,
parsed_body,
true,
);
return res.map(|it| it.into_subtree()).map_err(PanicMessage::from);
}
_ => continue,
}
}
Err(proc_macro::bridge::PanicMessage::String("Nothing to expand".to_string()).into())
}
pub fn list_macros(&self) -> Vec<(String, ProcMacroKind)> {
self.exported_macros
.iter()
.map(|proc_macro| match proc_macro {
proc_macro::bridge::client::ProcMacro::CustomDerive { trait_name, .. } => {
(trait_name.to_string(), ProcMacroKind::CustomDerive)
}
proc_macro::bridge::client::ProcMacro::Bang { name, .. } => {
(name.to_string(), ProcMacroKind::FuncLike)
}
proc_macro::bridge::client::ProcMacro::Attr { name, .. } => {
(name.to_string(), ProcMacroKind::Attr)
}
})
.collect()
}
}

View file

@ -1,143 +0,0 @@
//! Buffer management for same-process client<->server communication.
use std::io::{self, Write};
use std::mem;
use std::ops::{Deref, DerefMut};
use std::slice;
#[repr(C)]
pub struct Buffer<T: Copy> {
data: *mut T,
len: usize,
capacity: usize,
reserve: extern "C" fn(Buffer<T>, usize) -> Buffer<T>,
drop: extern "C" fn(Buffer<T>),
}
unsafe impl<T: Copy + Sync> Sync for Buffer<T> {}
unsafe impl<T: Copy + Send> Send for Buffer<T> {}
impl<T: Copy> Default for Buffer<T> {
fn default() -> Self {
Self::from(vec![])
}
}
impl<T: Copy> Deref for Buffer<T> {
type Target = [T];
fn deref(&self) -> &[T] {
unsafe { slice::from_raw_parts(self.data as *const T, self.len) }
}
}
impl<T: Copy> DerefMut for Buffer<T> {
fn deref_mut(&mut self) -> &mut [T] {
unsafe { slice::from_raw_parts_mut(self.data, self.len) }
}
}
impl<T: Copy> Buffer<T> {
pub(super) fn new() -> Self {
Self::default()
}
pub(super) fn clear(&mut self) {
self.len = 0;
}
pub(super) fn take(&mut self) -> Self {
mem::take(self)
}
// We have the array method separate from extending from a slice. This is
// because in the case of small arrays, codegen can be more efficient
// (avoiding a memmove call). With extend_from_slice, LLVM at least
// currently is not able to make that optimization.
pub(super) fn extend_from_array<const N: usize>(&mut self, xs: &[T; N]) {
if xs.len() > (self.capacity - self.len) {
let b = self.take();
*self = (b.reserve)(b, xs.len());
}
unsafe {
xs.as_ptr().copy_to_nonoverlapping(self.data.add(self.len), xs.len());
self.len += xs.len();
}
}
pub(super) fn extend_from_slice(&mut self, xs: &[T]) {
if xs.len() > (self.capacity - self.len) {
let b = self.take();
*self = (b.reserve)(b, xs.len());
}
unsafe {
xs.as_ptr().copy_to_nonoverlapping(self.data.add(self.len), xs.len());
self.len += xs.len();
}
}
pub(super) fn push(&mut self, v: T) {
// The code here is taken from Vec::push, and we know that reserve()
// will panic if we're exceeding isize::MAX bytes and so there's no need
// to check for overflow.
if self.len == self.capacity {
let b = self.take();
*self = (b.reserve)(b, 1);
}
unsafe {
*self.data.add(self.len) = v;
self.len += 1;
}
}
}
impl Write for Buffer<u8> {
fn write(&mut self, xs: &[u8]) -> io::Result<usize> {
self.extend_from_slice(xs);
Ok(xs.len())
}
fn write_all(&mut self, xs: &[u8]) -> io::Result<()> {
self.extend_from_slice(xs);
Ok(())
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
impl<T: Copy> Drop for Buffer<T> {
fn drop(&mut self) {
let b = self.take();
(b.drop)(b);
}
}
impl<T: Copy> From<Vec<T>> for Buffer<T> {
fn from(mut v: Vec<T>) -> Self {
let (data, len, capacity) = (v.as_mut_ptr(), v.len(), v.capacity());
mem::forget(v);
// This utility function is nested in here because it can *only*
// be safely called on `Buffer`s created by *this* `proc_macro`.
fn to_vec<T: Copy>(b: Buffer<T>) -> Vec<T> {
unsafe {
let Buffer { data, len, capacity, .. } = b;
mem::forget(b);
Vec::from_raw_parts(data, len, capacity)
}
}
extern "C" fn reserve<T: Copy>(b: Buffer<T>, additional: usize) -> Buffer<T> {
let mut v = to_vec(b);
v.reserve(additional);
Buffer::from(v)
}
extern "C" fn drop<T: Copy>(b: Buffer<T>) {
mem::drop(to_vec(b));
}
Buffer { data, len, capacity, reserve, drop }
}
}

View file

@ -1,485 +0,0 @@
//! Client-side types.
use super::*;
macro_rules! define_handles {
(
'owned: $($oty:ident,)*
'interned: $($ity:ident,)*
) => {
#[repr(C)]
#[allow(non_snake_case)]
pub struct HandleCounters {
$($oty: AtomicUsize,)*
$($ity: AtomicUsize,)*
}
impl HandleCounters {
// FIXME(eddyb) use a reference to the `static COUNTERS`, instead of
// a wrapper `fn` pointer, once `const fn` can reference `static`s.
extern "C" fn get() -> &'static Self {
static COUNTERS: HandleCounters = HandleCounters {
$($oty: AtomicUsize::new(1),)*
$($ity: AtomicUsize::new(1),)*
};
&COUNTERS
}
}
// FIXME(eddyb) generate the definition of `HandleStore` in `server.rs`.
#[repr(C)]
#[allow(non_snake_case)]
pub(super) struct HandleStore<S: server::Types> {
$($oty: handle::OwnedStore<S::$oty>,)*
$($ity: handle::InternedStore<S::$ity>,)*
}
impl<S: server::Types> HandleStore<S> {
pub(super) fn new(handle_counters: &'static HandleCounters) -> Self {
HandleStore {
$($oty: handle::OwnedStore::new(&handle_counters.$oty),)*
$($ity: handle::InternedStore::new(&handle_counters.$ity),)*
}
}
}
$(
#[repr(C)]
pub(crate) struct $oty(handle::Handle);
// Forward `Drop::drop` to the inherent `drop` method.
impl Drop for $oty {
fn drop(&mut self) {
$oty(self.0).drop();
}
}
impl<S> Encode<S> for $oty {
fn encode(self, w: &mut Writer, s: &mut S) {
let handle = self.0;
mem::forget(self);
handle.encode(w, s);
}
}
impl<S: server::Types> DecodeMut<'_, '_, HandleStore<server::MarkedTypes<S>>>
for Marked<S::$oty, $oty>
{
fn decode(r: &mut Reader<'_>, s: &mut HandleStore<server::MarkedTypes<S>>) -> Self {
s.$oty.take(handle::Handle::decode(r, &mut ()))
}
}
impl<S> Encode<S> for &$oty {
fn encode(self, w: &mut Writer, s: &mut S) {
self.0.encode(w, s);
}
}
impl<'s, S: server::Types> Decode<'_, 's, HandleStore<server::MarkedTypes<S>>>
for &'s Marked<S::$oty, $oty>
{
fn decode(r: &mut Reader<'_>, s: &'s HandleStore<server::MarkedTypes<S>>) -> Self {
&s.$oty[handle::Handle::decode(r, &mut ())]
}
}
impl<S> Encode<S> for &mut $oty {
fn encode(self, w: &mut Writer, s: &mut S) {
self.0.encode(w, s);
}
}
impl<'s, S: server::Types> DecodeMut<'_, 's, HandleStore<server::MarkedTypes<S>>>
for &'s mut Marked<S::$oty, $oty>
{
fn decode(
r: &mut Reader<'_>,
s: &'s mut HandleStore<server::MarkedTypes<S>>
) -> Self {
&mut s.$oty[handle::Handle::decode(r, &mut ())]
}
}
impl<S: server::Types> Encode<HandleStore<server::MarkedTypes<S>>>
for Marked<S::$oty, $oty>
{
fn encode(self, w: &mut Writer, s: &mut HandleStore<server::MarkedTypes<S>>) {
s.$oty.alloc(self).encode(w, s);
}
}
impl<S> DecodeMut<'_, '_, S> for $oty {
fn decode(r: &mut Reader<'_>, s: &mut S) -> Self {
$oty(handle::Handle::decode(r, s))
}
}
)*
$(
#[repr(C)]
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub(crate) struct $ity(handle::Handle);
impl<S> Encode<S> for $ity {
fn encode(self, w: &mut Writer, s: &mut S) {
self.0.encode(w, s);
}
}
impl<S: server::Types> DecodeMut<'_, '_, HandleStore<server::MarkedTypes<S>>>
for Marked<S::$ity, $ity>
{
fn decode(r: &mut Reader<'_>, s: &mut HandleStore<server::MarkedTypes<S>>) -> Self {
s.$ity.copy(handle::Handle::decode(r, &mut ()))
}
}
impl<S: server::Types> Encode<HandleStore<server::MarkedTypes<S>>>
for Marked<S::$ity, $ity>
{
fn encode(self, w: &mut Writer, s: &mut HandleStore<server::MarkedTypes<S>>) {
s.$ity.alloc(self).encode(w, s);
}
}
impl<S> DecodeMut<'_, '_, S> for $ity {
fn decode(r: &mut Reader<'_>, s: &mut S) -> Self {
$ity(handle::Handle::decode(r, s))
}
}
)*
}
}
define_handles! {
'owned:
FreeFunctions,
TokenStream,
TokenStreamBuilder,
TokenStreamIter,
Group,
Literal,
SourceFile,
MultiSpan,
Diagnostic,
'interned:
Punct,
Ident,
Span,
}
// FIXME(eddyb) generate these impls by pattern-matching on the
// names of methods - also could use the presence of `fn drop`
// to distinguish between 'owned and 'interned, above.
// Alternatively, special 'modes" could be listed of types in with_api
// instead of pattern matching on methods, here and in server decl.
impl Clone for TokenStream {
fn clone(&self) -> Self {
self.clone()
}
}
impl Clone for TokenStreamIter {
fn clone(&self) -> Self {
self.clone()
}
}
impl Clone for Group {
fn clone(&self) -> Self {
self.clone()
}
}
impl Clone for Literal {
fn clone(&self) -> Self {
self.clone()
}
}
impl fmt::Debug for Literal {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Literal")
// format the kind without quotes, as in `kind: Float`
.field("kind", &format_args!("{}", &self.debug_kind()))
.field("symbol", &self.symbol())
// format `Some("...")` on one line even in {:#?} mode
.field("suffix", &format_args!("{:?}", &self.suffix()))
.field("span", &self.span())
.finish()
}
}
impl Clone for SourceFile {
fn clone(&self) -> Self {
self.clone()
}
}
impl fmt::Debug for Span {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.debug())
}
}
macro_rules! define_client_side {
($($name:ident {
$(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)*
}),* $(,)?) => {
$(impl $name {
$(pub(crate) fn $method($($arg: $arg_ty),*) $(-> $ret_ty)* {
Bridge::with(|bridge| {
let mut b = bridge.cached_buffer.take();
b.clear();
api_tags::Method::$name(api_tags::$name::$method).encode(&mut b, &mut ());
reverse_encode!(b; $($arg),*);
b = bridge.dispatch.call(b);
let r = Result::<_, PanicMessage>::decode(&mut &b[..], &mut ());
bridge.cached_buffer = b;
r.unwrap_or_else(|e| panic::resume_unwind(e.into()))
})
})*
})*
}
}
with_api!(self, self, define_client_side);
enum BridgeState<'a> {
/// No server is currently connected to this client.
NotConnected,
/// A server is connected and available for requests.
Connected(Bridge<'a>),
/// Access to the bridge is being exclusively acquired
/// (e.g., during `BridgeState::with`).
InUse,
}
enum BridgeStateL {}
impl<'a> scoped_cell::ApplyL<'a> for BridgeStateL {
type Out = BridgeState<'a>;
}
thread_local! {
static BRIDGE_STATE: scoped_cell::ScopedCell<BridgeStateL> =
scoped_cell::ScopedCell::new(BridgeState::NotConnected);
}
impl BridgeState<'_> {
/// Take exclusive control of the thread-local
/// `BridgeState`, and pass it to `f`, mutably.
/// The state will be restored after `f` exits, even
/// by panic, including modifications made to it by `f`.
///
/// N.B., while `f` is running, the thread-local state
/// is `BridgeState::InUse`.
fn with<R>(f: impl FnOnce(&mut BridgeState<'_>) -> R) -> R {
BRIDGE_STATE.with(|state| {
state.replace(BridgeState::InUse, |mut state| {
// FIXME(#52812) pass `f` directly to `replace` when `RefMutL` is gone
f(&mut state)
})
})
}
}
impl Bridge<'_> {
pub(crate) fn is_available() -> bool {
BridgeState::with(|state| match state {
BridgeState::Connected(_) | BridgeState::InUse => true,
BridgeState::NotConnected => false,
})
}
fn enter<R>(self, f: impl FnOnce() -> R) -> R {
let force_show_panics = self.force_show_panics;
// Hide the default panic output within `proc_macro` expansions.
// NB. the server can't do this because it may use a different libstd.
static HIDE_PANICS_DURING_EXPANSION: Once = Once::new();
HIDE_PANICS_DURING_EXPANSION.call_once(|| {
let prev = panic::take_hook();
panic::set_hook(Box::new(move |info| {
let show = BridgeState::with(|state| match state {
BridgeState::NotConnected => true,
BridgeState::Connected(_) | BridgeState::InUse => force_show_panics,
});
if show {
prev(info)
}
}));
});
BRIDGE_STATE.with(|state| state.set(BridgeState::Connected(self), f))
}
fn with<R>(f: impl FnOnce(&mut Bridge<'_>) -> R) -> R {
BridgeState::with(|state| match state {
BridgeState::NotConnected => {
panic!("procedural macro API is used outside of a procedural macro");
}
BridgeState::InUse => {
panic!("procedural macro API is used while it's already in use");
}
BridgeState::Connected(bridge) => f(bridge),
})
}
}
/// A client-side "global object" (usually a function pointer),
/// which may be using a different `proc_macro` from the one
/// used by the server, but can be interacted with compatibly.
///
/// N.B., `F` must have FFI-friendly memory layout (e.g., a pointer).
/// The call ABI of function pointers used for `F` doesn't
/// need to match between server and client, since it's only
/// passed between them and (eventually) called by the client.
#[repr(C)]
#[derive(Copy, Clone)]
pub struct Client<F> {
// FIXME(eddyb) use a reference to the `static COUNTERS`, instead of
// a wrapper `fn` pointer, once `const fn` can reference `static`s.
pub(super) get_handle_counters: extern "C" fn() -> &'static HandleCounters,
pub(super) run: extern "C" fn(Bridge<'_>, F) -> Buffer<u8>,
pub(super) f: F,
}
/// Client-side helper for handling client panics, entering the bridge,
/// deserializing input and serializing output.
// FIXME(eddyb) maybe replace `Bridge::enter` with this?
fn run_client<A: for<'a, 's> DecodeMut<'a, 's, ()>, R: Encode<()>>(
mut bridge: Bridge<'_>,
f: impl FnOnce(A) -> R,
) -> Buffer<u8> {
// The initial `cached_buffer` contains the input.
let mut b = bridge.cached_buffer.take();
panic::catch_unwind(panic::AssertUnwindSafe(|| {
bridge.enter(|| {
let reader = &mut &b[..];
let input = A::decode(reader, &mut ());
// Put the `cached_buffer` back in the `Bridge`, for requests.
Bridge::with(|bridge| bridge.cached_buffer = b.take());
let output = f(input);
// Take the `cached_buffer` back out, for the output value.
b = Bridge::with(|bridge| bridge.cached_buffer.take());
// HACK(eddyb) Separate encoding a success value (`Ok(output)`)
// from encoding a panic (`Err(e: PanicMessage)`) to avoid
// having handles outside the `bridge.enter(|| ...)` scope, and
// to catch panics that could happen while encoding the success.
//
// Note that panics should be impossible beyond this point, but
// this is defensively trying to avoid any accidental panicking
// reaching the `extern "C"` (which should `abort` but might not
// at the moment, so this is also potentially preventing UB).
b.clear();
Ok::<_, ()>(output).encode(&mut b, &mut ());
})
}))
.map_err(PanicMessage::from)
.unwrap_or_else(|e| {
b.clear();
Err::<(), _>(e).encode(&mut b, &mut ());
});
b
}
impl Client<fn(super::super::TokenStream) -> super::super::TokenStream> {
pub fn expand1(f: fn(super::super::TokenStream) -> super::super::TokenStream) -> Self {
extern "C" fn run(
bridge: Bridge<'_>,
f: impl FnOnce(super::super::TokenStream) -> super::super::TokenStream,
) -> Buffer<u8> {
run_client(bridge, |input| f(super::super::TokenStream(input)).0)
}
Client { get_handle_counters: HandleCounters::get, run, f }
}
}
impl Client<fn(super::super::TokenStream, super::super::TokenStream) -> super::super::TokenStream> {
pub fn expand2(
f: fn(super::super::TokenStream, super::super::TokenStream) -> super::super::TokenStream,
) -> Self {
extern "C" fn run(
bridge: Bridge<'_>,
f: impl FnOnce(
super::super::TokenStream,
super::super::TokenStream,
) -> super::super::TokenStream,
) -> Buffer<u8> {
run_client(bridge, |(input, input2)| {
f(super::super::TokenStream(input), super::super::TokenStream(input2)).0
})
}
Client { get_handle_counters: HandleCounters::get, run, f }
}
}
#[repr(C)]
#[derive(Copy, Clone)]
pub enum ProcMacro {
CustomDerive {
trait_name: &'static str,
attributes: &'static [&'static str],
client: Client<fn(super::super::TokenStream) -> super::super::TokenStream>,
},
Attr {
name: &'static str,
client: Client<
fn(super::super::TokenStream, super::super::TokenStream) -> super::super::TokenStream,
>,
},
Bang {
name: &'static str,
client: Client<fn(super::super::TokenStream) -> super::super::TokenStream>,
},
}
impl ProcMacro {
pub fn name(&self) -> &'static str {
match self {
ProcMacro::CustomDerive { trait_name, .. } => trait_name,
ProcMacro::Attr { name, .. } => name,
ProcMacro::Bang { name, .. } => name,
}
}
pub fn custom_derive(
trait_name: &'static str,
attributes: &'static [&'static str],
expand: fn(super::super::TokenStream) -> super::super::TokenStream,
) -> Self {
ProcMacro::CustomDerive { trait_name, attributes, client: Client::expand1(expand) }
}
pub fn attr(
name: &'static str,
expand: fn(
super::super::TokenStream,
super::super::TokenStream,
) -> super::super::TokenStream,
) -> Self {
ProcMacro::Attr { name, client: Client::expand2(expand) }
}
pub fn bang(
name: &'static str,
expand: fn(super::super::TokenStream) -> super::super::TokenStream,
) -> Self {
ProcMacro::Bang { name, client: Client::expand1(expand) }
}
}

View file

@ -1,24 +0,0 @@
//! Closure type (equivalent to `&mut dyn FnMut(A) -> R`) that's `repr(C)`.
#[repr(C)]
pub struct Closure<'a, A, R> {
call: unsafe extern "C" fn(&mut Env, A) -> R,
env: &'a mut Env,
}
struct Env;
impl<'a, A, R, F: FnMut(A) -> R> From<&'a mut F> for Closure<'a, A, R> {
fn from(f: &'a mut F) -> Self {
unsafe extern "C" fn call<A, R, F: FnMut(A) -> R>(env: &mut Env, arg: A) -> R {
(*(env as *mut _ as *mut F))(arg)
}
Closure { call: call::<A, R, F>, env: unsafe { &mut *(f as *mut _ as *mut Env) } }
}
}
impl<'a, A, R> Closure<'a, A, R> {
pub fn call(&mut self, arg: A) -> R {
unsafe { (self.call)(self.env, arg) }
}
}

View file

@ -1,70 +0,0 @@
//! Server-side handles and storage for per-handle data.
use std::collections::{BTreeMap, HashMap};
use std::hash::Hash;
use std::num::NonZeroU32;
use std::ops::{Index, IndexMut};
use std::sync::atomic::{AtomicUsize, Ordering};
pub(super) type Handle = NonZeroU32;
pub(super) struct OwnedStore<T: 'static> {
counter: &'static AtomicUsize,
data: BTreeMap<Handle, T>,
}
impl<T> OwnedStore<T> {
pub(super) fn new(counter: &'static AtomicUsize) -> Self {
// Ensure the handle counter isn't 0, which would panic later,
// when `NonZeroU32::new` (aka `Handle::new`) is called in `alloc`.
assert_ne!(counter.load(Ordering::SeqCst), 0);
OwnedStore { counter, data: BTreeMap::new() }
}
}
impl<T> OwnedStore<T> {
pub(super) fn alloc(&mut self, x: T) -> Handle {
let counter = self.counter.fetch_add(1, Ordering::SeqCst);
let handle = Handle::new(counter as u32).expect("`proc_macro` handle counter overflowed");
assert!(self.data.insert(handle, x).is_none());
handle
}
pub(super) fn take(&mut self, h: Handle) -> T {
self.data.remove(&h).expect("use-after-free in `proc_macro` handle")
}
}
impl<T> Index<Handle> for OwnedStore<T> {
type Output = T;
fn index(&self, h: Handle) -> &T {
self.data.get(&h).expect("use-after-free in `proc_macro` handle")
}
}
impl<T> IndexMut<Handle> for OwnedStore<T> {
fn index_mut(&mut self, h: Handle) -> &mut T {
self.data.get_mut(&h).expect("use-after-free in `proc_macro` handle")
}
}
pub(super) struct InternedStore<T: 'static> {
owned: OwnedStore<T>,
interner: HashMap<T, Handle>,
}
impl<T: Copy + Eq + Hash> InternedStore<T> {
pub(super) fn new(counter: &'static AtomicUsize) -> Self {
InternedStore { owned: OwnedStore::new(counter), interner: HashMap::new() }
}
pub(super) fn alloc(&mut self, x: T) -> Handle {
let owned = &mut self.owned;
*self.interner.entry(x).or_insert_with(|| owned.alloc(x))
}
pub(super) fn copy(&mut self, h: Handle) -> T {
self.owned[h]
}
}

View file

@ -1,429 +0,0 @@
//! Internal interface for communicating between a `proc_macro` client
//! (a proc macro crate) and a `proc_macro` server (a compiler front-end).
//!
//! Serialization (with C ABI buffers) and unique integer handles are employed
//! to allow safely interfacing between two copies of `proc_macro` built
//! (from the same source) by different compilers with potentially mismatching
//! Rust ABIs (e.g., stage0/bin/rustc vs stage1/bin/rustc during bootstrap).
#![deny(unsafe_code)]
pub use super::{Delimiter, Level, LineColumn, Spacing};
use std::fmt;
use std::hash::Hash;
use std::marker;
use std::mem;
use std::ops::Bound;
use std::panic;
use std::sync::atomic::AtomicUsize;
use std::sync::Once;
use std::thread;
/// Higher-order macro describing the server RPC API, allowing automatic
/// generation of type-safe Rust APIs, both client-side and server-side.
///
/// `with_api!(MySelf, my_self, my_macro)` expands to:
/// ```rust,ignore (pseudo-code)
/// my_macro! {
/// // ...
/// Literal {
/// // ...
/// fn character(ch: char) -> MySelf::Literal;
/// // ...
/// fn span(my_self: &MySelf::Literal) -> MySelf::Span;
/// fn set_span(my_self: &mut MySelf::Literal, span: MySelf::Span);
/// },
/// // ...
/// }
/// ```
///
/// The first two arguments serve to customize the arguments names
/// and argument/return types, to enable several different usecases:
///
/// If `my_self` is just `self`, then each `fn` signature can be used
/// as-is for a method. If it's anything else (`self_` in practice),
/// then the signatures don't have a special `self` argument, and
/// can, therefore, have a different one introduced.
///
/// If `MySelf` is just `Self`, then the types are only valid inside
/// a trait or a trait impl, where the trait has associated types
/// for each of the API types. If non-associated types are desired,
/// a module name (`self` in practice) can be used instead of `Self`.
macro_rules! with_api {
($S:ident, $self:ident, $m:ident) => {
$m! {
FreeFunctions {
fn drop($self: $S::FreeFunctions);
fn track_env_var(var: &str, value: Option<&str>);
fn track_path(path: &str);
},
TokenStream {
fn drop($self: $S::TokenStream);
fn clone($self: &$S::TokenStream) -> $S::TokenStream;
fn new() -> $S::TokenStream;
fn is_empty($self: &$S::TokenStream) -> bool;
fn expand_expr($self: &$S::TokenStream) -> Result<$S::TokenStream, ()>;
fn from_str(src: &str) -> $S::TokenStream;
fn to_string($self: &$S::TokenStream) -> String;
fn from_token_tree(
tree: TokenTree<$S::Group, $S::Punct, $S::Ident, $S::Literal>,
) -> $S::TokenStream;
fn into_iter($self: $S::TokenStream) -> $S::TokenStreamIter;
},
TokenStreamBuilder {
fn drop($self: $S::TokenStreamBuilder);
fn new() -> $S::TokenStreamBuilder;
fn push($self: &mut $S::TokenStreamBuilder, stream: $S::TokenStream);
fn build($self: $S::TokenStreamBuilder) -> $S::TokenStream;
},
TokenStreamIter {
fn drop($self: $S::TokenStreamIter);
fn clone($self: &$S::TokenStreamIter) -> $S::TokenStreamIter;
fn next(
$self: &mut $S::TokenStreamIter,
) -> Option<TokenTree<$S::Group, $S::Punct, $S::Ident, $S::Literal>>;
},
Group {
fn drop($self: $S::Group);
fn clone($self: &$S::Group) -> $S::Group;
fn new(delimiter: Delimiter, stream: $S::TokenStream) -> $S::Group;
fn delimiter($self: &$S::Group) -> Delimiter;
fn stream($self: &$S::Group) -> $S::TokenStream;
fn span($self: &$S::Group) -> $S::Span;
fn span_open($self: &$S::Group) -> $S::Span;
fn span_close($self: &$S::Group) -> $S::Span;
fn set_span($self: &mut $S::Group, span: $S::Span);
},
Punct {
fn new(ch: char, spacing: Spacing) -> $S::Punct;
fn as_char($self: $S::Punct) -> char;
fn spacing($self: $S::Punct) -> Spacing;
fn span($self: $S::Punct) -> $S::Span;
fn with_span($self: $S::Punct, span: $S::Span) -> $S::Punct;
},
Ident {
fn new(string: &str, span: $S::Span, is_raw: bool) -> $S::Ident;
fn span($self: $S::Ident) -> $S::Span;
fn with_span($self: $S::Ident, span: $S::Span) -> $S::Ident;
},
Literal {
fn drop($self: $S::Literal);
fn clone($self: &$S::Literal) -> $S::Literal;
fn from_str(s: &str) -> Result<$S::Literal, ()>;
fn to_string($self: &$S::Literal) -> String;
fn debug_kind($self: &$S::Literal) -> String;
fn symbol($self: &$S::Literal) -> String;
fn suffix($self: &$S::Literal) -> Option<String>;
fn integer(n: &str) -> $S::Literal;
fn typed_integer(n: &str, kind: &str) -> $S::Literal;
fn float(n: &str) -> $S::Literal;
fn f32(n: &str) -> $S::Literal;
fn f64(n: &str) -> $S::Literal;
fn string(string: &str) -> $S::Literal;
fn character(ch: char) -> $S::Literal;
fn byte_string(bytes: &[u8]) -> $S::Literal;
fn span($self: &$S::Literal) -> $S::Span;
fn set_span($self: &mut $S::Literal, span: $S::Span);
fn subspan(
$self: &$S::Literal,
start: Bound<usize>,
end: Bound<usize>,
) -> Option<$S::Span>;
},
SourceFile {
fn drop($self: $S::SourceFile);
fn clone($self: &$S::SourceFile) -> $S::SourceFile;
fn eq($self: &$S::SourceFile, other: &$S::SourceFile) -> bool;
fn path($self: &$S::SourceFile) -> String;
fn is_real($self: &$S::SourceFile) -> bool;
},
MultiSpan {
fn drop($self: $S::MultiSpan);
fn new() -> $S::MultiSpan;
fn push($self: &mut $S::MultiSpan, span: $S::Span);
},
Diagnostic {
fn drop($self: $S::Diagnostic);
fn new(level: Level, msg: &str, span: $S::MultiSpan) -> $S::Diagnostic;
fn sub(
$self: &mut $S::Diagnostic,
level: Level,
msg: &str,
span: $S::MultiSpan,
);
fn emit($self: $S::Diagnostic);
},
Span {
fn debug($self: $S::Span) -> String;
fn def_site() -> $S::Span;
fn call_site() -> $S::Span;
fn mixed_site() -> $S::Span;
fn source_file($self: $S::Span) -> $S::SourceFile;
fn parent($self: $S::Span) -> Option<$S::Span>;
fn source($self: $S::Span) -> $S::Span;
fn start($self: $S::Span) -> LineColumn;
fn end($self: $S::Span) -> LineColumn;
fn before($self: $S::Span) -> $S::Span;
fn after($self: $S::Span) -> $S::Span;
fn join($self: $S::Span, other: $S::Span) -> Option<$S::Span>;
fn resolved_at($self: $S::Span, at: $S::Span) -> $S::Span;
fn source_text($self: $S::Span) -> Option<String>;
fn save_span($self: $S::Span) -> usize;
fn recover_proc_macro_span(id: usize) -> $S::Span;
},
}
};
}
// FIXME(eddyb) this calls `encode` for each argument, but in reverse,
// to avoid borrow conflicts from borrows started by `&mut` arguments.
macro_rules! reverse_encode {
($writer:ident;) => {};
($writer:ident; $first:ident $(, $rest:ident)*) => {
reverse_encode!($writer; $($rest),*);
$first.encode(&mut $writer, &mut ());
}
}
// FIXME(eddyb) this calls `decode` for each argument, but in reverse,
// to avoid borrow conflicts from borrows started by `&mut` arguments.
macro_rules! reverse_decode {
($reader:ident, $s:ident;) => {};
($reader:ident, $s:ident; $first:ident: $first_ty:ty $(, $rest:ident: $rest_ty:ty)*) => {
reverse_decode!($reader, $s; $($rest: $rest_ty),*);
let $first = <$first_ty>::decode(&mut $reader, $s);
}
}
#[allow(unsafe_code)]
mod buffer;
#[forbid(unsafe_code)]
pub mod client;
#[allow(unsafe_code)]
mod closure;
#[forbid(unsafe_code)]
mod handle;
#[macro_use]
#[forbid(unsafe_code)]
mod rpc;
#[allow(unsafe_code)]
mod scoped_cell;
#[forbid(unsafe_code)]
pub mod server;
use buffer::Buffer;
pub use rpc::PanicMessage;
use rpc::{Decode, DecodeMut, Encode, Reader, Writer};
/// An active connection between a server and a client.
/// The server creates the bridge (`Bridge::run_server` in `server.rs`),
/// then passes it to the client through the function pointer in the `run`
/// field of `client::Client`. The client holds its copy of the `Bridge`
/// in TLS during its execution (`Bridge::{enter, with}` in `client.rs`).
#[repr(C)]
pub struct Bridge<'a> {
/// Reusable buffer (only `clear`-ed, never shrunk), primarily
/// used for making requests, but also for passing input to client.
cached_buffer: Buffer<u8>,
/// Server-side function that the client uses to make requests.
dispatch: closure::Closure<'a, Buffer<u8>, Buffer<u8>>,
/// If 'true', always invoke the default panic hook
force_show_panics: bool,
}
#[forbid(unsafe_code)]
#[allow(non_camel_case_types)]
mod api_tags {
use super::rpc::{DecodeMut, Encode, Reader, Writer};
macro_rules! declare_tags {
($($name:ident {
$(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)*
}),* $(,)?) => {
$(
pub(super) enum $name {
$($method),*
}
rpc_encode_decode!(enum $name { $($method),* });
)*
pub(super) enum Method {
$($name($name)),*
}
rpc_encode_decode!(enum Method { $($name(m)),* });
}
}
with_api!(self, self, declare_tags);
}
/// Helper to wrap associated types to allow trait impl dispatch.
/// That is, normally a pair of impls for `T::Foo` and `T::Bar`
/// can overlap, but if the impls are, instead, on types like
/// `Marked<T::Foo, Foo>` and `Marked<T::Bar, Bar>`, they can't.
trait Mark {
type Unmarked;
fn mark(unmarked: Self::Unmarked) -> Self;
}
/// Unwrap types wrapped by `Mark::mark` (see `Mark` for details).
trait Unmark {
type Unmarked;
fn unmark(self) -> Self::Unmarked;
}
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
struct Marked<T, M> {
value: T,
_marker: marker::PhantomData<M>,
}
impl<T, M> Mark for Marked<T, M> {
type Unmarked = T;
fn mark(unmarked: Self::Unmarked) -> Self {
Marked { value: unmarked, _marker: marker::PhantomData }
}
}
impl<T, M> Unmark for Marked<T, M> {
type Unmarked = T;
fn unmark(self) -> Self::Unmarked {
self.value
}
}
impl<'a, T, M> Unmark for &'a Marked<T, M> {
type Unmarked = &'a T;
fn unmark(self) -> Self::Unmarked {
&self.value
}
}
impl<'a, T, M> Unmark for &'a mut Marked<T, M> {
type Unmarked = &'a mut T;
fn unmark(self) -> Self::Unmarked {
&mut self.value
}
}
impl<T: Mark> Mark for Option<T> {
type Unmarked = Option<T::Unmarked>;
fn mark(unmarked: Self::Unmarked) -> Self {
unmarked.map(T::mark)
}
}
impl<T: Unmark> Unmark for Option<T> {
type Unmarked = Option<T::Unmarked>;
fn unmark(self) -> Self::Unmarked {
self.map(T::unmark)
}
}
impl<T: Mark, E: Mark> Mark for Result<T, E> {
type Unmarked = Result<T::Unmarked, E::Unmarked>;
fn mark(unmarked: Self::Unmarked) -> Self {
unmarked.map(T::mark).map_err(E::mark)
}
}
impl<T: Unmark, E: Unmark> Unmark for Result<T, E> {
type Unmarked = Result<T::Unmarked, E::Unmarked>;
fn unmark(self) -> Self::Unmarked {
self.map(T::unmark).map_err(E::unmark)
}
}
macro_rules! mark_noop {
($($ty:ty),* $(,)?) => {
$(
impl Mark for $ty {
type Unmarked = Self;
fn mark(unmarked: Self::Unmarked) -> Self {
unmarked
}
}
impl Unmark for $ty {
type Unmarked = Self;
fn unmark(self) -> Self::Unmarked {
self
}
}
)*
}
}
mark_noop! {
(),
bool,
char,
&'_ [u8],
&'_ str,
String,
usize,
Delimiter,
Level,
LineColumn,
Spacing,
Bound<usize>,
}
rpc_encode_decode!(
enum Delimiter {
Parenthesis,
Brace,
Bracket,
None,
}
);
rpc_encode_decode!(
enum Level {
Error,
Warning,
Note,
Help,
}
);
rpc_encode_decode!(struct LineColumn { line, column });
rpc_encode_decode!(
enum Spacing {
Alone,
Joint,
}
);
#[derive(Clone)]
pub enum TokenTree<G, P, I, L> {
Group(G),
Punct(P),
Ident(I),
Literal(L),
}
impl<G: Mark, P: Mark, I: Mark, L: Mark> Mark for TokenTree<G, P, I, L> {
type Unmarked = TokenTree<G::Unmarked, P::Unmarked, I::Unmarked, L::Unmarked>;
fn mark(unmarked: Self::Unmarked) -> Self {
match unmarked {
TokenTree::Group(tt) => TokenTree::Group(G::mark(tt)),
TokenTree::Punct(tt) => TokenTree::Punct(P::mark(tt)),
TokenTree::Ident(tt) => TokenTree::Ident(I::mark(tt)),
TokenTree::Literal(tt) => TokenTree::Literal(L::mark(tt)),
}
}
}
impl<G: Unmark, P: Unmark, I: Unmark, L: Unmark> Unmark for TokenTree<G, P, I, L> {
type Unmarked = TokenTree<G::Unmarked, P::Unmarked, I::Unmarked, L::Unmarked>;
fn unmark(self) -> Self::Unmarked {
match self {
TokenTree::Group(tt) => TokenTree::Group(tt.unmark()),
TokenTree::Punct(tt) => TokenTree::Punct(tt.unmark()),
TokenTree::Ident(tt) => TokenTree::Ident(tt.unmark()),
TokenTree::Literal(tt) => TokenTree::Literal(tt.unmark()),
}
}
}
rpc_encode_decode!(
enum TokenTree<G, P, I, L> {
Group(tt),
Punct(tt),
Ident(tt),
Literal(tt),
}
);

View file

@ -1,305 +0,0 @@
//! Serialization for client-server communication.
use std::any::Any;
use std::char;
use std::io::Write;
use std::num::NonZeroU32;
use std::ops::Bound;
use std::str;
pub(super) type Writer = super::buffer::Buffer<u8>;
pub(super) trait Encode<S>: Sized {
fn encode(self, w: &mut Writer, s: &mut S);
}
pub(super) type Reader<'a> = &'a [u8];
pub(super) trait Decode<'a, 's, S>: Sized {
fn decode(r: &mut Reader<'a>, s: &'s S) -> Self;
}
pub(super) trait DecodeMut<'a, 's, S>: Sized {
fn decode(r: &mut Reader<'a>, s: &'s mut S) -> Self;
}
macro_rules! rpc_encode_decode {
(le $ty:ty) => {
impl<S> Encode<S> for $ty {
fn encode(self, w: &mut Writer, _: &mut S) {
w.extend_from_array(&self.to_le_bytes());
}
}
impl<S> DecodeMut<'_, '_, S> for $ty {
fn decode(r: &mut Reader<'_>, _: &mut S) -> Self {
const N: usize = ::std::mem::size_of::<$ty>();
let mut bytes = [0; N];
bytes.copy_from_slice(&r[..N]);
*r = &r[N..];
Self::from_le_bytes(bytes)
}
}
};
(struct $name:ident { $($field:ident),* $(,)? }) => {
impl<S> Encode<S> for $name {
fn encode(self, w: &mut Writer, s: &mut S) {
$(self.$field.encode(w, s);)*
}
}
impl<S> DecodeMut<'_, '_, S> for $name {
fn decode(r: &mut Reader<'_>, s: &mut S) -> Self {
$name {
$($field: DecodeMut::decode(r, s)),*
}
}
}
};
(enum $name:ident $(<$($T:ident),+>)? { $($variant:ident $(($field:ident))*),* $(,)? }) => {
impl<S, $($($T: Encode<S>),+)?> Encode<S> for $name $(<$($T),+>)? {
fn encode(self, w: &mut Writer, s: &mut S) {
// HACK(eddyb): `Tag` enum duplicated between the
// two impls as there's no other place to stash it.
#[allow(non_upper_case_globals)]
mod tag {
#[repr(u8)] enum Tag { $($variant),* }
$(pub const $variant: u8 = Tag::$variant as u8;)*
}
match self {
$($name::$variant $(($field))* => {
tag::$variant.encode(w, s);
$($field.encode(w, s);)*
})*
}
}
}
impl<'a, S, $($($T: for<'s> DecodeMut<'a, 's, S>),+)?> DecodeMut<'a, '_, S>
for $name $(<$($T),+>)?
{
fn decode(r: &mut Reader<'a>, s: &mut S) -> Self {
// HACK(eddyb): `Tag` enum duplicated between the
// two impls as there's no other place to stash it.
#[allow(non_upper_case_globals)]
mod tag {
#[repr(u8)] enum Tag { $($variant),* }
$(pub const $variant: u8 = Tag::$variant as u8;)*
}
match u8::decode(r, s) {
$(tag::$variant => {
$(let $field = DecodeMut::decode(r, s);)*
$name::$variant $(($field))*
})*
_ => unreachable!(),
}
}
}
}
}
impl<S> Encode<S> for () {
fn encode(self, _: &mut Writer, _: &mut S) {}
}
impl<S> DecodeMut<'_, '_, S> for () {
fn decode(_: &mut Reader<'_>, _: &mut S) -> Self {}
}
impl<S> Encode<S> for u8 {
fn encode(self, w: &mut Writer, _: &mut S) {
w.push(self);
}
}
impl<S> DecodeMut<'_, '_, S> for u8 {
fn decode(r: &mut Reader<'_>, _: &mut S) -> Self {
let x = r[0];
*r = &r[1..];
x
}
}
rpc_encode_decode!(le u32);
rpc_encode_decode!(le usize);
impl<S> Encode<S> for bool {
fn encode(self, w: &mut Writer, s: &mut S) {
(self as u8).encode(w, s);
}
}
impl<S> DecodeMut<'_, '_, S> for bool {
fn decode(r: &mut Reader<'_>, s: &mut S) -> Self {
match u8::decode(r, s) {
0 => false,
1 => true,
_ => unreachable!(),
}
}
}
impl<S> Encode<S> for char {
fn encode(self, w: &mut Writer, s: &mut S) {
(self as u32).encode(w, s);
}
}
impl<S> DecodeMut<'_, '_, S> for char {
fn decode(r: &mut Reader<'_>, s: &mut S) -> Self {
char::from_u32(u32::decode(r, s)).unwrap()
}
}
impl<S> Encode<S> for NonZeroU32 {
fn encode(self, w: &mut Writer, s: &mut S) {
self.get().encode(w, s);
}
}
impl<S> DecodeMut<'_, '_, S> for NonZeroU32 {
fn decode(r: &mut Reader<'_>, s: &mut S) -> Self {
Self::new(u32::decode(r, s)).unwrap()
}
}
impl<S, A: Encode<S>, B: Encode<S>> Encode<S> for (A, B) {
fn encode(self, w: &mut Writer, s: &mut S) {
self.0.encode(w, s);
self.1.encode(w, s);
}
}
impl<'a, S, A: for<'s> DecodeMut<'a, 's, S>, B: for<'s> DecodeMut<'a, 's, S>> DecodeMut<'a, '_, S>
for (A, B)
{
fn decode(r: &mut Reader<'a>, s: &mut S) -> Self {
(DecodeMut::decode(r, s), DecodeMut::decode(r, s))
}
}
rpc_encode_decode!(
enum Bound<T> {
Included(x),
Excluded(x),
Unbounded,
}
);
rpc_encode_decode!(
enum Option<T> {
None,
Some(x),
}
);
rpc_encode_decode!(
enum Result<T, E> {
Ok(x),
Err(e),
}
);
impl<S> Encode<S> for &[u8] {
fn encode(self, w: &mut Writer, s: &mut S) {
self.len().encode(w, s);
w.write_all(self).unwrap();
}
}
impl<'a, S> DecodeMut<'a, '_, S> for &'a [u8] {
fn decode(r: &mut Reader<'a>, s: &mut S) -> Self {
let len = usize::decode(r, s);
let xs = &r[..len];
*r = &r[len..];
xs
}
}
impl<S> Encode<S> for &str {
fn encode(self, w: &mut Writer, s: &mut S) {
self.as_bytes().encode(w, s);
}
}
impl<'a, S> DecodeMut<'a, '_, S> for &'a str {
fn decode(r: &mut Reader<'a>, s: &mut S) -> Self {
str::from_utf8(<&[u8]>::decode(r, s)).unwrap()
}
}
impl<S> Encode<S> for String {
fn encode(self, w: &mut Writer, s: &mut S) {
self[..].encode(w, s);
}
}
impl<S> DecodeMut<'_, '_, S> for String {
fn decode(r: &mut Reader<'_>, s: &mut S) -> Self {
<&str>::decode(r, s).to_string()
}
}
/// Simplified version of panic payloads, ignoring
/// types other than `&'static str` and `String`.
pub enum PanicMessage {
StaticStr(&'static str),
String(String),
Unknown,
}
impl From<Box<dyn Any + Send>> for PanicMessage {
fn from(payload: Box<dyn Any + Send + 'static>) -> Self {
if let Some(s) = payload.downcast_ref::<&'static str>() {
return PanicMessage::StaticStr(s);
}
if let Ok(s) = payload.downcast::<String>() {
return PanicMessage::String(*s);
}
PanicMessage::Unknown
}
}
impl Into<Box<dyn Any + Send>> for PanicMessage {
fn into(self) -> Box<dyn Any + Send> {
match self {
PanicMessage::StaticStr(s) => Box::new(s),
PanicMessage::String(s) => Box::new(s),
PanicMessage::Unknown => {
struct UnknownPanicMessage;
Box::new(UnknownPanicMessage)
}
}
}
}
impl PanicMessage {
pub fn as_str(&self) -> Option<&str> {
match self {
PanicMessage::StaticStr(s) => Some(s),
PanicMessage::String(s) => Some(s),
PanicMessage::Unknown => None,
}
}
}
impl<S> Encode<S> for PanicMessage {
fn encode(self, w: &mut Writer, s: &mut S) {
self.as_str().encode(w, s);
}
}
impl<S> DecodeMut<'_, '_, S> for PanicMessage {
fn decode(r: &mut Reader<'_>, s: &mut S) -> Self {
match Option::<String>::decode(r, s) {
Some(s) => PanicMessage::String(s),
None => PanicMessage::Unknown,
}
}
}

View file

@ -1,81 +0,0 @@
//! `Cell` variant for (scoped) existential lifetimes.
use std::cell::Cell;
use std::mem;
use std::ops::{Deref, DerefMut};
/// Type lambda application, with a lifetime.
#[allow(unused_lifetimes)]
pub trait ApplyL<'a> {
type Out;
}
/// Type lambda taking a lifetime, i.e., `Lifetime -> Type`.
pub trait LambdaL: for<'a> ApplyL<'a> {}
impl<T: for<'a> ApplyL<'a>> LambdaL for T {}
// HACK(eddyb) work around projection limitations with a newtype
// FIXME(#52812) replace with `&'a mut <T as ApplyL<'b>>::Out`
pub struct RefMutL<'a, 'b, T: LambdaL>(&'a mut <T as ApplyL<'b>>::Out);
impl<'a, 'b, T: LambdaL> Deref for RefMutL<'a, 'b, T> {
type Target = <T as ApplyL<'b>>::Out;
fn deref(&self) -> &Self::Target {
self.0
}
}
impl<'a, 'b, T: LambdaL> DerefMut for RefMutL<'a, 'b, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.0
}
}
pub struct ScopedCell<T: LambdaL>(Cell<<T as ApplyL<'static>>::Out>);
impl<T: LambdaL> ScopedCell<T> {
pub fn new(value: <T as ApplyL<'static>>::Out) -> Self {
ScopedCell(Cell::new(value))
}
/// Sets the value in `self` to `replacement` while
/// running `f`, which gets the old value, mutably.
/// The old value will be restored after `f` exits, even
/// by panic, including modifications made to it by `f`.
pub fn replace<'a, R>(
&self,
replacement: <T as ApplyL<'a>>::Out,
f: impl for<'b, 'c> FnOnce(RefMutL<'b, 'c, T>) -> R,
) -> R {
/// Wrapper that ensures that the cell always gets filled
/// (with the original state, optionally changed by `f`),
/// even if `f` had panicked.
struct PutBackOnDrop<'a, T: LambdaL> {
cell: &'a ScopedCell<T>,
value: Option<<T as ApplyL<'static>>::Out>,
}
impl<'a, T: LambdaL> Drop for PutBackOnDrop<'a, T> {
fn drop(&mut self) {
self.cell.0.set(self.value.take().unwrap());
}
}
let mut put_back_on_drop = PutBackOnDrop {
cell: self,
value: Some(self.0.replace(unsafe {
let erased = mem::transmute_copy(&replacement);
mem::forget(replacement);
erased
})),
};
f(RefMutL(put_back_on_drop.value.as_mut().unwrap()))
}
/// Sets the value in `self` to `value` while running `f`.
pub fn set<R>(&self, value: <T as ApplyL<'_>>::Out, f: impl FnOnce() -> R) -> R {
self.replace(value, |_| f())
}
}

View file

@ -1,352 +0,0 @@
//! Server-side traits.
use super::*;
// FIXME(eddyb) generate the definition of `HandleStore` in `server.rs`.
use super::client::HandleStore;
/// Declare an associated item of one of the traits below, optionally
/// adjusting it (i.e., adding bounds to types and default bodies to methods).
macro_rules! associated_item {
(type FreeFunctions) =>
(type FreeFunctions: 'static;);
(type TokenStream) =>
(type TokenStream: 'static + Clone;);
(type TokenStreamBuilder) =>
(type TokenStreamBuilder: 'static;);
(type TokenStreamIter) =>
(type TokenStreamIter: 'static + Clone;);
(type Group) =>
(type Group: 'static + Clone;);
(type Punct) =>
(type Punct: 'static + Copy + Eq + Hash;);
(type Ident) =>
(type Ident: 'static + Copy + Eq + Hash;);
(type Literal) =>
(type Literal: 'static + Clone;);
(type SourceFile) =>
(type SourceFile: 'static + Clone;);
(type MultiSpan) =>
(type MultiSpan: 'static;);
(type Diagnostic) =>
(type Diagnostic: 'static;);
(type Span) =>
(type Span: 'static + Copy + Eq + Hash;);
(fn drop(&mut self, $arg:ident: $arg_ty:ty)) =>
(fn drop(&mut self, $arg: $arg_ty) { mem::drop($arg) });
(fn clone(&mut self, $arg:ident: $arg_ty:ty) -> $ret_ty:ty) =>
(fn clone(&mut self, $arg: $arg_ty) -> $ret_ty { $arg.clone() });
($($item:tt)*) => ($($item)*;)
}
macro_rules! declare_server_traits {
($($name:ident {
$(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)*
}),* $(,)?) => {
pub trait Types {
$(associated_item!(type $name);)*
}
$(pub trait $name: Types {
$(associated_item!(fn $method(&mut self, $($arg: $arg_ty),*) $(-> $ret_ty)?);)*
})*
pub trait Server: Types $(+ $name)* {}
impl<S: Types $(+ $name)*> Server for S {}
}
}
with_api!(Self, self_, declare_server_traits);
pub(super) struct MarkedTypes<S: Types>(S);
macro_rules! define_mark_types_impls {
($($name:ident {
$(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)*
}),* $(,)?) => {
impl<S: Types> Types for MarkedTypes<S> {
$(type $name = Marked<S::$name, client::$name>;)*
}
$(impl<S: $name> $name for MarkedTypes<S> {
$(fn $method(&mut self, $($arg: $arg_ty),*) $(-> $ret_ty)? {
<_>::mark($name::$method(&mut self.0, $($arg.unmark()),*))
})*
})*
}
}
with_api!(Self, self_, define_mark_types_impls);
struct Dispatcher<S: Types> {
handle_store: HandleStore<S>,
server: S,
}
macro_rules! define_dispatcher_impl {
($($name:ident {
$(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)*
}),* $(,)?) => {
// FIXME(eddyb) `pub` only for `ExecutionStrategy` below.
pub trait DispatcherTrait {
// HACK(eddyb) these are here to allow `Self::$name` to work below.
$(type $name;)*
fn dispatch(&mut self, b: Buffer<u8>) -> Buffer<u8>;
}
impl<S: Server> DispatcherTrait for Dispatcher<MarkedTypes<S>> {
$(type $name = <MarkedTypes<S> as Types>::$name;)*
fn dispatch(&mut self, mut b: Buffer<u8>) -> Buffer<u8> {
let Dispatcher { handle_store, server } = self;
let mut reader = &b[..];
match api_tags::Method::decode(&mut reader, &mut ()) {
$(api_tags::Method::$name(m) => match m {
$(api_tags::$name::$method => {
let mut call_method = || {
reverse_decode!(reader, handle_store; $($arg: $arg_ty),*);
$name::$method(server, $($arg),*)
};
// HACK(eddyb) don't use `panic::catch_unwind` in a panic.
// If client and server happen to use the same `libstd`,
// `catch_unwind` asserts that the panic counter was 0,
// even when the closure passed to it didn't panic.
let r = if thread::panicking() {
Ok(call_method())
} else {
panic::catch_unwind(panic::AssertUnwindSafe(call_method))
.map_err(PanicMessage::from)
};
b.clear();
r.encode(&mut b, handle_store);
})*
}),*
}
b
}
}
}
}
with_api!(Self, self_, define_dispatcher_impl);
pub trait ExecutionStrategy {
fn run_bridge_and_client<D: Copy + Send + 'static>(
&self,
dispatcher: &mut impl DispatcherTrait,
input: Buffer<u8>,
run_client: extern "C" fn(Bridge<'_>, D) -> Buffer<u8>,
client_data: D,
force_show_panics: bool,
) -> Buffer<u8>;
}
pub struct SameThread;
impl ExecutionStrategy for SameThread {
fn run_bridge_and_client<D: Copy + Send + 'static>(
&self,
dispatcher: &mut impl DispatcherTrait,
input: Buffer<u8>,
run_client: extern "C" fn(Bridge<'_>, D) -> Buffer<u8>,
client_data: D,
force_show_panics: bool,
) -> Buffer<u8> {
let mut dispatch = |b| dispatcher.dispatch(b);
run_client(
Bridge { cached_buffer: input, dispatch: (&mut dispatch).into(), force_show_panics },
client_data,
)
}
}
// NOTE(eddyb) Two implementations are provided, the second one is a bit
// faster but neither is anywhere near as fast as same-thread execution.
pub struct CrossThread1;
impl ExecutionStrategy for CrossThread1 {
fn run_bridge_and_client<D: Copy + Send + 'static>(
&self,
dispatcher: &mut impl DispatcherTrait,
input: Buffer<u8>,
run_client: extern "C" fn(Bridge<'_>, D) -> Buffer<u8>,
client_data: D,
force_show_panics: bool,
) -> Buffer<u8> {
use std::sync::mpsc::channel;
let (req_tx, req_rx) = channel();
let (res_tx, res_rx) = channel();
let join_handle = thread::spawn(move || {
let mut dispatch = |b| {
req_tx.send(b).unwrap();
res_rx.recv().unwrap()
};
run_client(
Bridge {
cached_buffer: input,
dispatch: (&mut dispatch).into(),
force_show_panics,
},
client_data,
)
});
for b in req_rx {
res_tx.send(dispatcher.dispatch(b)).unwrap();
}
join_handle.join().unwrap()
}
}
pub struct CrossThread2;
impl ExecutionStrategy for CrossThread2 {
fn run_bridge_and_client<D: Copy + Send + 'static>(
&self,
dispatcher: &mut impl DispatcherTrait,
input: Buffer<u8>,
run_client: extern "C" fn(Bridge<'_>, D) -> Buffer<u8>,
client_data: D,
force_show_panics: bool,
) -> Buffer<u8> {
use std::sync::{Arc, Mutex};
enum State<T> {
Req(T),
Res(T),
}
let mut state = Arc::new(Mutex::new(State::Res(Buffer::new())));
let server_thread = thread::current();
let state2 = state.clone();
let join_handle = thread::spawn(move || {
let mut dispatch = |b| {
*state2.lock().unwrap() = State::Req(b);
server_thread.unpark();
loop {
thread::park();
if let State::Res(b) = &mut *state2.lock().unwrap() {
break b.take();
}
}
};
let r = run_client(
Bridge {
cached_buffer: input,
dispatch: (&mut dispatch).into(),
force_show_panics,
},
client_data,
);
// Wake up the server so it can exit the dispatch loop.
drop(state2);
server_thread.unpark();
r
});
// Check whether `state2` was dropped, to know when to stop.
while Arc::get_mut(&mut state).is_none() {
thread::park();
let mut b = match &mut *state.lock().unwrap() {
State::Req(b) => b.take(),
_ => continue,
};
b = dispatcher.dispatch(b.take());
*state.lock().unwrap() = State::Res(b);
join_handle.thread().unpark();
}
join_handle.join().unwrap()
}
}
fn run_server<
S: Server,
I: Encode<HandleStore<MarkedTypes<S>>>,
O: for<'a, 's> DecodeMut<'a, 's, HandleStore<MarkedTypes<S>>>,
D: Copy + Send + 'static,
>(
strategy: &impl ExecutionStrategy,
handle_counters: &'static client::HandleCounters,
server: S,
input: I,
run_client: extern "C" fn(Bridge<'_>, D) -> Buffer<u8>,
client_data: D,
force_show_panics: bool,
) -> Result<O, PanicMessage> {
let mut dispatcher =
Dispatcher { handle_store: HandleStore::new(handle_counters), server: MarkedTypes(server) };
let mut b = Buffer::new();
input.encode(&mut b, &mut dispatcher.handle_store);
b = strategy.run_bridge_and_client(
&mut dispatcher,
b,
run_client,
client_data,
force_show_panics,
);
Result::decode(&mut &b[..], &mut dispatcher.handle_store)
}
impl client::Client<fn(super::super::TokenStream) -> super::super::TokenStream> {
pub fn run<S: Server>(
&self,
strategy: &impl ExecutionStrategy,
server: S,
input: S::TokenStream,
force_show_panics: bool,
) -> Result<S::TokenStream, PanicMessage> {
let client::Client { get_handle_counters, run, f } = *self;
run_server(
strategy,
get_handle_counters(),
server,
<MarkedTypes<S> as Types>::TokenStream::mark(input),
run,
f,
force_show_panics,
)
.map(<MarkedTypes<S> as Types>::TokenStream::unmark)
}
}
impl
client::Client<
fn(super::super::TokenStream, super::super::TokenStream) -> super::super::TokenStream,
>
{
pub fn run<S: Server>(
&self,
strategy: &impl ExecutionStrategy,
server: S,
input: S::TokenStream,
input2: S::TokenStream,
force_show_panics: bool,
) -> Result<S::TokenStream, PanicMessage> {
let client::Client { get_handle_counters, run, f } = *self;
run_server(
strategy,
get_handle_counters(),
server,
(
<MarkedTypes<S> as Types>::TokenStream::mark(input),
<MarkedTypes<S> as Types>::TokenStream::mark(input2),
),
run,
f,
force_show_panics,
)
.map(<MarkedTypes<S> as Types>::TokenStream::unmark)
}
}

View file

@ -1,166 +0,0 @@
//! lib-proc-macro diagnostic
//!
//! Copy from <https://github.com/rust-lang/rust/blob/6050e523bae6de61de4e060facc43dc512adaccd/src/libproc_macro/diagnostic.rs>
//! augmented with removing unstable features
use super::Span;
/// An enum representing a diagnostic level.
#[derive(Copy, Clone, Debug)]
#[non_exhaustive]
pub enum Level {
/// An error.
Error,
/// A warning.
Warning,
/// A note.
Note,
/// A help message.
Help,
}
/// Trait implemented by types that can be converted into a set of `Span`s.
pub trait MultiSpan {
/// Converts `self` into a `Vec<Span>`.
fn into_spans(self) -> Vec<Span>;
}
impl MultiSpan for Span {
fn into_spans(self) -> Vec<Span> {
vec![self]
}
}
impl MultiSpan for Vec<Span> {
fn into_spans(self) -> Vec<Span> {
self
}
}
impl<'a> MultiSpan for &'a [Span] {
fn into_spans(self) -> Vec<Span> {
self.to_vec()
}
}
/// A structure representing a diagnostic message and associated children
/// messages.
#[derive(Clone, Debug)]
pub struct Diagnostic {
level: Level,
message: String,
spans: Vec<Span>,
children: Vec<Diagnostic>,
}
macro_rules! diagnostic_child_methods {
($spanned:ident, $regular:ident, $level:expr) => {
#[doc = concat!("Adds a new child diagnostics message to `self` with the [`",
stringify!($level), "`] level, and the given `spans` and `message`.")]
pub fn $spanned<S, T>(mut self, spans: S, message: T) -> Diagnostic
where
S: MultiSpan,
T: Into<String>,
{
self.children.push(Diagnostic::spanned(spans, $level, message));
self
}
#[doc = concat!("Adds a new child diagnostic message to `self` with the [`",
stringify!($level), "`] level, and the given `message`.")]
pub fn $regular<T: Into<String>>(mut self, message: T) -> Diagnostic {
self.children.push(Diagnostic::new($level, message));
self
}
};
}
/// Iterator over the children diagnostics of a `Diagnostic`.
#[derive(Debug, Clone)]
pub struct Children<'a>(std::slice::Iter<'a, Diagnostic>);
impl<'a> Iterator for Children<'a> {
type Item = &'a Diagnostic;
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
}
impl Diagnostic {
/// Creates a new diagnostic with the given `level` and `message`.
pub fn new<T: Into<String>>(level: Level, message: T) -> Diagnostic {
Diagnostic { level, message: message.into(), spans: vec![], children: vec![] }
}
/// Creates a new diagnostic with the given `level` and `message` pointing to
/// the given set of `spans`.
pub fn spanned<S, T>(spans: S, level: Level, message: T) -> Diagnostic
where
S: MultiSpan,
T: Into<String>,
{
Diagnostic { level, message: message.into(), spans: spans.into_spans(), children: vec![] }
}
diagnostic_child_methods!(span_error, error, Level::Error);
diagnostic_child_methods!(span_warning, warning, Level::Warning);
diagnostic_child_methods!(span_note, note, Level::Note);
diagnostic_child_methods!(span_help, help, Level::Help);
/// Returns the diagnostic `level` for `self`.
pub fn level(&self) -> Level {
self.level
}
/// Sets the level in `self` to `level`.
pub fn set_level(&mut self, level: Level) {
self.level = level;
}
/// Returns the message in `self`.
pub fn message(&self) -> &str {
&self.message
}
/// Sets the message in `self` to `message`.
pub fn set_message<T: Into<String>>(&mut self, message: T) {
self.message = message.into();
}
/// Returns the `Span`s in `self`.
pub fn spans(&self) -> &[Span] {
&self.spans
}
/// Sets the `Span`s in `self` to `spans`.
pub fn set_spans<S: MultiSpan>(&mut self, spans: S) {
self.spans = spans.into_spans();
}
/// Returns an iterator over the children diagnostics of `self`.
pub fn children(&self) -> Children<'_> {
Children(self.children.iter())
}
/// Emit the diagnostic.
pub fn emit(self) {
fn to_internal(spans: Vec<Span>) -> super::bridge::client::MultiSpan {
let mut multi_span = super::bridge::client::MultiSpan::new();
for span in spans {
multi_span.push(span.0);
}
multi_span
}
let mut diag = super::bridge::client::Diagnostic::new(
self.level,
&self.message[..],
to_internal(self.spans),
);
for c in self.children {
diag.sub(c.level, &c.message[..], to_internal(c.spans));
}
diag.emit();
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,140 +0,0 @@
//! # Quasiquoter
//! This file contains the implementation internals of the quasiquoter provided by `quote!`.
//! This quasiquoter uses macros 2.0 hygiene to reliably access
//! items from `proc_macro`, to build a `proc_macro::TokenStream`.
use super::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree};
macro_rules! quote_tt {
(($($t:tt)*)) => { Group::new(Delimiter::Parenthesis, quote!($($t)*)) };
([$($t:tt)*]) => { Group::new(Delimiter::Bracket, quote!($($t)*)) };
({$($t:tt)*}) => { Group::new(Delimiter::Brace, quote!($($t)*)) };
(,) => { Punct::new(',', Spacing::Alone) };
(.) => { Punct::new('.', Spacing::Alone) };
(:) => { Punct::new(':', Spacing::Alone) };
(;) => { Punct::new(';', Spacing::Alone) };
(!) => { Punct::new('!', Spacing::Alone) };
(<) => { Punct::new('<', Spacing::Alone) };
(>) => { Punct::new('>', Spacing::Alone) };
(&) => { Punct::new('&', Spacing::Alone) };
(=) => { Punct::new('=', Spacing::Alone) };
($i:ident) => { Ident::new(stringify!($i), Span::def_site()) };
}
macro_rules! quote_ts {
((@ $($t:tt)*)) => { $($t)* };
(::) => {
[
TokenTree::from(Punct::new(':', Spacing::Joint)),
TokenTree::from(Punct::new(':', Spacing::Alone)),
].iter()
.cloned()
.map(|mut x| {
x.set_span(Span::def_site());
x
})
.collect::<TokenStream>()
};
($t:tt) => { TokenTree::from(quote_tt!($t)) };
}
/// Simpler version of the real `quote!` macro, implemented solely
/// through `macro_rules`, for bootstrapping the real implementation
/// (see the `quote` function), which does not have access to the
/// real `quote!` macro due to the `proc_macro` crate not being
/// able to depend on itself.
///
/// Note: supported tokens are a subset of the real `quote!`, but
/// unquoting is different: instead of `$x`, this uses `(@ expr)`.
macro_rules! quote {
() => { TokenStream::new() };
($($t:tt)*) => {
[
$(TokenStream::from(quote_ts!($t)),)*
].iter().cloned().collect::<TokenStream>()
};
}
/// Quote a `TokenStream` into a `TokenStream`.
/// This is the actual implementation of the `quote!()` proc macro.
///
/// It is loaded by the compiler in `register_builtin_macros`.
pub fn quote(stream: TokenStream) -> TokenStream {
if stream.is_empty() {
return quote!(crate::TokenStream::new());
}
let proc_macro_crate = quote!(crate);
let mut after_dollar = false;
let tokens = stream
.into_iter()
.filter_map(|tree| {
if after_dollar {
after_dollar = false;
match tree {
TokenTree::Ident(_) => {
return Some(quote!(Into::<crate::TokenStream>::into(
Clone::clone(&(@ tree))),));
}
TokenTree::Punct(ref tt) if tt.as_char() == '$' => {}
_ => panic!("`$` must be followed by an ident or `$` in `quote!`"),
}
} else if let TokenTree::Punct(ref tt) = tree {
if tt.as_char() == '$' {
after_dollar = true;
return None;
}
}
Some(quote!(crate::TokenStream::from((@ match tree {
TokenTree::Punct(tt) => quote!(crate::TokenTree::Punct(crate::Punct::new(
(@ TokenTree::from(Literal::character(tt.as_char()))),
(@ match tt.spacing() {
Spacing::Alone => quote!(crate::Spacing::Alone),
Spacing::Joint => quote!(crate::Spacing::Joint),
}),
))),
TokenTree::Group(tt) => quote!(crate::TokenTree::Group(crate::Group::new(
(@ match tt.delimiter() {
Delimiter::Parenthesis => quote!(crate::Delimiter::Parenthesis),
Delimiter::Brace => quote!(crate::Delimiter::Brace),
Delimiter::Bracket => quote!(crate::Delimiter::Bracket),
Delimiter::None => quote!(crate::Delimiter::None),
}),
(@ quote(tt.stream())),
))),
TokenTree::Ident(tt) => quote!(crate::TokenTree::Ident(crate::Ident::new(
(@ TokenTree::from(Literal::string(&tt.to_string()))),
(@ quote_span(proc_macro_crate.clone(), tt.span())),
))),
TokenTree::Literal(tt) => quote!(crate::TokenTree::Literal({
let mut iter = (@ TokenTree::from(Literal::string(&tt.to_string())))
.parse::<crate::TokenStream>()
.unwrap()
.into_iter();
if let (Some(crate::TokenTree::Literal(mut lit)), None) =
(iter.next(), iter.next())
{
lit.set_span((@ quote_span(proc_macro_crate.clone(), tt.span())));
lit
} else {
unreachable!()
}
}))
})),))
})
.collect::<TokenStream>();
if after_dollar {
panic!("unexpected trailing `$` in `quote!`");
}
quote!([(@ tokens)].iter().cloned().collect::<crate::TokenStream>())
}
/// Quote a `Span` into a `TokenStream`.
/// This is needed to implement a custom quoter.
pub fn quote_span(proc_macro_crate: TokenStream, span: Span) -> TokenStream {
let id = span.save_span();
quote!((@ proc_macro_crate ) ::Span::recover_proc_macro_span((@ TokenTree::from(Literal::usize_unsuffixed(id)))))
}

View file

@ -1,822 +0,0 @@
//! Rustc proc-macro server implementation with tt
//!
//! Based on idea from <https://github.com/fedochet/rust-proc-macro-expander>
//! The lib-proc-macro server backend is `TokenStream`-agnostic, such that
//! we could provide any TokenStream implementation.
//! The original idea from fedochet is using proc-macro2 as backend,
//! we use tt instead for better integration with RA.
//!
//! FIXME: No span and source file information is implemented yet
use super::proc_macro::bridge::{self, server};
use std::collections::HashMap;
use std::hash::Hash;
use std::ops::Bound;
use std::{ascii, vec::IntoIter};
type Group = tt::Subtree;
type TokenTree = tt::TokenTree;
type Punct = tt::Punct;
type Spacing = tt::Spacing;
type Literal = tt::Literal;
type Span = tt::TokenId;
#[derive(Debug, Clone)]
pub struct TokenStream {
pub token_trees: Vec<TokenTree>,
}
impl TokenStream {
pub fn new() -> Self {
TokenStream { token_trees: Default::default() }
}
pub fn with_subtree(subtree: tt::Subtree) -> Self {
if subtree.delimiter.is_some() {
TokenStream { token_trees: vec![TokenTree::Subtree(subtree)] }
} else {
TokenStream { token_trees: subtree.token_trees }
}
}
pub fn into_subtree(self) -> tt::Subtree {
tt::Subtree { delimiter: None, token_trees: self.token_trees }
}
pub fn is_empty(&self) -> bool {
self.token_trees.is_empty()
}
}
/// Creates a token stream containing a single token tree.
impl From<TokenTree> for TokenStream {
fn from(tree: TokenTree) -> TokenStream {
TokenStream { token_trees: vec![tree] }
}
}
/// Collects a number of token trees into a single stream.
impl FromIterator<TokenTree> for TokenStream {
fn from_iter<I: IntoIterator<Item = TokenTree>>(trees: I) -> Self {
trees.into_iter().map(TokenStream::from).collect()
}
}
/// A "flattening" operation on token streams, collects token trees
/// from multiple token streams into a single stream.
impl FromIterator<TokenStream> for TokenStream {
fn from_iter<I: IntoIterator<Item = TokenStream>>(streams: I) -> Self {
let mut builder = TokenStreamBuilder::new();
streams.into_iter().for_each(|stream| builder.push(stream));
builder.build()
}
}
impl Extend<TokenTree> for TokenStream {
fn extend<I: IntoIterator<Item = TokenTree>>(&mut self, trees: I) {
self.extend(trees.into_iter().map(TokenStream::from));
}
}
impl Extend<TokenStream> for TokenStream {
fn extend<I: IntoIterator<Item = TokenStream>>(&mut self, streams: I) {
for item in streams {
for tkn in item {
match tkn {
tt::TokenTree::Subtree(subtree) if subtree.delimiter.is_none() => {
self.token_trees.extend(subtree.token_trees);
}
_ => {
self.token_trees.push(tkn);
}
}
}
}
}
}
#[derive(Clone)]
pub struct SourceFile {
// FIXME stub
}
type Level = super::proc_macro::Level;
type LineColumn = super::proc_macro::LineColumn;
/// A structure representing a diagnostic message and associated children
/// messages.
#[derive(Clone, Debug)]
pub struct Diagnostic {
level: Level,
message: String,
spans: Vec<Span>,
children: Vec<Diagnostic>,
}
impl Diagnostic {
/// Creates a new diagnostic with the given `level` and `message`.
pub fn new<T: Into<String>>(level: Level, message: T) -> Diagnostic {
Diagnostic { level, message: message.into(), spans: vec![], children: vec![] }
}
}
// Rustc Server Ident has to be `Copyable`
// We use a stub here for bypassing
#[derive(Hash, Eq, PartialEq, Copy, Clone)]
pub struct IdentId(u32);
#[derive(Clone, Hash, Eq, PartialEq)]
struct IdentData(tt::Ident);
#[derive(Default)]
struct IdentInterner {
idents: HashMap<IdentData, u32>,
ident_data: Vec<IdentData>,
}
impl IdentInterner {
fn intern(&mut self, data: &IdentData) -> u32 {
if let Some(index) = self.idents.get(data) {
return *index;
}
let index = self.idents.len() as u32;
self.ident_data.push(data.clone());
self.idents.insert(data.clone(), index);
index
}
fn get(&self, index: u32) -> &IdentData {
&self.ident_data[index as usize]
}
#[allow(unused)]
fn get_mut(&mut self, index: u32) -> &mut IdentData {
self.ident_data.get_mut(index as usize).expect("Should be consistent")
}
}
pub struct TokenStreamBuilder {
acc: TokenStream,
}
/// Public implementation details for the `TokenStream` type, such as iterators.
pub mod token_stream {
use std::str::FromStr;
use super::{TokenStream, TokenTree};
/// An iterator over `TokenStream`'s `TokenTree`s.
/// The iteration is "shallow", e.g., the iterator doesn't recurse into delimited groups,
/// and returns whole groups as token trees.
impl IntoIterator for TokenStream {
type Item = TokenTree;
type IntoIter = super::IntoIter<TokenTree>;
fn into_iter(self) -> Self::IntoIter {
self.token_trees.into_iter()
}
}
type LexError = String;
/// Attempts to break the string into tokens and parse those tokens into a token stream.
/// May fail for a number of reasons, for example, if the string contains unbalanced delimiters
/// or characters not existing in the language.
/// All tokens in the parsed stream get `Span::call_site()` spans.
///
/// NOTE: some errors may cause panics instead of returning `LexError`. We reserve the right to
/// change these errors into `LexError`s later.
impl FromStr for TokenStream {
type Err = LexError;
fn from_str(src: &str) -> Result<TokenStream, LexError> {
let (subtree, _token_map) =
mbe::parse_to_token_tree(src).ok_or("Failed to parse from mbe")?;
let subtree = subtree_replace_token_ids_with_unspecified(subtree);
Ok(TokenStream::with_subtree(subtree))
}
}
impl ToString for TokenStream {
fn to_string(&self) -> String {
tt::pretty(&self.token_trees)
}
}
fn subtree_replace_token_ids_with_unspecified(subtree: tt::Subtree) -> tt::Subtree {
tt::Subtree {
delimiter: subtree
.delimiter
.map(|d| tt::Delimiter { id: tt::TokenId::unspecified(), ..d }),
token_trees: subtree
.token_trees
.into_iter()
.map(token_tree_replace_token_ids_with_unspecified)
.collect(),
}
}
fn token_tree_replace_token_ids_with_unspecified(tt: tt::TokenTree) -> tt::TokenTree {
match tt {
tt::TokenTree::Leaf(leaf) => {
tt::TokenTree::Leaf(leaf_replace_token_ids_with_unspecified(leaf))
}
tt::TokenTree::Subtree(subtree) => {
tt::TokenTree::Subtree(subtree_replace_token_ids_with_unspecified(subtree))
}
}
}
fn leaf_replace_token_ids_with_unspecified(leaf: tt::Leaf) -> tt::Leaf {
match leaf {
tt::Leaf::Literal(lit) => {
tt::Leaf::Literal(tt::Literal { id: tt::TokenId::unspecified(), ..lit })
}
tt::Leaf::Punct(punct) => {
tt::Leaf::Punct(tt::Punct { id: tt::TokenId::unspecified(), ..punct })
}
tt::Leaf::Ident(ident) => {
tt::Leaf::Ident(tt::Ident { id: tt::TokenId::unspecified(), ..ident })
}
}
}
}
impl TokenStreamBuilder {
fn new() -> TokenStreamBuilder {
TokenStreamBuilder { acc: TokenStream::new() }
}
fn push(&mut self, stream: TokenStream) {
self.acc.extend(stream.into_iter())
}
fn build(self) -> TokenStream {
self.acc
}
}
pub struct FreeFunctions;
#[derive(Clone)]
pub struct TokenStreamIter {
trees: IntoIter<TokenTree>,
}
#[derive(Default)]
pub struct RustAnalyzer {
ident_interner: IdentInterner,
// FIXME: store span information here.
}
impl server::Types for RustAnalyzer {
type FreeFunctions = FreeFunctions;
type TokenStream = TokenStream;
type TokenStreamBuilder = TokenStreamBuilder;
type TokenStreamIter = TokenStreamIter;
type Group = Group;
type Punct = Punct;
type Ident = IdentId;
type Literal = Literal;
type SourceFile = SourceFile;
type Diagnostic = Diagnostic;
type Span = Span;
type MultiSpan = Vec<Span>;
}
impl server::FreeFunctions for RustAnalyzer {
fn track_env_var(&mut self, _var: &str, _value: Option<&str>) {
// FIXME: track env var accesses
// https://github.com/rust-lang/rust/pull/71858
}
fn track_path(&mut self, _path: &str) {}
}
impl server::TokenStream for RustAnalyzer {
fn new(&mut self) -> Self::TokenStream {
Self::TokenStream::new()
}
fn is_empty(&mut self, stream: &Self::TokenStream) -> bool {
stream.is_empty()
}
fn from_str(&mut self, src: &str) -> Self::TokenStream {
use std::str::FromStr;
Self::TokenStream::from_str(src).expect("cannot parse string")
}
fn to_string(&mut self, stream: &Self::TokenStream) -> String {
stream.to_string()
}
fn from_token_tree(
&mut self,
tree: bridge::TokenTree<Self::Group, Self::Punct, Self::Ident, Self::Literal>,
) -> Self::TokenStream {
match tree {
bridge::TokenTree::Group(group) => {
let tree = TokenTree::from(group);
Self::TokenStream::from_iter(vec![tree])
}
bridge::TokenTree::Ident(IdentId(index)) => {
let IdentData(ident) = self.ident_interner.get(index).clone();
let ident: tt::Ident = ident;
let leaf = tt::Leaf::from(ident);
let tree = TokenTree::from(leaf);
Self::TokenStream::from_iter(vec![tree])
}
bridge::TokenTree::Literal(literal) => {
let leaf = tt::Leaf::from(literal);
let tree = TokenTree::from(leaf);
Self::TokenStream::from_iter(vec![tree])
}
bridge::TokenTree::Punct(p) => {
let leaf = tt::Leaf::from(p);
let tree = TokenTree::from(leaf);
Self::TokenStream::from_iter(vec![tree])
}
}
}
fn into_iter(&mut self, stream: Self::TokenStream) -> Self::TokenStreamIter {
let trees: Vec<TokenTree> = stream.into_iter().collect();
TokenStreamIter { trees: trees.into_iter() }
}
fn expand_expr(&mut self, self_: &Self::TokenStream) -> Result<Self::TokenStream, ()> {
Ok(self_.clone())
}
}
impl server::TokenStreamBuilder for RustAnalyzer {
fn new(&mut self) -> Self::TokenStreamBuilder {
Self::TokenStreamBuilder::new()
}
fn push(&mut self, builder: &mut Self::TokenStreamBuilder, stream: Self::TokenStream) {
builder.push(stream)
}
fn build(&mut self, builder: Self::TokenStreamBuilder) -> Self::TokenStream {
builder.build()
}
}
impl server::TokenStreamIter for RustAnalyzer {
fn next(
&mut self,
iter: &mut Self::TokenStreamIter,
) -> Option<bridge::TokenTree<Self::Group, Self::Punct, Self::Ident, Self::Literal>> {
iter.trees.next().map(|tree| match tree {
TokenTree::Subtree(group) => bridge::TokenTree::Group(group),
TokenTree::Leaf(tt::Leaf::Ident(ident)) => {
bridge::TokenTree::Ident(IdentId(self.ident_interner.intern(&IdentData(ident))))
}
TokenTree::Leaf(tt::Leaf::Literal(literal)) => bridge::TokenTree::Literal(literal),
TokenTree::Leaf(tt::Leaf::Punct(punct)) => bridge::TokenTree::Punct(punct),
})
}
}
fn delim_to_internal(d: bridge::Delimiter) -> Option<tt::Delimiter> {
let kind = match d {
bridge::Delimiter::Parenthesis => tt::DelimiterKind::Parenthesis,
bridge::Delimiter::Brace => tt::DelimiterKind::Brace,
bridge::Delimiter::Bracket => tt::DelimiterKind::Bracket,
bridge::Delimiter::None => return None,
};
Some(tt::Delimiter { id: tt::TokenId::unspecified(), kind })
}
fn delim_to_external(d: Option<tt::Delimiter>) -> bridge::Delimiter {
match d.map(|it| it.kind) {
Some(tt::DelimiterKind::Parenthesis) => bridge::Delimiter::Parenthesis,
Some(tt::DelimiterKind::Brace) => bridge::Delimiter::Brace,
Some(tt::DelimiterKind::Bracket) => bridge::Delimiter::Bracket,
None => bridge::Delimiter::None,
}
}
fn spacing_to_internal(spacing: bridge::Spacing) -> Spacing {
match spacing {
bridge::Spacing::Alone => Spacing::Alone,
bridge::Spacing::Joint => Spacing::Joint,
}
}
fn spacing_to_external(spacing: Spacing) -> bridge::Spacing {
match spacing {
Spacing::Alone => bridge::Spacing::Alone,
Spacing::Joint => bridge::Spacing::Joint,
}
}
impl server::Group for RustAnalyzer {
fn new(&mut self, delimiter: bridge::Delimiter, stream: Self::TokenStream) -> Self::Group {
Self::Group { delimiter: delim_to_internal(delimiter), token_trees: stream.token_trees }
}
fn delimiter(&mut self, group: &Self::Group) -> bridge::Delimiter {
delim_to_external(group.delimiter)
}
// NOTE: Return value of do not include delimiter
fn stream(&mut self, group: &Self::Group) -> Self::TokenStream {
TokenStream { token_trees: group.token_trees.clone() }
}
fn span(&mut self, group: &Self::Group) -> Self::Span {
group.delimiter.map(|it| it.id).unwrap_or_else(tt::TokenId::unspecified)
}
fn set_span(&mut self, group: &mut Self::Group, span: Self::Span) {
if let Some(delim) = &mut group.delimiter {
delim.id = span;
}
}
fn span_open(&mut self, group: &Self::Group) -> Self::Span {
// FIXME we only store one `TokenId` for the delimiters
group.delimiter.map(|it| it.id).unwrap_or_else(tt::TokenId::unspecified)
}
fn span_close(&mut self, group: &Self::Group) -> Self::Span {
// FIXME we only store one `TokenId` for the delimiters
group.delimiter.map(|it| it.id).unwrap_or_else(tt::TokenId::unspecified)
}
}
impl server::Punct for RustAnalyzer {
fn new(&mut self, ch: char, spacing: bridge::Spacing) -> Self::Punct {
tt::Punct {
char: ch,
spacing: spacing_to_internal(spacing),
id: tt::TokenId::unspecified(),
}
}
fn as_char(&mut self, punct: Self::Punct) -> char {
punct.char
}
fn spacing(&mut self, punct: Self::Punct) -> bridge::Spacing {
spacing_to_external(punct.spacing)
}
fn span(&mut self, punct: Self::Punct) -> Self::Span {
punct.id
}
fn with_span(&mut self, punct: Self::Punct, span: Self::Span) -> Self::Punct {
tt::Punct { id: span, ..punct }
}
}
impl server::Ident for RustAnalyzer {
fn new(&mut self, string: &str, span: Self::Span, is_raw: bool) -> Self::Ident {
IdentId(self.ident_interner.intern(&IdentData(tt::Ident::new_with_is_raw(
string.into(),
span,
is_raw,
))))
}
fn span(&mut self, ident: Self::Ident) -> Self::Span {
self.ident_interner.get(ident.0).0.id
}
fn with_span(&mut self, ident: Self::Ident, span: Self::Span) -> Self::Ident {
let data = self.ident_interner.get(ident.0);
let new = IdentData(tt::Ident { id: span, ..data.0.clone() });
IdentId(self.ident_interner.intern(&new))
}
}
impl server::Literal for RustAnalyzer {
fn debug_kind(&mut self, _literal: &Self::Literal) -> String {
// r-a: debug_kind and suffix are unsupported; corresponding client code has been changed to not call these.
// They must still be present to be ABI-compatible and work with upstream proc_macro.
"".to_owned()
}
fn from_str(&mut self, s: &str) -> Result<Self::Literal, ()> {
Ok(Literal { text: s.into(), id: tt::TokenId::unspecified() })
}
fn symbol(&mut self, literal: &Self::Literal) -> String {
literal.text.to_string()
}
fn suffix(&mut self, _literal: &Self::Literal) -> Option<String> {
None
}
fn to_string(&mut self, literal: &Self::Literal) -> String {
literal.to_string()
}
fn integer(&mut self, n: &str) -> Self::Literal {
let n = match n.parse::<i128>() {
Ok(n) => n.to_string(),
Err(_) => n.parse::<u128>().unwrap().to_string(),
};
Literal { text: n.into(), id: tt::TokenId::unspecified() }
}
fn typed_integer(&mut self, n: &str, kind: &str) -> Self::Literal {
macro_rules! def_suffixed_integer {
($kind:ident, $($ty:ty),*) => {
match $kind {
$(
stringify!($ty) => {
let n: $ty = n.parse().unwrap();
format!(concat!("{}", stringify!($ty)), n)
}
)*
_ => unimplemented!("unknown args for typed_integer: n {}, kind {}", n, $kind),
}
}
}
let text = def_suffixed_integer! {kind, u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize};
Literal { text: text.into(), id: tt::TokenId::unspecified() }
}
fn float(&mut self, n: &str) -> Self::Literal {
let n: f64 = n.parse().unwrap();
let mut text = f64::to_string(&n);
if !text.contains('.') {
text += ".0"
}
Literal { text: text.into(), id: tt::TokenId::unspecified() }
}
fn f32(&mut self, n: &str) -> Self::Literal {
let n: f32 = n.parse().unwrap();
let text = format!("{n}f32");
Literal { text: text.into(), id: tt::TokenId::unspecified() }
}
fn f64(&mut self, n: &str) -> Self::Literal {
let n: f64 = n.parse().unwrap();
let text = format!("{n}f64");
Literal { text: text.into(), id: tt::TokenId::unspecified() }
}
fn string(&mut self, string: &str) -> Self::Literal {
let mut escaped = String::new();
for ch in string.chars() {
escaped.extend(ch.escape_debug());
}
Literal { text: format!("\"{escaped}\"").into(), id: tt::TokenId::unspecified() }
}
fn character(&mut self, ch: char) -> Self::Literal {
Literal { text: format!("'{ch}'").into(), id: tt::TokenId::unspecified() }
}
fn byte_string(&mut self, bytes: &[u8]) -> Self::Literal {
let string = bytes
.iter()
.cloned()
.flat_map(ascii::escape_default)
.map(Into::<char>::into)
.collect::<String>();
Literal { text: format!("b\"{string}\"").into(), id: tt::TokenId::unspecified() }
}
fn span(&mut self, literal: &Self::Literal) -> Self::Span {
literal.id
}
fn set_span(&mut self, literal: &mut Self::Literal, span: Self::Span) {
literal.id = span;
}
fn subspan(
&mut self,
_literal: &Self::Literal,
_start: Bound<usize>,
_end: Bound<usize>,
) -> Option<Self::Span> {
// FIXME handle span
None
}
}
impl server::SourceFile for RustAnalyzer {
// FIXME these are all stubs
fn eq(&mut self, _file1: &Self::SourceFile, _file2: &Self::SourceFile) -> bool {
true
}
fn path(&mut self, _file: &Self::SourceFile) -> String {
String::new()
}
fn is_real(&mut self, _file: &Self::SourceFile) -> bool {
true
}
}
impl server::Diagnostic for RustAnalyzer {
fn new(&mut self, level: Level, msg: &str, spans: Self::MultiSpan) -> Self::Diagnostic {
let mut diag = Diagnostic::new(level, msg);
diag.spans = spans;
diag
}
fn sub(
&mut self,
_diag: &mut Self::Diagnostic,
_level: Level,
_msg: &str,
_spans: Self::MultiSpan,
) {
// FIXME handle diagnostic
//
}
fn emit(&mut self, _diag: Self::Diagnostic) {
// FIXME handle diagnostic
// diag.emit()
}
}
impl server::Span for RustAnalyzer {
fn debug(&mut self, span: Self::Span) -> String {
format!("{:?}", span.0)
}
fn def_site(&mut self) -> Self::Span {
// MySpan(self.span_interner.intern(&MySpanData(Span::def_site())))
// FIXME handle span
tt::TokenId::unspecified()
}
fn call_site(&mut self) -> Self::Span {
// MySpan(self.span_interner.intern(&MySpanData(Span::call_site())))
// FIXME handle span
tt::TokenId::unspecified()
}
fn source_file(&mut self, _span: Self::Span) -> Self::SourceFile {
SourceFile {}
}
fn save_span(&mut self, _span: Self::Span) -> usize {
// FIXME stub
0
}
fn recover_proc_macro_span(&mut self, _id: usize) -> Self::Span {
// FIXME stub
tt::TokenId::unspecified()
}
/// Recent feature, not yet in the proc_macro
///
/// See PR:
/// https://github.com/rust-lang/rust/pull/55780
fn source_text(&mut self, _span: Self::Span) -> Option<String> {
None
}
fn parent(&mut self, _span: Self::Span) -> Option<Self::Span> {
// FIXME handle span
None
}
fn source(&mut self, span: Self::Span) -> Self::Span {
// FIXME handle span
span
}
fn start(&mut self, _span: Self::Span) -> LineColumn {
// FIXME handle span
LineColumn { line: 0, column: 0 }
}
fn end(&mut self, _span: Self::Span) -> LineColumn {
// FIXME handle span
LineColumn { line: 0, column: 0 }
}
fn join(&mut self, first: Self::Span, _second: Self::Span) -> Option<Self::Span> {
// Just return the first span again, because some macros will unwrap the result.
Some(first)
}
fn resolved_at(&mut self, _span: Self::Span, _at: Self::Span) -> Self::Span {
// FIXME handle span
tt::TokenId::unspecified()
}
fn mixed_site(&mut self) -> Self::Span {
// FIXME handle span
tt::TokenId::unspecified()
}
fn after(&mut self, _self_: Self::Span) -> Self::Span {
tt::TokenId::unspecified()
}
fn before(&mut self, _self_: Self::Span) -> Self::Span {
tt::TokenId::unspecified()
}
}
impl server::MultiSpan for RustAnalyzer {
fn new(&mut self) -> Self::MultiSpan {
// FIXME handle span
vec![]
}
fn push(&mut self, other: &mut Self::MultiSpan, span: Self::Span) {
//TODP
other.push(span)
}
}
#[cfg(test)]
mod tests {
use super::super::proc_macro::bridge::server::Literal;
use super::*;
#[test]
fn test_ra_server_literals() {
let mut srv = RustAnalyzer { ident_interner: IdentInterner::default() };
assert_eq!(srv.integer("1234").text, "1234");
assert_eq!(srv.typed_integer("12", "u8").text, "12u8");
assert_eq!(srv.typed_integer("255", "u16").text, "255u16");
assert_eq!(srv.typed_integer("1234", "u32").text, "1234u32");
assert_eq!(srv.typed_integer("15846685", "u64").text, "15846685u64");
assert_eq!(srv.typed_integer("15846685258", "u128").text, "15846685258u128");
assert_eq!(srv.typed_integer("156788984", "usize").text, "156788984usize");
assert_eq!(srv.typed_integer("127", "i8").text, "127i8");
assert_eq!(srv.typed_integer("255", "i16").text, "255i16");
assert_eq!(srv.typed_integer("1234", "i32").text, "1234i32");
assert_eq!(srv.typed_integer("15846685", "i64").text, "15846685i64");
assert_eq!(srv.typed_integer("15846685258", "i128").text, "15846685258i128");
assert_eq!(srv.float("0").text, "0.0");
assert_eq!(srv.float("15684.5867").text, "15684.5867");
assert_eq!(srv.f32("15684.58").text, "15684.58f32");
assert_eq!(srv.f64("15684.58").text, "15684.58f64");
assert_eq!(srv.string("hello_world").text, "\"hello_world\"");
assert_eq!(srv.character('c').text, "'c'");
assert_eq!(srv.byte_string(b"1234586\x88").text, "b\"1234586\\x88\"");
// u128::max
assert_eq!(
srv.integer("340282366920938463463374607431768211455").text,
"340282366920938463463374607431768211455"
);
// i128::min
assert_eq!(
srv.integer("-170141183460469231731687303715884105728").text,
"-170141183460469231731687303715884105728"
);
}
#[test]
fn test_ra_server_to_string() {
let s = TokenStream {
token_trees: vec![
tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
text: "struct".into(),
id: tt::TokenId::unspecified(),
})),
tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
text: "T".into(),
id: tt::TokenId::unspecified(),
})),
tt::TokenTree::Subtree(tt::Subtree {
delimiter: Some(tt::Delimiter {
id: tt::TokenId::unspecified(),
kind: tt::DelimiterKind::Brace,
}),
token_trees: vec![],
}),
],
};
assert_eq!(s.to_string(), "struct T {}");
}
#[test]
fn test_ra_server_from_str() {
use std::str::FromStr;
let subtree_paren_a = tt::TokenTree::Subtree(tt::Subtree {
delimiter: Some(tt::Delimiter {
id: tt::TokenId::unspecified(),
kind: tt::DelimiterKind::Parenthesis,
}),
token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
text: "a".into(),
id: tt::TokenId::unspecified(),
}))],
});
let t1 = TokenStream::from_str("(a)").unwrap();
assert_eq!(t1.token_trees.len(), 1);
assert_eq!(t1.token_trees[0], subtree_paren_a);
let t2 = TokenStream::from_str("(a);").unwrap();
assert_eq!(t2.token_trees.len(), 2);
assert_eq!(t2.token_trees[0], subtree_paren_a);
let underscore = TokenStream::from_str("_").unwrap();
assert_eq!(
underscore.token_trees[0],
tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
text: "_".into(),
id: tt::TokenId::unspecified(),
}))
);
}
}

View file

@ -23,7 +23,6 @@
//! for the relevant versions of the rust compiler
//!
mod abi_1_58;
mod abi_1_63;
#[cfg(feature = "sysroot-abi")]
mod abi_sysroot;
@ -36,7 +35,6 @@ include!(concat!(env!("OUT_DIR"), "/rustc_version.rs"));
pub(crate) use abi_sysroot::TokenStream as TestTokenStream;
use super::dylib::LoadProcMacroDylibError;
pub(crate) use abi_1_58::Abi as Abi_1_58;
pub(crate) use abi_1_63::Abi as Abi_1_63;
#[cfg(feature = "sysroot-abi")]
pub(crate) use abi_sysroot::Abi as Abi_Sysroot;
@ -54,7 +52,6 @@ impl PanicMessage {
}
pub(crate) enum Abi {
Abi1_58(Abi_1_58),
Abi1_63(Abi_1_63),
#[cfg(feature = "sysroot-abi")]
AbiSysroot(Abi_Sysroot),
@ -109,10 +106,6 @@ impl Abi {
// FIXME: this should use exclusive ranges when they're stable
// https://github.com/rust-lang/rust/issues/37854
match (info.version.0, info.version.1) {
(1, 58..=62) => {
let inner = unsafe { Abi_1_58::from_lib(lib, symbol_name) }?;
Ok(Abi::Abi1_58(inner))
}
(1, 63) => {
let inner = unsafe { Abi_1_63::from_lib(lib, symbol_name) }?;
Ok(Abi::Abi1_63(inner))
@ -128,7 +121,6 @@ impl Abi {
attributes: Option<&tt::Subtree>,
) -> Result<tt::Subtree, PanicMessage> {
match self {
Self::Abi1_58(abi) => abi.expand(macro_name, macro_body, attributes),
Self::Abi1_63(abi) => abi.expand(macro_name, macro_body, attributes),
#[cfg(feature = "sysroot-abi")]
Self::AbiSysroot(abi) => abi.expand(macro_name, macro_body, attributes),
@ -137,7 +129,6 @@ impl Abi {
pub fn list_macros(&self) -> Vec<(String, ProcMacroKind)> {
match self {
Self::Abi1_58(abi) => abi.list_macros(),
Self::Abi1_63(abi) => abi.list_macros(),
#[cfg(feature = "sysroot-abi")]
Self::AbiSysroot(abi) => abi.list_macros(),