about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlex Good <alex@memoryandthought.me>2021-07-12 15:47:47 +0100
committerAlex Good <alex@memoryandthought.me>2021-07-12 16:05:45 +0100
commite240eb67a86bb4deff2762e3c46f47278ccd975c (patch)
tree23791831e4261758d72f3cf8b992d73788bd5ee8
parent14a51d28b530331151e636986e57912da7e406ec (diff)
downloadrust-e240eb67a86bb4deff2762e3c46f47278ccd975c.tar.gz
rust-e240eb67a86bb4deff2762e3c46f47278ccd975c.zip
Introduce proc_macro_srv::abis, impl 1.47 and 1.55
Rather than a "Stable" and "Nightly" ABI we instead name ABIs based on
the version of the rust compiler in which they were introduced. We place
these ABIs in a new module - `proc_macro_srv::abis` - where we also add
some mchinery to abstract over ABIs. This should make it easy to add new
ABIs at a later date as the rust compiler evolves.
-rw-r--r--crates/proc_macro_srv/src/abis/abi_1_47/mod.rs106
-rw-r--r--crates/proc_macro_srv/src/abis/abi_1_47/proc_macro/bridge/buffer.rs (renamed from crates/proc_macro_srv/src/proc_macro/bridge/buffer.rs)0
-rw-r--r--crates/proc_macro_srv/src/abis/abi_1_47/proc_macro/bridge/client.rs (renamed from crates/proc_macro_srv/src/proc_macro/bridge/client.rs)29
-rw-r--r--crates/proc_macro_srv/src/abis/abi_1_47/proc_macro/bridge/closure.rs (renamed from crates/proc_macro_srv/src/proc_macro/bridge/closure.rs)0
-rw-r--r--crates/proc_macro_srv/src/abis/abi_1_47/proc_macro/bridge/handle.rs (renamed from crates/proc_macro_srv/src/proc_macro/bridge/handle.rs)0
-rw-r--r--crates/proc_macro_srv/src/abis/abi_1_47/proc_macro/bridge/mod.rs (renamed from crates/proc_macro_srv/src/proc_macro/bridge/mod.rs)2
-rw-r--r--crates/proc_macro_srv/src/abis/abi_1_47/proc_macro/bridge/rpc.rs (renamed from crates/proc_macro_srv/src/proc_macro/bridge/rpc.rs)0
-rw-r--r--crates/proc_macro_srv/src/abis/abi_1_47/proc_macro/bridge/scoped_cell.rs (renamed from crates/proc_macro_srv/src/proc_macro/bridge/scoped_cell.rs)0
-rw-r--r--crates/proc_macro_srv/src/abis/abi_1_47/proc_macro/bridge/server.rs (renamed from crates/proc_macro_srv/src/proc_macro/bridge/server.rs)5
-rw-r--r--crates/proc_macro_srv/src/abis/abi_1_47/proc_macro/diagnostic.rs (renamed from crates/proc_macro_srv/src/proc_macro_nightly/diagnostic.rs)0
-rw-r--r--crates/proc_macro_srv/src/abis/abi_1_47/proc_macro/mod.rs (renamed from crates/proc_macro_srv/src/proc_macro/mod.rs)2
-rw-r--r--crates/proc_macro_srv/src/abis/abi_1_47/rustc_server.rs (renamed from crates/proc_macro_srv/src/rustc_server.rs)10
-rw-r--r--crates/proc_macro_srv/src/abis/abi_1_55/mod.rs104
-rw-r--r--crates/proc_macro_srv/src/abis/abi_1_55/proc_macro/bridge/buffer.rs (renamed from crates/proc_macro_srv/src/proc_macro_nightly/bridge/buffer.rs)0
-rw-r--r--crates/proc_macro_srv/src/abis/abi_1_55/proc_macro/bridge/client.rs (renamed from crates/proc_macro_srv/src/proc_macro_nightly/bridge/client.rs)29
-rw-r--r--crates/proc_macro_srv/src/abis/abi_1_55/proc_macro/bridge/closure.rs (renamed from crates/proc_macro_srv/src/proc_macro_nightly/bridge/closure.rs)0
-rw-r--r--crates/proc_macro_srv/src/abis/abi_1_55/proc_macro/bridge/handle.rs (renamed from crates/proc_macro_srv/src/proc_macro_nightly/bridge/handle.rs)0
-rw-r--r--crates/proc_macro_srv/src/abis/abi_1_55/proc_macro/bridge/mod.rs (renamed from crates/proc_macro_srv/src/proc_macro_nightly/bridge/mod.rs)0
-rw-r--r--crates/proc_macro_srv/src/abis/abi_1_55/proc_macro/bridge/rpc.rs (renamed from crates/proc_macro_srv/src/proc_macro_nightly/bridge/rpc.rs)0
-rw-r--r--crates/proc_macro_srv/src/abis/abi_1_55/proc_macro/bridge/scoped_cell.rs (renamed from crates/proc_macro_srv/src/proc_macro_nightly/bridge/scoped_cell.rs)0
-rw-r--r--crates/proc_macro_srv/src/abis/abi_1_55/proc_macro/bridge/server.rs (renamed from crates/proc_macro_srv/src/proc_macro_nightly/bridge/server.rs)5
-rw-r--r--crates/proc_macro_srv/src/abis/abi_1_55/proc_macro/diagnostic.rs (renamed from crates/proc_macro_srv/src/proc_macro/diagnostic.rs)8
-rw-r--r--crates/proc_macro_srv/src/abis/abi_1_55/proc_macro/mod.rs (renamed from crates/proc_macro_srv/src/proc_macro_nightly/mod.rs)0
-rw-r--r--crates/proc_macro_srv/src/abis/abi_1_55/rustc_server.rs (renamed from crates/proc_macro_srv/src/rustc_server_nightly.rs)10
-rw-r--r--crates/proc_macro_srv/src/abis/mod.rs97
-rw-r--r--crates/proc_macro_srv/src/dylib.rs278
-rw-r--r--crates/proc_macro_srv/src/lib.rs22
-rw-r--r--crates/proc_macro_srv/src/tests/utils.rs10
28 files changed, 390 insertions, 327 deletions
diff --git a/crates/proc_macro_srv/src/abis/abi_1_47/mod.rs b/crates/proc_macro_srv/src/abis/abi_1_47/mod.rs
new file mode 100644
index 00000000000..6bbdcc58686
--- /dev/null
+++ b/crates/proc_macro_srv/src/abis/abi_1_47/mod.rs
@@ -0,0 +1,106 @@
+//! Macro ABI for version 1.47 of rustc
+
+#[allow(dead_code)]
+#[doc(hidden)]
+mod proc_macro;
+
+#[allow(dead_code)]
+#[doc(hidden)]
+mod rustc_server;
+use libloading::Library;
+
+use proc_macro_api::ProcMacroKind;
+
+use super::PanicMessage;
+
+pub use rustc_server::TokenStream;
+
+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 = rustc_server::TokenStream::with_subtree(macro_body.clone());
+
+        let parsed_attributes = attributes.map_or(rustc_server::TokenStream::new(), |attr| {
+            rustc_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,
+                        rustc_server::Rustc::default(),
+                        parsed_body,
+                        false,
+                    );
+                    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,
+                        rustc_server::Rustc::default(),
+                        parsed_body,
+                        false,
+                    );
+                    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,
+                        rustc_server::Rustc::default(),
+                        parsed_attributes,
+                        parsed_body,
+                        false,
+                    );
+                    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()
+    }
+}
diff --git a/crates/proc_macro_srv/src/proc_macro/bridge/buffer.rs b/crates/proc_macro_srv/src/abis/abi_1_47/proc_macro/bridge/buffer.rs
index 3b2afe01f5b..3b2afe01f5b 100644
--- a/crates/proc_macro_srv/src/proc_macro/bridge/buffer.rs
+++ b/crates/proc_macro_srv/src/abis/abi_1_47/proc_macro/bridge/buffer.rs
diff --git a/crates/proc_macro_srv/src/proc_macro/bridge/client.rs b/crates/proc_macro_srv/src/abis/abi_1_47/proc_macro/bridge/client.rs
index c135cf7a237..9f74fb06689 100644
--- a/crates/proc_macro_srv/src/proc_macro/bridge/client.rs
+++ b/crates/proc_macro_srv/src/abis/abi_1_47/proc_macro/bridge/client.rs
@@ -3,6 +3,7 @@
 //! Copy from <https://github.com/rust-lang/rust/blob/6050e523bae6de61de4e060facc43dc512adaccd/src/libproc_macro/bridge/client.rs>
 //! augmented with removing unstable features
 
