Skip to content

Commit 8f26221

Browse files
Merge #6820
6820: Pass the crate environment to proc macros r=jonas-schievink a=jonas-schievink In theory, fixes #6696. This seems to result in these obscure crashes for some reason: ``` thread '<unnamed>' panicked at 'called `Option::unwrap()` on a `None` value', /home/jonas/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/proc_macro/src/bridge/scoped_cell.rs:75:51 stack backtrace: 0: rust_begin_unwind at /rustc/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/library/std/src/panicking.rs:483 1: core::panicking::panic_fmt at /rustc/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/library/core/src/panicking.rs:85 2: core::panicking::panic at /rustc/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/library/core/src/panicking.rs:50 3: core::option::Option<T>::unwrap at /home/jonas/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/option.rs:383 4: proc_macro::bridge::scoped_cell::ScopedCell<T>::replace at /home/jonas/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/proc_macro/src/bridge/scoped_cell.rs:75 5: proc_macro::bridge::client::BridgeState::with::{{closure}} at /home/jonas/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/proc_macro/src/bridge/client.rs:291 6: std::thread::local::LocalKey<T>::try_with at /home/jonas/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/thread/local.rs:272 7: std::thread::local::LocalKey<T>::with at /home/jonas/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/thread/local.rs:248 8: proc_macro::bridge::client::BridgeState::with at /home/jonas/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/proc_macro/src/bridge/client.rs:290 9: proc_macro::bridge::client::<impl proc_macro::bridge::Bridge>::with at /home/jonas/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/proc_macro/src/bridge/client.rs:329 10: proc_macro::bridge::client::run_client::{{closure}}::{{closure}} at /home/jonas/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/proc_macro/src/bridge/client.rs:375 11: proc_macro::bridge::scoped_cell::ScopedCell<T>::set::{{closure}} at /home/jonas/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/proc_macro/src/bridge/scoped_cell.rs:80 12: proc_macro::bridge::scoped_cell::ScopedCell<T>::replace at /home/jonas/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/proc_macro/src/bridge/scoped_cell.rs:75 13: proc_macro::bridge::scoped_cell::ScopedCell<T>::set at /home/jonas/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/proc_macro/src/bridge/scoped_cell.rs:80 14: proc_macro::bridge::client::<impl proc_macro::bridge::Bridge>::enter::{{closure}} at /home/jonas/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/proc_macro/src/bridge/client.rs:325 15: std::thread::local::LocalKey<T>::try_with at /home/jonas/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/thread/local.rs:272 16: std::thread::local::LocalKey<T>::with at /home/jonas/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/thread/local.rs:248 17: proc_macro::bridge::client::<impl proc_macro::bridge::Bridge>::enter at /home/jonas/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/proc_macro/src/bridge/client.rs:325 18: proc_macro::bridge::client::run_client::{{closure}} at /home/jonas/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/proc_macro/src/bridge/client.rs:370 19: <std::panic::AssertUnwindSafe<F> as core::ops::function::FnOnce<()>>::call_once at /home/jonas/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/panic.rs:308 20: std::panicking::try::do_call at /home/jonas/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/panicking.rs:381 21: __rust_try 22: std::panicking::try at /home/jonas/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/panicking.rs:345 23: std::panic::catch_unwind at /home/jonas/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/panic.rs:382 24: proc_macro::bridge::client::run_client at /home/jonas/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/proc_macro/src/bridge/client.rs:369 25: proc_macro::bridge::client::Client<fn(proc_macro::TokenStream) .> proc_macro::TokenStream>::expand1::run at /home/jonas/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/proc_macro/src/bridge/client.rs:410 26: proc_macro_srv::proc_macro::bridge::server::run_server 27: proc_macro_srv::dylib::Expander::expand 28: proc_macro_srv::ProcMacroSrv::expand 29: proc_macro_srv::cli::run 30: rust_analyzer::main ``` Co-authored-by: Jonas Schievink <[email protected]>
2 parents 0fd75c9 + 7087742 commit 8f26221

File tree

8 files changed

+52
-19
lines changed

8 files changed

+52
-19
lines changed

crates/base_db/src/input.rs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@
66
//! actual IO. See `vfs` and `project_model` in the `rust-analyzer` crate for how
77
//! actual IO is done and lowered to input.
88
9-
use std::{fmt, iter::FromIterator, ops, str::FromStr, sync::Arc};
9+
use std::{fmt, iter::FromIterator, ops, panic::RefUnwindSafe, str::FromStr, sync::Arc};
1010

