1 //! Procedural macros are implemented by compiling the macro providing crate
2 //! to a dynamic library with a particular ABI which the compiler uses to expand
3 //! macros. Unfortunately this ABI is not specified and can change from version
4 //! to version of the compiler. To support this we copy the ABI from the rust
5 //! compiler into submodules of this module (e.g proc_macro_srv::abis::abi_1_47).
7 //! All of these ABIs are subsumed in the `Abi` enum, which exposes a simple
8 //! interface the rest of rust-analyzer can use to talk to the macro
11 //! # Adding a new ABI
13 //! To add a new ABI you'll need to copy the source of the target proc_macro
14 //! crate from the source tree of the Rust compiler into this directory tree.
15 //! Then you'll need to modify it
16 //! - Remove any feature! or other things which won't compile on stable
17 //! - change any absolute imports to relative imports within the ABI tree
19 //! Then you'll need to add a branch to the `Abi` enum and an implementation of
20 //! `Abi::expand`, `Abi::list_macros` and `Abi::from_lib` for the new ABI. See
21 //! `proc_macro_srv/src/abis/abi_1_47/mod.rs` for an example. Finally you'll
22 //! need to update the conditionals in `Abi::from_lib` to return your new ABI
23 //! for the relevant versions of the rust compiler
28 #[cfg(feature = "sysroot-abi")]
32 include
!(concat
!(env
!("OUT_DIR"), "/rustc_version.rs"));
34 // Used by `test/utils.rs`
35 #[cfg(all(test, feature = "sysroot-abi"))]
36 pub(crate) use abi_sysroot
::TokenStream
as TestTokenStream
;
38 use super::dylib
::LoadProcMacroDylibError
;
39 pub(crate) use abi_1_58
::Abi
as Abi_1_58
;
40 pub(crate) use abi_1_63
::Abi
as Abi_1_63
;
41 #[cfg(feature = "sysroot-abi")]
42 pub(crate) use abi_sysroot
::Abi
as Abi_Sysroot
;
43 use libloading
::Library
;
44 use proc_macro_api
::{ProcMacroKind, RustCInfo}
;
46 pub struct PanicMessage
{
47 message
: Option
<String
>,
51 pub fn as_str(&self) -> Option
<String
> {
59 #[cfg(feature = "sysroot-abi")]
60 AbiSysroot(Abi_Sysroot
),
68 /// *`lib` - The dynamic library containing the macro implementations
69 /// *`symbol_name` - The symbol name the macros can be found attributes
70 /// *`info` - RustCInfo about the compiler that was used to compile the
71 /// macro crate. This is the information we use to figure out
72 /// which ABI to return
77 ) -> Result
<Abi
, LoadProcMacroDylibError
> {
78 // the sysroot ABI relies on `extern proc_macro` with unstable features,
79 // instead of a snapshot of the proc macro bridge's source code. it's only
80 // enabled if we have an exact version match.
81 #[cfg(feature = "sysroot-abi")]
83 if info
.version_string
== RUSTC_VERSION_STRING
{
84 let inner
= unsafe { Abi_Sysroot::from_lib(lib, symbol_name) }?
;
85 return Ok(Abi
::AbiSysroot(inner
));
88 // if we reached this point, versions didn't match. in testing, we
89 // want that to panic - this could mean that the format of `rustc
90 // --version` no longer matches the format of the version string
91 // stored in the `.rustc` section, and we want to catch that in-tree
95 let allow_mismatch
= std
::env
::var("PROC_MACRO_SRV_ALLOW_SYSROOT_MISMATCH");
96 if let Ok("1") = allow_mismatch
.as_deref() {
97 // only used by rust-analyzer developers, when working on the
98 // sysroot ABI from the rust-analyzer repository - which should
99 // only happen pre-subtree. this can be removed later.
102 "sysroot ABI mismatch: dylib rustc version (read from .rustc section): {:?} != proc-macro-srv version (read from 'rustc --version'): {:?}",
103 info
.version_string
, RUSTC_VERSION_STRING
109 // FIXME: this should use exclusive ranges when they're stable
110 // https://github.com/rust-lang/rust/issues/37854
111 match (info
.version
.0, info
.version
.1) {
113 let inner
= unsafe { Abi_1_58::from_lib(lib, symbol_name) }?
;
114 Ok(Abi
::Abi1_58(inner
))
117 let inner
= unsafe { Abi_1_63::from_lib(lib, symbol_name) }?
;
118 Ok(Abi
::Abi1_63(inner
))
120 _
=> Err(LoadProcMacroDylibError
::UnsupportedABI(info
.version_string
)),
127 macro_body
: &tt
::Subtree
,
128 attributes
: Option
<&tt
::Subtree
>,
129 ) -> Result
<tt
::Subtree
, PanicMessage
> {
131 Self::Abi1_58(abi
) => abi
.expand(macro_name
, macro_body
, attributes
),
132 Self::Abi1_63(abi
) => abi
.expand(macro_name
, macro_body
, attributes
),
133 #[cfg(feature = "sysroot-abi")]
134 Self::AbiSysroot(abi
) => abi
.expand(macro_name
, macro_body
, attributes
),
138 pub fn list_macros(&self) -> Vec
<(String
, ProcMacroKind
)> {
140 Self::Abi1_58(abi
) => abi
.list_macros(),
141 Self::Abi1_63(abi
) => abi
.list_macros(),
142 #[cfg(feature = "sysroot-abi")]
143 Self::AbiSysroot(abi
) => abi
.list_macros(),
149 fn test_version_check() {
150 let path
= paths
::AbsPathBuf
::assert(crate::proc_macro_test_dylib_path());
151 let info
= proc_macro_api
::read_dylib_info(&path
).unwrap();
152 assert
!(info
.version
.1 >= 50);