+use super::super::TokenStream as CrateTokenStream;
 use super::*;
 
 macro_rules! define_handles {
@@ -401,26 +402,26 @@ fn run_client<A: for<'a, 's> DecodeMut<'a, 's, ()>, R: Encode<()>>(
     b
 }
 
-impl Client<fn(crate::TokenStream) -> crate::TokenStream> {
-    pub fn expand1(f: fn(crate::TokenStream) -> crate::TokenStream) -> Self {
+impl Client<fn(CrateTokenStream) -> CrateTokenStream> {
+    pub fn expand1(f: fn(CrateTokenStream) -> CrateTokenStream) -> Self {
         extern "C" fn run(
             bridge: Bridge<'_>,
-            f: impl FnOnce(crate::TokenStream) -> crate::TokenStream,
+            f: impl FnOnce(CrateTokenStream) -> CrateTokenStream,
         ) -> Buffer<u8> {
-            run_client(bridge, |input| f(crate::TokenStream(input)).0)
+            run_client(bridge, |input| f(CrateTokenStream(input)).0)
         }
         Client { get_handle_counters: HandleCounters::get, run, f }
     }
 }
 
-impl Client<fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream> {
-    pub fn expand2(f: fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream) -> Self {
+impl Client<fn(CrateTokenStream, CrateTokenStream) -> CrateTokenStream> {
+    pub fn expand2(f: fn(CrateTokenStream, CrateTokenStream) -> CrateTokenStream) -> Self {
         extern "C" fn run(
             bridge: Bridge<'_>,
-            f: impl FnOnce(crate::TokenStream, crate::TokenStream) -> crate::TokenStream,
+            f: impl FnOnce(CrateTokenStream, CrateTokenStream) -> CrateTokenStream,
         ) -> Buffer<u8> {
             run_client(bridge, |(input, input2)| {
-                f(crate::TokenStream(input), crate::TokenStream(input2)).0
+                f(CrateTokenStream(input), CrateTokenStream(input2)).0
             })
         }
         Client { get_handle_counters: HandleCounters::get, run, f }
@@ -433,17 +434,17 @@ pub enum ProcMacro {
     CustomDerive {
         trait_name: &'static str,
         attributes: &'static [&'static str],
-        client: Client<fn(crate::TokenStream) -> crate::TokenStream>,
+        client: Client<fn(CrateTokenStream) -> CrateTokenStream>,
     },
 
     Attr {
         name: &'static str,
-        client: Client<fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream>,
+        client: Client<fn(CrateTokenStream, CrateTokenStream) -> CrateTokenStream>,
     },
 
     Bang {
         name: &'static str,
-        client: Client<fn(crate::TokenStream) -> crate::TokenStream>,
+        client: Client<fn(CrateTokenStream) -> CrateTokenStream>,
     },
 }
 
@@ -465,19 +466,19 @@ impl ProcMacro {
     pub fn custom_derive(
         trait_name: &'static str,
         attributes: &'static [&'static str],
-        expand: fn(crate::TokenStream) -> crate::TokenStream,
+        expand: fn(CrateTokenStream) -> CrateTokenStream,
     ) -> Self {
         ProcMacro::CustomDerive { trait_name, attributes, client: Client::expand1(expand) }
     }
 
     pub fn attr(
         name: &'static str,
-        expand: fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream,
+        expand: fn(CrateTokenStream, CrateTokenStream) -> CrateTokenStream,
     ) -> Self {
         ProcMacro::Attr { name, client: Client::expand2(expand) }
     }
 
-    pub fn bang(name: &'static str, expand: fn(crate::TokenStream) -> crate::TokenStream) -> Self {
+    pub fn bang(name: &'static str, expand: fn(CrateTokenStream) -> CrateTokenStream) -> Self {
         ProcMacro::Bang { name, client: Client::expand1(expand) }
     }
 }
diff --git a/crates/proc_macro_srv/src/proc_macro/bridge/closure.rs b/crates/proc_macro_srv/src/abis/abi_1_47/proc_macro/bridge/closure.rs
index f5b6d897e43..f5b6d897e43 100644
--- a/crates/proc_macro_srv/src/proc_macro/bridge/closure.rs
+++ b/crates/proc_macro_srv/src/abis/abi_1_47/proc_macro/bridge/closure.rs
diff --git a/crates/proc_macro_srv/src/proc_macro/bridge/handle.rs b/crates/proc_macro_srv/src/abis/abi_1_47/proc_macro/bridge/handle.rs
index d2a65d249b5..d2a65d249b5 100644
--- a/crates/proc_macro_srv/src/proc_macro/bridge/handle.rs
+++ b/crates/proc_macro_srv/src/abis/abi_1_47/proc_macro/bridge/handle.rs
diff --git a/crates/proc_macro_srv/src/proc_macro/bridge/mod.rs b/crates/proc_macro_srv/src/abis/abi_1_47/proc_macro/bridge/mod.rs
index 375396d1b44..be5402d6eed 100644
--- a/crates/proc_macro_srv/src/proc_macro/bridge/mod.rs
+++ b/crates/proc_macro_srv/src/abis/abi_1_47/proc_macro/bridge/mod.rs
@@ -13,7 +13,7 @@
 
 #![deny(unsafe_code)]
 
-pub use crate::proc_macro::{Delimiter, Level, LineColumn, Spacing};
+pub use super::{Delimiter, Level, LineColumn, Spacing};
 use std::fmt;
 use std::hash::Hash;
 use std::marker;
diff --git a/crates/proc_macro_srv/src/proc_macro/bridge/rpc.rs b/crates/proc_macro_srv/src/abis/abi_1_47/proc_macro/bridge/rpc.rs
index 69928ec845a..69928ec845a 100644
--- a/crates/proc_macro_srv/src/proc_macro/bridge/rpc.rs
+++ b/crates/proc_macro_srv/src/abis/abi_1_47/proc_macro/bridge/rpc.rs
diff --git a/crates/proc_macro_srv/src/proc_macro/bridge/scoped_cell.rs b/crates/proc_macro_srv/src/abis/abi_1_47/proc_macro/bridge/scoped_cell.rs
index 0436bc41836..0436bc41836 100644
--- a/crates/proc_macro_srv/src/proc_macro/bridge/scoped_cell.rs
+++ b/crates/proc_macro_srv/src/abis/abi_1_47/proc_macro/bridge/scoped_cell.rs
diff --git a/crates/proc_macro_srv/src/proc_macro/bridge/server.rs b/crates/proc_macro_srv/src/abis/abi_1_47/proc_macro/bridge/server.rs
index 731d302196f..a580419fd13 100644
--- a/crates/proc_macro_srv/src/proc_macro/bridge/server.rs
+++ b/crates/proc_macro_srv/src/abis/abi_1_47/proc_macro/bridge/server.rs
@@ -3,6 +3,7 @@
 //! Copy from <https://github.com/rust-lang/rust/blob/6050e523bae6de61de4e060facc43dc512adaccd/src/libproc_macro/bridge/server.rs>
 //! augmented with removing unstable features
 
+use super::super::TokenStream as ProcMacroTokenStream;
 use super::*;
 
 // FIXME(eddyb) generate the definition of `HandleStore` in `server.rs`.
@@ -308,7 +309,7 @@ fn run_server<
     Result::decode(&mut &b[..], &mut dispatcher.handle_store)
 }
 
-impl client::Client<fn(crate::TokenStream) -> crate::TokenStream> {
+impl client::Client<fn(ProcMacroTokenStream) -> ProcMacroTokenStream> {
     pub fn run<S: Server>(
         &self,
         strategy: &impl ExecutionStrategy,
@@ -330,7 +331,7 @@ impl client::Client<fn(crate::TokenStream) -> crate::TokenStream> {
     }
 }
 
-impl client::Client<fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream> {
+impl client::Client<fn(ProcMacroTokenStream, ProcMacroTokenStream) -> ProcMacroTokenStream> {
     pub fn run<S: Server>(
         &self,
         strategy: &impl ExecutionStrategy,
diff --git a/crates/proc_macro_srv/src/proc_macro_nightly/diagnostic.rs b/crates/proc_macro_srv/src/abis/abi_1_47/proc_macro/diagnostic.rs
index 6953b1ecf4c..6953b1ecf4c 100644
--- a/crates/proc_macro_srv/src/proc_macro_nightly/diagnostic.rs
+++ b/crates/proc_macro_srv/src/abis/abi_1_47/proc_macro/diagnostic.rs
diff --git a/crates/proc_macro_srv/src/proc_macro/mod.rs b/crates/proc_macro_srv/src/abis/abi_1_47/proc_macro/mod.rs
index b7c1d04b50e..aaa71037567 100644
--- a/crates/proc_macro_srv/src/proc_macro/mod.rs
+++ b/crates/proc_macro_srv/src/abis/abi_1_47/proc_macro/mod.rs
@@ -133,7 +133,7 @@ impl Extend<TokenStream> for TokenStream {
 
 /// Public implementation details for the `TokenStream` type, such as iterators.
 pub mod token_stream {
-    use crate::proc_macro::{bridge, Group, Ident, Literal, Punct, TokenStream, TokenTree};
+    use super::{bridge, Group, Ident, Literal, Punct, TokenStream, TokenTree};
 
     /// An iterator over `TokenStream`'s `TokenTree`s.
     /// The iteration is "shallow", e.g., the iterator doesn't recurse into delimited groups,
diff --git a/crates/proc_macro_srv/src/rustc_server.rs b/crates/proc_macro_srv/src/abis/abi_1_47/rustc_server.rs
index e252e89a569..088cc694e83 100644
--- a/crates/proc_macro_srv/src/rustc_server.rs
+++ b/crates/proc_macro_srv/src/abis/abi_1_47/rustc_server.rs
@@ -8,7 +8,7 @@
 //!
 //! FIXME: No span and source file information is implemented yet
 
-use crate::proc_macro::bridge::{self, server};
+use super::proc_macro::bridge::{self, server};
 
 use std::collections::HashMap;
 use std::hash::Hash;
@@ -97,9 +97,9 @@ impl Extend<TokenStream> for TokenStream {
     }
 }
 
-type Level = crate::proc_macro::Level;
-type LineColumn = crate::proc_macro::LineColumn;
-type SourceFile = crate::proc_macro::SourceFile;
+type Level = super::proc_macro::Level;
+type LineColumn = super::proc_macro::LineColumn;
+type SourceFile = super::proc_macro::SourceFile;
 
 /// A structure representing a diagnostic message and associated children
 /// messages.
@@ -734,8 +734,8 @@ impl server::MultiSpan for Rustc {
 
 #[cfg(test)]
 mod tests {
+    use super::super::proc_macro::bridge::server::Literal;
     use super::*;
-    use crate::proc_macro::bridge::server::Literal;
 
     #[test]
     fn test_rustc_server_literals() {
diff --git a/crates/proc_macro_srv/src/abis/abi_1_55/mod.rs b/crates/proc_macro_srv/src/abis/abi_1_55/mod.rs
new file mode 100644
index 00000000000..81260162075
--- /dev/null
+++ b/crates/proc_macro_srv/src/abis/abi_1_55/mod.rs
@@ -0,0 +1,104 @@
+//! Macro ABI for version 1.55 of rustc
+
+#[allow(dead_code)]
+#[doc(hidden)]
+mod proc_macro;
+
+#[allow(dead_code)]
+#[doc(hidden)]
+mod rustc_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 = rustc_server::TokenStream::with_subtree(macro_body.clone());
+
+        let parsed_attributes = attributes.map_or(rustc_server::TokenStream::new(), |attr| {
+            rustc_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,
+                        rustc_server::Rustc::default(),
+                        parsed_body,
+                        false,
+                    );
+                    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,
+                        rustc_server::Rustc::default(),
+                        parsed_body,
+                        false,
+                    );
+                    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,
+                        rustc_server::Rustc::default(),
+                        parsed_attributes,
+                        parsed_body,
+                        false,
+                    );
+                    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()
+    }
+}
diff --git a/crates/proc_macro_srv/src/proc_macro_nightly/bridge/buffer.rs b/crates/proc_macro_srv/src/abis/abi_1_55/proc_macro/bridge/buffer.rs
index 1565db187c6..1565db187c6 100644
--- a/crates/proc_macro_srv/src/proc_macro_nightly/bridge/buffer.rs
+++ b/crates/proc_macro_srv/src/abis/abi_1_55/proc_macro/bridge/buffer.rs
diff --git a/crates/proc_macro_srv/src/proc_macro_nightly/bridge/client.rs b/crates/proc_macro_srv/src/abis/abi_1_55/proc_macro/bridge/client.rs
index c135cf7a237..9f74fb06689 100644
--- a/crates/proc_macro_srv/src/proc_macro_nightly/bridge/client.rs
+++ b/crates/proc_macro_srv/src/abis/abi_1_55/proc_macro/bridge/client.rs
@@ -3,6 +3,7 @@
 //! Copy from <https://github.com/rust-lang/rust/blob/6050e523bae6de61de4e060facc43dc512adaccd/src/libproc_macro/bridge/client.rs>
 //! augmented with removing unstable features
 
+use super::super::TokenStream as CrateTokenStream;
 use super::*;
 
 macro_rules! define_handles {
@@ -401,26 +402,26 @@ fn run_client<A: for<'a, 's> DecodeMut<'a, 's, ()>, R: Encode<()>>(
     b
 }
 
-impl Client<fn(crate::TokenStream) -> crate::TokenStream> {
-    pub fn expand1(f: fn(crate::TokenStream) -> crate::TokenStream) -> Self {
+impl Client<fn(CrateTokenStream) -> CrateTokenStream> {
+    pub fn expand1(f: fn(CrateTokenStream) -> CrateTokenStream) -> Self {
         extern "C" fn run(
             bridge: Bridge<'_>,
-            f: impl FnOnce(crate::TokenStream) -> crate::TokenStream,
+            f: impl FnOnce(CrateTokenStream) -> CrateTokenStream,
         ) -> Buffer<u8> {
-            run_client(bridge, |input| f(crate::TokenStream(input)).0)
+            run_client(bridge, |input| f(CrateTokenStream(input)).0)
         }
         Client { get_handle_counters: HandleCounters::get, run, f }
     }
 }
 
-impl Client<fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream> {
-    pub fn expand2(f: fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream) -> Self {
+impl Client<fn(CrateTokenStream, CrateTokenStream) -> CrateTokenStream> {
+    pub fn expand2(f: fn(CrateTokenStream, CrateTokenStream) -> CrateTokenStream) -> Self {
         extern "C" fn run(
             bridge: Bridge<'_>,
-            f: impl FnOnce(crate::TokenStream, crate::TokenStream) -> crate::TokenStream,
+            f: impl FnOnce(CrateTokenStream, CrateTokenStream) -> CrateTokenStream,
         ) -> Buffer<u8> {
             run_client(bridge, |(input, input2)| {
-                f(crate::TokenStream(input), crate::TokenStream(input2)).0
+                f(CrateTokenStream(input), CrateTokenStream(input2)).0
             })
         }
         Client { get_handle_counters: HandleCounters::get, run, f }
@@ -433,17 +434,17 @@ pub enum ProcMacro {
     CustomDerive {
         trait_name: &'static str,
         attributes: &'static [&'static str],
-        client: Client<fn(crate::TokenStream) -> crate::TokenStream>,
+        client: Client<fn(CrateTokenStream) -> CrateTokenStream>,
     },
 
     Attr {
         name: &'static str,
-        client: Client<fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream>,
+        client: Client<fn(CrateTokenStream, CrateTokenStream) -> CrateTokenStream>,
     },
 
     Bang {
         name: &'static str,
-        client: Client<fn(crate::TokenStream) -> crate::TokenStream>,
+        client: Client<fn(CrateTokenStream) -> CrateTokenStream>,
     },
 }
 
@@ -465,19 +466,19 @@ impl ProcMacro {
     pub fn custom_derive(
         trait_name: &'static str,
         attributes: &'static [&'static str],
-        expand: fn(crate::TokenStream) -> crate::TokenStream,
+        expand: fn(CrateTokenStream) -> CrateTokenStream,
     ) -> Self {
         ProcMacro::CustomDerive { trait_name, attributes, client: Client::expand1(expand) }
     }
 
     pub fn attr(
         name: &'static str,
-        expand: fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream,
+        expand: fn(CrateTokenStream, CrateTokenStream) -> CrateTokenStream,
     ) -> Self {
         ProcMacro::Attr { name, client: Client::expand2(expand) }
     }
 
-    pub fn bang(name: &'static str, expand: fn(crate::TokenStream) -> crate::TokenStream) -> Self {
+    pub fn bang(name: &'static str, expand: fn(CrateTokenStream) -> CrateTokenStream) -> Self {
         ProcMacro::Bang { name, client: Client::expand1(expand) }
     }
 }
diff --git a/crates/proc_macro_srv/src/proc_macro_nightly/bridge/closure.rs b/crates/proc_macro_srv/src/abis/abi_1_55/proc_macro/bridge/closure.rs
index f5b6d897e43..f5b6d897e43 100644
--- a/crates/proc_macro_srv/src/proc_macro_nightly/bridge/closure.rs
+++ b/crates/proc_macro_srv/src/abis/abi_1_55/proc_macro/bridge/closure.rs
diff --git a/crates/proc_macro_srv/src/proc_macro_nightly/bridge/handle.rs b/crates/proc_macro_srv/src/abis/abi_1_55/proc_macro/bridge/handle.rs
index d2a65d249b5..d2a65d249b5 100644
--- a/crates/proc_macro_srv/src/proc_macro_nightly/bridge/handle.rs
+++ b/crates/proc_macro_srv/src/abis/abi_1_55/proc_macro/bridge/handle.rs
diff --git a/crates/proc_macro_srv/src/proc_macro_nightly/bridge/mod.rs b/crates/proc_macro_srv/src/abis/abi_1_55/proc_macro/bridge/mod.rs
index 8d97bddfd38..8d97bddfd38 100644
--- a/crates/proc_macro_srv/src/proc_macro_nightly/bridge/mod.rs
+++ b/crates/proc_macro_srv/src/abis/abi_1_55/proc_macro/bridge/mod.rs
diff --git a/crates/proc_macro_srv/src/proc_macro_nightly/bridge/rpc.rs b/crates/proc_macro_srv/src/abis/abi_1_55/proc_macro/bridge/rpc.rs
index 69928ec845a..69928ec845a 100644
--- a/crates/proc_macro_srv/src/proc_macro_nightly/bridge/rpc.rs
+++ b/crates/proc_macro_srv/src/abis/abi_1_55/proc_macro/bridge/rpc.rs
diff --git a/crates/proc_macro_srv/src/proc_macro_nightly/bridge/scoped_cell.rs b/crates/proc_macro_srv/src/abis/abi_1_55/proc_macro/bridge/scoped_cell.rs
index 0436bc41836..0436bc41836 100644
--- a/crates/proc_macro_srv/src/proc_macro_nightly/bridge/scoped_cell.rs
+++ b/crates/proc_macro_srv/src/abis/abi_1_55/proc_macro/bridge/scoped_cell.rs
diff --git a/crates/proc_macro_srv/src/proc_macro_nightly/bridge/server.rs b/crates/proc_macro_srv/src/abis/abi_1_55/proc_macro/bridge/server.rs
index cc9afd84b1c..21563fe6049 100644
--- a/crates/proc_macro_srv/src/proc_macro_nightly/bridge/server.rs
+++ b/crates/proc_macro_srv/src/abis/abi_1_55/proc_macro/bridge/server.rs
@@ -3,6 +3,7 @@
 //! Copy from <https://github.com/rust-lang/rust/blob/6050e523bae6de61de4e060facc43dc512adaccd/src/libproc_macro/bridge/server.rs>
 //! augmented with removing unstable features
 
+use super::super::TokenStream as CrateTokenStream;
 use super::*;
 
 // FIXME(eddyb) generate the definition of `HandleStore` in `server.rs`.
@@ -302,7 +303,7 @@ fn run_server<
     Result::decode(&mut &b[..], &mut dispatcher.handle_store)
 }
 
-impl client::Client<fn(crate::TokenStream) -> crate::TokenStream> {
+impl client::Client<fn(CrateTokenStream) -> CrateTokenStream> {
     pub fn run<S: Server>(
         &self,
         strategy: &impl ExecutionStrategy,
@@ -324,7 +325,7 @@ impl client::Client<fn(crate::TokenStream) -> crate::TokenStream> {
     }
 }
 
-impl client::Client<fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream> {
+impl client::Client<fn(CrateTokenStream, CrateTokenStream) -> CrateTokenStream> {
     pub fn run<S: Server>(
         &self,
         strategy: &impl ExecutionStrategy,
diff --git a/crates/proc_macro_srv/src/proc_macro/diagnostic.rs b/crates/proc_macro_srv/src/abis/abi_1_55/proc_macro/diagnostic.rs
index 3c5b7bc0167..6953b1ecf4c 100644
--- a/crates/proc_macro_srv/src/proc_macro/diagnostic.rs
+++ b/crates/proc_macro_srv/src/abis/abi_1_55/proc_macro/diagnostic.rs
@@ -3,7 +3,7 @@
 //! Copy from <https://github.com/rust-lang/rust/blob/6050e523bae6de61de4e060facc43dc512adaccd/src/libproc_macro/diagnostic.rs>
 //! augmented with removing unstable features
 
-use crate::proc_macro::Span;
+use super::Span;
 
 /// An enum representing a diagnostic level.
 #[derive(Copy, Clone, Debug)]
@@ -146,15 +146,15 @@ impl Diagnostic {
 
     /// Emit the diagnostic.
     pub fn emit(self) {
-        fn to_internal(spans: Vec<Span>) -> crate::proc_macro::bridge::client::MultiSpan {
-            let mut multi_span = crate::proc_macro::bridge::client::MultiSpan::new();
+        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 = crate::proc_macro::bridge::client::Diagnostic::new(
+        let mut diag = super::bridge::client::Diagnostic::new(
             self.level,
             &self.message[..],
             to_internal(self.spans),
diff --git a/crates/proc_macro_srv/src/proc_macro_nightly/mod.rs b/crates/proc_macro_srv/src/abis/abi_1_55/proc_macro/mod.rs
index 5814267cfc5..5814267cfc5 100644
--- a/crates/proc_macro_srv/src/proc_macro_nightly/mod.rs
+++ b/crates/proc_macro_srv/src/abis/abi_1_55/proc_macro/mod.rs
diff --git a/crates/proc_macro_srv/src/rustc_server_nightly.rs b/crates/proc_macro_srv/src/abis/abi_1_55/rustc_server.rs
index 2f7a4a31c39..8dfd65ade1c 100644
--- a/crates/proc_macro_srv/src/rustc_server_nightly.rs
+++ b/crates/proc_macro_srv/src/abis/abi_1_55/rustc_server.rs
@@ -8,7 +8,7 @@
 //!
 //! FIXME: No span and source file information is implemented yet
 
-use crate::proc_macro_nightly::bridge::{self, server};
+use super::proc_macro::bridge::{self, server};
 
 use std::collections::HashMap;
 use std::hash::Hash;
@@ -97,9 +97,9 @@ impl Extend<TokenStream> for TokenStream {
     }
 }
 
-type Level = crate::proc_macro_nightly::Level;
-type LineColumn = crate::proc_macro_nightly::LineColumn;
-type SourceFile = crate::proc_macro_nightly::SourceFile;
+type Level = super::proc_macro::Level;
+type LineColumn = super::proc_macro::LineColumn;
+type SourceFile = super::proc_macro::SourceFile;
 
 /// A structure representing a diagnostic message and associated children
 /// messages.
@@ -737,8 +737,8 @@ impl server::MultiSpan for Rustc {
 
 #[cfg(test)]
 mod tests {
+    use super::super::proc_macro::bridge::server::Literal;
     use super::*;
-    use crate::proc_macro_nightly::bridge::server::Literal;
 
     #[test]
     fn test_rustc_server_literals() {
diff --git a/crates/proc_macro_srv/src/abis/mod.rs b/crates/proc_macro_srv/src/abis/mod.rs
new file mode 100644
index 00000000000..3b30aaa90bd
--- /dev/null
+++ b/crates/proc_macro_srv/src/abis/mod.rs
@@ -0,0 +1,97 @@
+//! Procedural macros are implemented by compiling the macro providing crate
+//! to a dynamic library with a particular ABI which the compiler uses to expand
+//! macros. Unfortunately this ABI is not specified and can change from version
+//! to version of the compiler. To support this we copy the ABI from the rust
+//! compiler into submodules of this module (e.g proc_macro_srv::abis::abi_1_47).
+//!
+//! All of these ABIs are subsumed in the `Abi` enum, which exposes a simple
+//! interface the rest of rust analyzer can use to talk to the macro
+//! provider.
+//!
+//! # Adding a new ABI
+//!
+//! To add a new ABI you'll need to copy the source of the target proc_macro
+//! crate from the source tree of the Rust compiler into this directory tree.
+//! Then you'll need to modify it
+//! - Remove any feature! or other things which won't compile on stable
+//! - change any absolute imports to relative imports within the ABI tree
+//!
+//! Then you'll need to add a branch to the `Abi` enum and an implementation of
+//! `Abi::expand`, `Abi::list_macros` and `Abi::from_lib` for the new ABI. See
+//! `proc_macro_srv/src/abis/abi_1_47/mod.rs` for an example. Finally you'll
+//! need to update the conditionals in `Abi::from_lib` to return your new ABI
+//! for the relevant versions of the rust compiler
+//!
+
+// pub(crate) so tests can use the TokenStream, more notes in test/utils.rs
+pub(crate) mod abi_1_47;
+mod abi_1_55;
+
+use super::dylib::LoadProcMacroDylibError;
+pub(crate) use abi_1_47::Abi as Abi_1_47;
+pub(crate) use abi_1_55::Abi as Abi_1_55;
+use libloading::Library;
+use proc_macro_api::{ProcMacroKind, RustCInfo};
+
+pub struct PanicMessage {
+    message: Option<String>,
+}
+
+impl PanicMessage {
+    pub fn as_str(&self) -> Option<String> {
+        self.message.clone()
+    }
+}
+
+pub(crate) enum Abi {
+    Abi1_47(Abi_1_47),
+    Abi1_55(Abi_1_55),
+}
+
+impl Abi {
+    /// Load a new ABI.
+    ///
+    /// # Arguments
+    ///
+    /// *`lib` - The dynamic library containing the macro implementations
+    /// *`symbol_name` - The symbol name the macros can be found attributes
+    /// *`info` - RustCInfo about the compiler that was used to compile the
+    ///           macro crate. This is the information we use to figure out
+    ///           which ABI to return
+    pub fn from_lib(
+        lib: &Library,
+        symbol_name: String,
+        info: RustCInfo,
+    ) -> Result<Abi, LoadProcMacroDylibError> {
+        if info.version.0 != 1 {
+            Err(LoadProcMacroDylibError::UnsupportedABI)
+        } else if info.version.1 < 47 {
+            Err(LoadProcMacroDylibError::UnsupportedABI)
+        } else if info.version.1 < 54 {
+            let inner = unsafe { Abi_1_47::from_lib(lib, symbol_name) }?;
+            Ok(Abi::Abi1_47(inner))
+        } else {
+            let inner = unsafe { Abi_1_55::from_lib(lib, symbol_name) }?;
+            Ok(Abi::Abi1_55(inner))
+        }
+    }
+
+    pub fn expand(
+        &self,
+        macro_name: &str,
+        macro_body: &tt::Subtree,
+        attributes: Option<&tt::Subtree>,
+    ) -> Result<tt::Subtree, PanicMessage> {
+        match self {
+            Self::Abi1_55(abi) => abi.expand(macro_name, macro_body, attributes),
+            Self::Abi1_47(abi) => abi.expand(macro_name, macro_body, attributes),
+        }
+    }
+
+    pub fn list_macros(&self) -> Vec<(String, ProcMacroKind)> {
+        match self {
+            Self::Abi1_47(abi) => abi.list_macros(),
+            Self::Abi1_55(abi) => abi.list_macros(),
+        }
+    }
+}
diff --git a/crates/proc_macro_srv/src/dylib.rs b/crates/proc_macro_srv/src/dylib.rs
index 69a645119f4..5f0b0b061e1 100644
--- a/crates/proc_macro_srv/src/dylib.rs
+++ b/crates/proc_macro_srv/src/dylib.rs
@@ -1,7 +1,6 @@
 //! Handles dynamic library loading for proc macro
 
 use std::{
-    convert::{TryFrom, TryInto},
     fmt,
     fs::File,
     io,
@@ -11,16 +10,9 @@ use std::{
 use libloading::Library;
 use memmap2::Mmap;
 use object::Object;
-use proc_macro_api::{read_dylib_info, ProcMacroKind, RustCInfo};
+use proc_macro_api::{read_dylib_info, ProcMacroKind};
 
-use crate::{
-    proc_macro::bridge::{self as stable_bridge, client::ProcMacro as StableProcMacro},
-    rustc_server::TokenStream as StableTokenStream,
-};
-use crate::{
-    proc_macro_nightly::bridge::{self as nightly_bridge, client::ProcMacro as NightlyProcMacro},
-    rustc_server_nightly::TokenStream as NightlyTokenStream,
-};
+use super::abis::Abi;
 
 const NEW_REGISTRAR_SYMBOL: &str = "_rustc_proc_macro_decls_";
 
@@ -83,30 +75,10 @@ fn load_library(file: &Path) -> Result<Library, libloading::Error> {
     unsafe { UnixLibrary::open(Some(file), RTLD_NOW | RTLD_DEEPBIND).map(|lib| lib.into()) }
 }
 
-enum ProcMacroABI {
-    Stable,
-    Nightly,
-}
-
-impl TryFrom<RustCInfo> for ProcMacroABI {
-    type Error = LoadProcMacroDylibError;
-
-    fn try_from(info: RustCInfo) -> Result<Self, Self::Error> {
-        if info.version.0 != 1 {
-            Err(LoadProcMacroDylibError::UnsupportedABI)
-        } else if info.version.1 < 47 {
-            Err(LoadProcMacroDylibError::UnsupportedABI)
-        } else if info.version.1 < 54 {
-            Ok(ProcMacroABI::Stable)
-        } else {
-            Ok(ProcMacroABI::Nightly)
-        }
-    }
-}
-
 #[derive(Debug)]
 pub enum LoadProcMacroDylibError {
     Io(io::Error),
+    LibLoading(libloading::Error),
     UnsupportedABI,
 }
 
@@ -115,6 +87,7 @@ impl fmt::Display for LoadProcMacroDylibError {
         match self {
             Self::Io(e) => e.fmt(f),
             Self::UnsupportedABI => write!(f, "unsupported ABI version"),
+            Self::LibLoading(e) => e.fmt(f),
         }
     }
 }
@@ -125,15 +98,16 @@ impl From<io::Error> for LoadProcMacroDylibError {
     }
 }
 
-enum ProcMacroLibraryLibloading {
-    StableProcMacroLibrary {
-        _lib: Library,
-        exported_macros: Vec<crate::proc_macro::bridge::client::ProcMacro>,
-    },
-    NightlyProcMacroLibrary {
-        _lib: Library,
-        exported_macros: Vec<crate::proc_macro_nightly::bridge::client::ProcMacro>,
-    },
+impl From<libloading::Error> for LoadProcMacroDylibError {
+    fn from(e: libloading::Error) -> Self {
+        LoadProcMacroDylibError::LibLoading(e)
+    }
+}
+
+struct ProcMacroLibraryLibloading {
+    // Hold on to the library so it doesn't unload
+    _lib: Library,
+    abi: Abi,
 }
 
 impl ProcMacroLibraryLibloading {
@@ -143,57 +117,10 @@ impl ProcMacroLibraryLibloading {
         })?;
 
         let version_info = read_dylib_info(file)?;
-        let macro_abi: ProcMacroABI = version_info.try_into()?;
 
         let lib = load_library(file).map_err(invalid_data_err)?;
-        match macro_abi {
-            ProcMacroABI::Stable => {
-                let macros: libloading::Symbol<&&[crate::proc_macro::bridge::client::ProcMacro]> =
-                    unsafe { lib.get(symbol_name.as_bytes()) }.map_err(invalid_data_err)?;
-                let macros_vec = macros.to_vec();
-                Ok(ProcMacroLibraryLibloading::StableProcMacroLibrary {
-                    _lib: lib,
-                    exported_macros: macros_vec,
-                })
-            }
-            ProcMacroABI::Nightly => {
-                let macros: libloading::Symbol<
-                    &&[crate::proc_macro_nightly::bridge::client::ProcMacro],
-                > = unsafe { lib.get(symbol_name.as_bytes()) }.map_err(invalid_data_err)?;
-                let macros_vec = macros.to_vec();
-                Ok(ProcMacroLibraryLibloading::NightlyProcMacroLibrary {
-                    _lib: lib,
-                    exported_macros: macros_vec,
-                })
-            }
-        }
-    }
-}
-
-#[derive(Debug)]
-pub enum PanicMessage {
-    Stable(stable_bridge::PanicMessage),
-    Nightly(nightly_bridge::PanicMessage),
-}
-
-impl From<stable_bridge::PanicMessage> for PanicMessage {
-    fn from(p: stable_bridge::PanicMessage) -> Self {
-        PanicMessage::Stable(p)
-    }
-}
-
-impl From<nightly_bridge::PanicMessage> for PanicMessage {
-    fn from(p: nightly_bridge::PanicMessage) -> Self {
-        PanicMessage::Nightly(p)
-    }
-}
-
-impl PanicMessage {
-    pub fn as_str(&self) -> Option<&str> {
-        match self {
-            Self::Stable(p) => p.as_str(),
-            Self::Nightly(p) => p.as_str(),
-        }
+        let abi = Abi::from_lib(&lib, symbol_name, version_info)?;
+        Ok(ProcMacroLibraryLibloading { _lib: lib, abi })
     }
 }
 
@@ -219,28 +146,13 @@ impl Expander {
         macro_name: &str,
         macro_body: &tt::Subtree,
         attributes: Option<&tt::Subtree>,
-    ) -> Result<tt::Subtree, PanicMessage> {
-        match &self.inner {
-            ProcMacroLibraryLibloading::StableProcMacroLibrary { exported_macros, .. } => {
-                expand_stable(macro_name, macro_body, attributes, &exported_macros[..])
-                    .map_err(PanicMessage::from)
-            }
-            ProcMacroLibraryLibloading::NightlyProcMacroLibrary { exported_macros, .. } => {
-                expand_nightly(macro_name, macro_body, attributes, &exported_macros[..])
-                    .map_err(PanicMessage::from)
-            }
-        }
+    ) -> Result<tt::Subtree, String> {
+        let result = self.inner.abi.expand(macro_name, macro_body, attributes);
+        result.map_err(|e| e.as_str().unwrap_or_else(|| "<unknown error>".to_string()))
     }
 
     pub fn list_macros(&self) -> Vec<(String, ProcMacroKind)> {
-        match &self.inner {
-            ProcMacroLibraryLibloading::StableProcMacroLibrary { exported_macros, .. } => {
-                list_macros_stable(&exported_macros[..])
-            }
-            ProcMacroLibraryLibloading::NightlyProcMacroLibrary { exported_macros, .. } => {
-                list_macros_nightly(&exported_macros[..])
-            }
-        }
+        self.inner.abi.list_macros()
     }
 }
 
@@ -276,153 +188,3 @@ fn ensure_file_with_lock_free_access(path: &Path) -> io::Result<PathBuf> {
 fn ensure_file_with_lock_free_access(path: &Path) -> io::Result<PathBuf> {
     Ok(path.to_path_buf())
 }
-
-fn expand_nightly(
-    macro_name: &str,
-    macro_body: &tt::Subtree,
-    attributes: Option<&tt::Subtree>,
-    macros: &[NightlyProcMacro],
-) -> Result<tt::Subtree, crate::proc_macro_nightly::bridge::PanicMessage> {
-    let parsed_body = NightlyTokenStream::with_subtree(macro_body.clone());
-
-    let parsed_attributes = attributes
-        .map_or(crate::rustc_server_nightly::TokenStream::new(), |attr| {
-            NightlyTokenStream::with_subtree(attr.clone())
-        });
-
-    for proc_macro in macros {
-        match proc_macro {
-            crate::proc_macro_nightly::bridge::client::ProcMacro::CustomDerive {
-                trait_name,
-                client,
-                ..
-            } if *trait_name == macro_name => {
-                let res = client.run(
-                    &crate::proc_macro_nightly::bridge::server::SameThread,
-                    crate::rustc_server_nightly::Rustc::default(),
-                    parsed_body,
-                    false,
-                );
-                return res.map(|it| it.into_subtree());
-            }
-            crate::proc_macro_nightly::bridge::client::ProcMacro::Bang { name, client }
-                if *name == macro_name =>
-            {
-                let res = client.run(
-                    &crate::proc_macro_nightly::bridge::server::SameThread,
-                    crate::rustc_server_nightly::Rustc::default(),
-                    parsed_body,
-                    false,
-                );
-                return res.map(|it| it.into_subtree());
-            }
-            crate::proc_macro_nightly::bridge::client::ProcMacro::Attr { name, client }
-                if *name == macro_name =>
-            {
-                let res = client.run(
-                    &crate::proc_macro_nightly::bridge::server::SameThread,
-                    crate::rustc_server_nightly::Rustc::default(),
-                    parsed_attributes,
-                    parsed_body,
-                    false,
-                );
-                return res.map(|it| it.into_subtree());
-            }
-            _ => continue,
-        }
-    }
-
-    Err(crate::proc_macro_nightly::bridge::PanicMessage::String("Nothing to expand".to_string()))
-}
-
-fn expand_stable(
-    macro_name: &str,
-    macro_body: &tt::Subtree,
-    attributes: Option<&tt::Subtree>,
-    macros: &[StableProcMacro],
-) -> Result<tt::Subtree, crate::proc_macro::bridge::PanicMessage> {
-    let parsed_body = StableTokenStream::with_subtree(macro_body.clone());
-
-    let parsed_attributes = attributes.map_or(crate::rustc_server::TokenStream::new(), |attr| {
-        StableTokenStream::with_subtree(attr.clone())
-    });
-
-    for proc_macro in macros {
-        match proc_macro {
-            crate::proc_macro::bridge::client::ProcMacro::CustomDerive {
-                trait_name,
-                client,
-                ..
-            } if *trait_name == macro_name => {
-                let res = client.run(
-                    &crate::proc_macro::bridge::server::SameThread,
-                    crate::rustc_server::Rustc::default(),
-                    parsed_body,
-                    false,
-                );
-                return res.map(|it| it.into_subtree());
-            }
-            crate::proc_macro::bridge::client::ProcMacro::Bang { name, client }
-                if *name == macro_name =>
-            {
-                let res = client.run(
-                    &crate::proc_macro::bridge::server::SameThread,
-                    crate::rustc_server::Rustc::default(),
-                    parsed_body,
-                    false,
-                );
-                return res.map(|it| it.into_subtree());
-            }
-            crate::proc_macro::bridge::client::ProcMacro::Attr { name, client }
-                if *name == macro_name =>
-            {
-                let res = client.run(
-                    &crate::proc_macro::bridge::server::SameThread,
-                    crate::rustc_server::Rustc::default(),
-                    parsed_attributes,
-                    parsed_body,
-                    false,
-                );
-                return res.map(|it| it.into_subtree());
-            }
-            _ => continue,
-        }
-    }
-
-    Err(crate::proc_macro::bridge::PanicMessage::String("Nothing to expand".to_string()))
-}
-
-pub fn list_macros_stable(macros: &[StableProcMacro]) -> Vec<(String, ProcMacroKind)> {
-    macros
-        .iter()
-        .map(|proc_macro| match proc_macro {
-            crate::proc_macro::bridge::client::ProcMacro::CustomDerive { trait_name, .. } => {
-                (trait_name.to_string(), ProcMacroKind::CustomDerive)
-            }
-            crate::proc_macro::bridge::client::ProcMacro::Bang { name, .. } => {
-                (name.to_string(), ProcMacroKind::FuncLike)
-            }
-            crate::proc_macro::bridge::client::ProcMacro::Attr { name, .. } => {
-                (name.to_string(), ProcMacroKind::Attr)
-            }
-        })
-        .collect()
-}
-
-pub fn list_macros_nightly(macros: &[NightlyProcMacro]) -> Vec<(String, ProcMacroKind)> {
-    macros
-        .iter()
-        .map(|proc_macro| match proc_macro {
-            crate::proc_macro_nightly::bridge::client::ProcMacro::CustomDerive {
-                trait_name,
-                ..
-            } => (trait_name.to_string(), ProcMacroKind::CustomDerive),
-            crate::proc_macro_nightly::bridge::client::ProcMacro::Bang { name, .. } => {
-                (name.to_string(), ProcMacroKind::FuncLike)
-            }
-            crate::proc_macro_nightly::bridge::client::ProcMacro::Attr { name, .. } => {
-                (name.to_string(), ProcMacroKind::Attr)
-            }
-        })
-        .collect()
-}
diff --git a/crates/proc_macro_srv/src/lib.rs b/crates/proc_macro_srv/src/lib.rs
index deb1d1e526e..eb9080e998e 100644
--- a/crates/proc_macro_srv/src/lib.rs
+++ b/crates/proc_macro_srv/src/lib.rs
@@ -11,23 +11,10 @@
 //!   rustc rather than `unstable`. (Although in general ABI compatibility is still an issue)…
 #![allow(unreachable_pub)]
 
-#[allow(dead_code)]
-#[doc(hidden)]
-mod proc_macro;
-
-#[allow(dead_code)]
-#[doc(hidden)]
-mod proc_macro_nightly;
-
-#[doc(hidden)]
-mod rustc_server;
-
-#[doc(hidden)]
-mod rustc_server_nightly;
-
 mod dylib;
 
-use proc_macro::bridge::client::TokenStream;
+mod abis;
+
 use proc_macro_api::{ExpansionResult, ExpansionTask, ListMacrosResult, ListMacrosTask};
 use std::{
     collections::{hash_map::Entry, HashMap},
@@ -62,10 +49,7 @@ impl ProcMacroSrv {
 
         match result {
             Ok(expansion) => Ok(ExpansionResult { expansion }),
-            Err(msg) => {
-                let msg = msg.as_str().unwrap_or("<unknown error>");
-                Err(format!("proc-macro panicked: {}", msg))
-            }
+            Err(msg) => Err(format!("proc-macro panicked: {}", msg)),
         }
     }
 
diff --git a/crates/proc_macro_srv/src/tests/utils.rs b/crates/proc_macro_srv/src/tests/utils.rs
index 2c093aa0ad8..150e26fe759 100644
--- a/crates/proc_macro_srv/src/tests/utils.rs
+++ b/crates/proc_macro_srv/src/tests/utils.rs
@@ -12,8 +12,14 @@ pub mod fixtures {
     }
 }
 
-fn parse_string(code: &str) -> Option<crate::rustc_server::TokenStream> {
-    Some(crate::rustc_server::TokenStream::from_str(code).unwrap())
+fn parse_string(code: &str) -> Option<crate::abis::abi_1_47::TokenStream> {
+    // This is a bit strange. We need to parse a string into a token stream into
+    // order to create a tt::SubTree from it in fixtures. `into_subtree` is
+    // implemented by all the ABIs we have so we arbitrarily choose one ABI to
+    // write a `parse_string` function for and use that. The tests don't really
+    // care which ABI we're using as the `into_subtree` function isn't part of
+    // the ABI and shouldn't change between ABI versions.
+    crate::abis::abi_1_47::TokenStream::from_str(code).ok()
 }
 
 pub fn assert_expand(macro_name: &str, ra_fixture: &str, expect: Expect) {