1111
use cfg::CfgOptions;
1212
use rustc_hash::{FxHashMap, FxHashSet};
1313
use syntax::SmolStr;
14-
use tt::TokenExpander;
14+
use tt::{ExpansionError, Subtree};
1515
use vfs::{file_set::FileSet, FileId, VfsPath};
1616

1717
/// Files are grouped into source roots. A source root is a directory on the
@@ -150,11 +150,20 @@ pub enum ProcMacroKind {
150150
Attr,
151151
}
152152

153+
pub trait ProcMacroExpander: fmt::Debug + Send + Sync + RefUnwindSafe {
154+
fn expand(
155+
&self,
156+
subtree: &Subtree,
157+
attrs: Option<&Subtree>,
158+
env: &Env,
159+
) -> Result<Subtree, ExpansionError>;
160+
}
161+
153162
#[derive(Debug, Clone)]
154163
pub struct ProcMacro {
155164
pub name: SmolStr,
156165
pub kind: ProcMacroKind,
157-
pub expander: Arc<dyn TokenExpander>,
166+
pub expander: Arc<dyn ProcMacroExpander>,
158167
}
159168

160169
impl Eq for ProcMacro {}
@@ -413,6 +422,10 @@ impl Env {
413422
pub fn get(&self, env: &str) -> Option<String> {
414423
self.entries.get(env).cloned()
415424
}
425+
426+
pub fn iter(&self) -> impl Iterator<Item = (&str, &str)> {
427+
self.entries.iter().map(|(k, v)| (k.as_str(), v.as_str()))
428+
}
416429
}
417430

418431
#[derive(Debug)]

crates/base_db/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ pub use crate::{
1414
change::Change,
1515
input::{
1616
CrateData, CrateDisplayName, CrateGraph, CrateId, CrateName, Dependency, Edition, Env,
17-
ProcMacro, ProcMacroId, ProcMacroKind, SourceRoot, SourceRootId,
17+
ProcMacro, ProcMacroExpander, ProcMacroId, ProcMacroKind, SourceRoot, SourceRootId,
1818
},
1919
};
2020
pub use salsa;

crates/hir_expand/src/db.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ fn expand_proc_macro(
271271
_ => unreachable!(),
272272
};
273273

274-
expander.expand(db, lazy_id, &macro_arg.0)
274+
expander.expand(db, loc.krate, &macro_arg.0)
275275
}
276276

277277
fn parse_or_expand(db: &dyn AstDatabase, file_id: HirFileId) -> Option<SyntaxNode> {

crates/hir_expand/src/proc_macro.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Proc Macro Expander stub
22
3-
use crate::{db::AstDatabase, LazyMacroId};
3+
use crate::db::AstDatabase;
44
use base_db::{CrateId, ProcMacroId};
55
use tt::buffer::{Cursor, TokenBuffer};
66

@@ -32,7 +32,7 @@ impl ProcMacroExpander {
3232
pub fn expand(
3333
self,
3434
db: &dyn AstDatabase,
35-
_id: LazyMacroId,
35+
calling_crate: CrateId,
3636
tt: &tt::Subtree,
3737
) -> Result<tt::Subtree, mbe::ExpandError> {
3838
match self.proc_macro_id {
@@ -47,7 +47,10 @@ impl ProcMacroExpander {
4747
let tt = remove_derive_attrs(tt)
4848
.ok_or_else(|| err!("Fail to remove derive for custom derive"))?;
4949

50-
proc_macro.expander.expand(&tt, None).map_err(mbe::ExpandError::from)
50+
// Proc macros have access to the environment variables of the invoking crate.
51+
let env = &krate_graph[calling_crate].env;
52+
53+
proc_macro.expander.expand(&tt, None, &env).map_err(mbe::ExpandError::from)
5154
}
5255
None => Err(mbe::ExpandError::UnresolvedProcMacro),
5356
}

crates/proc_macro_api/src/lib.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use std::{
1616
sync::Arc,
1717
};
1818

19-
use base_db::ProcMacro;
19+
use base_db::{Env, ProcMacro};
2020
use tt::{SmolStr, Subtree};
2121

2222
use crate::process::{ProcMacroProcessSrv, ProcMacroProcessThread};
@@ -39,17 +39,19 @@ impl PartialEq for ProcMacroProcessExpander {
3939
}
4040
}
4141

42-
impl tt::TokenExpander for ProcMacroProcessExpander {
42+
impl base_db::ProcMacroExpander for ProcMacroProcessExpander {
4343
fn expand(
4444
&self,
4545
subtree: &Subtree,
4646
attr: Option<&Subtree>,
47+
env: &Env,
4748
) -> Result<Subtree, tt::ExpansionError> {
4849
let task = ExpansionTask {
4950
macro_body: subtree.clone(),
5051
macro_name: self.name.to_string(),
5152
attributes: attr.cloned(),
5253
lib: self.dylib_path.to_path_buf(),
54+
env: env.iter().map(|(k, v)| (k.to_string(), v.to_string())).collect(),
5355
};
5456

5557
let result: ExpansionResult = self.process.send_task(msg::Request::ExpansionMacro(task))?;
@@ -90,7 +92,7 @@ impl ProcMacroClient {
9092
ProcMacroKind::FuncLike => base_db::ProcMacroKind::FuncLike,
9193
ProcMacroKind::Attr => base_db::ProcMacroKind::Attr,
9294
};
93-
let expander: Arc<dyn tt::TokenExpander> = Arc::new(ProcMacroProcessExpander {
95+
let expander = Arc::new(ProcMacroProcessExpander {
9496
process: self.process.clone(),
9597
name: name.clone(),
9698
dylib_path: dylib_path.into(),

crates/proc_macro_api/src/rpc.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ pub struct ExpansionTask {
5151
pub attributes: Option<Subtree>,
5252

5353
pub lib: PathBuf,
54+
55+
/// Environment variables to set during macro expansion.
56+
pub env: Vec<(String, String)>,
5457
}
5558

5659
#[derive(Clone, Eq, PartialEq, Debug, Default, Serialize, Deserialize)]
@@ -251,6 +254,7 @@ mod tests {
251254
macro_name: Default::default(),
252255
attributes: None,
253256
lib: Default::default(),
257+
env: Default::default(),
254258
};
255259

256260
let json = serde_json::to_string(&task).unwrap();

crates/proc_macro_srv/src/lib.rs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use proc_macro::bridge::client::TokenStream;
2424
use proc_macro_api::{ExpansionResult, ExpansionTask, ListMacrosResult, ListMacrosTask};
2525
use std::{
2626
collections::{hash_map::Entry, HashMap},
27-
fs,
27+
env, fs,
2828
path::{Path, PathBuf},
2929
time::SystemTime,
3030
};
@@ -37,7 +37,23 @@ pub(crate) struct ProcMacroSrv {
3737
impl ProcMacroSrv {
3838
pub fn expand(&mut self, task: &ExpansionTask) -> Result<ExpansionResult, String> {
3939
let expander = self.expander(&task.lib)?;
40-
match expander.expand(&task.macro_name, &task.macro_body, task.attributes.as_ref()) {
40+
41+
let mut prev_env = HashMap::new();
42+
for (k, v) in &task.env {
43+
prev_env.insert(k.as_str(), env::var_os(k));
44+
env::set_var(k, v);
45+
}
46+
47+
let result = expander.expand(&task.macro_name, &task.macro_body, task.attributes.as_ref());
48+
49+
for (k, _) in &task.env {
50+
match &prev_env[k.as_str()] {
51+
Some(v) => env::set_var(k, v),
52+
None => env::remove_var(k),
53+
}
54+
}
55+
56+
match result {
4157
Ok(expansion) => Ok(ExpansionResult { expansion }),
4258
Err(msg) => {
4359
let msg = msg.as_str().unwrap_or("<unknown error>");

crates/tt/src/lib.rs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! `tt` crate defines a `TokenTree` data structure: this is the interface (both
22
//! input and output) of macros. It closely mirrors `proc_macro` crate's
33
//! `TokenTree`.
4-
use std::{fmt, panic::RefUnwindSafe};
4+
use std::fmt;
55

66
use stdx::impl_from;
77

@@ -247,8 +247,3 @@ impl fmt::Display for ExpansionError {
247247
}
248248
}
249249
}
250-
251-
pub trait TokenExpander: fmt::Debug + Send + Sync + RefUnwindSafe {
252-
fn expand(&self, subtree: &Subtree, attrs: Option<&Subtree>)
253-
-> Result<Subtree, ExpansionError>;
254-
}

0 commit comments

Comments
 (0)