diff options
Diffstat (limited to 'library/proc_macro')
-rw-r--r-- | library/proc_macro/src/bridge/client.rs | 2 | ||||
-rw-r--r-- | library/proc_macro/src/bridge/mod.rs | 29 | ||||
-rw-r--r-- | library/proc_macro/src/bridge/server.rs | 39 | ||||
-rw-r--r-- | library/proc_macro/src/diagnostic.rs | 21 | ||||
-rw-r--r-- | library/proc_macro/src/lib.rs | 7 |
5 files changed, 57 insertions, 41 deletions
diff --git a/library/proc_macro/src/bridge/client.rs b/library/proc_macro/src/bridge/client.rs index 1516f084a..4461b2180 100644 --- a/library/proc_macro/src/bridge/client.rs +++ b/library/proc_macro/src/bridge/client.rs @@ -176,8 +176,6 @@ define_handles! { FreeFunctions, TokenStream, SourceFile, - MultiSpan, - Diagnostic, 'interned: Span, diff --git a/library/proc_macro/src/bridge/mod.rs b/library/proc_macro/src/bridge/mod.rs index 5cde966bf..4c1e196b5 100644 --- a/library/proc_macro/src/bridge/mod.rs +++ b/library/proc_macro/src/bridge/mod.rs @@ -57,6 +57,7 @@ macro_rules! with_api { fn track_env_var(var: &str, value: Option<&str>); fn track_path(path: &str); fn literal_from_str(s: &str) -> Result<Literal<$S::Span, $S::Symbol>, ()>; + fn emit_diagnostic(diagnostic: Diagnostic<$S::Span>); }, TokenStream { fn drop($self: $S::TokenStream); @@ -87,22 +88,6 @@ macro_rules! with_api { 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 source_file($self: $S::Span) -> $S::SourceFile; @@ -510,6 +495,18 @@ compound_traits!( } ); +#[derive(Clone, Debug)] +pub struct Diagnostic<Span> { + pub level: Level, + pub message: String, + pub spans: Vec<Span>, + pub children: Vec<Diagnostic<Span>>, +} + +compound_traits!( + struct Diagnostic<Span> { level, message, spans, children } +); + /// Globals provided alongside the initial inputs for a macro expansion. /// Provides values such as spans which are used frequently to avoid RPC. #[derive(Clone)] diff --git a/library/proc_macro/src/bridge/server.rs b/library/proc_macro/src/bridge/server.rs index e068ec60b..8202c40d6 100644 --- a/library/proc_macro/src/bridge/server.rs +++ b/library/proc_macro/src/bridge/server.rs @@ -2,6 +2,7 @@ use super::*; +use std::cell::Cell; use std::marker::PhantomData; // FIXME(eddyb) generate the definition of `HandleStore` in `server.rs`. @@ -11,8 +12,6 @@ pub trait Types { type FreeFunctions: 'static; type TokenStream: 'static + Clone; type SourceFile: 'static + Clone; - type MultiSpan: 'static; - type Diagnostic: 'static; type Span: 'static + Copy + Eq + Hash; type Symbol: 'static; } @@ -145,6 +144,38 @@ pub trait ExecutionStrategy { ) -> Buffer; } +thread_local! { + /// While running a proc-macro with the same-thread executor, this flag will + /// be set, forcing nested proc-macro invocations (e.g. due to + /// `TokenStream::expand_expr`) to be run using a cross-thread executor. + /// + /// This is required as the thread-local state in the proc_macro client does + /// not handle being re-entered, and will invalidate all `Symbol`s when + /// entering a nested macro. + static ALREADY_RUNNING_SAME_THREAD: Cell<bool> = Cell::new(false); +} + +/// Keep `ALREADY_RUNNING_SAME_THREAD` (see also its documentation) +/// set to `true`, preventing same-thread reentrance. +struct RunningSameThreadGuard(()); + +impl RunningSameThreadGuard { + fn new() -> Self { + let already_running = ALREADY_RUNNING_SAME_THREAD.replace(true); + assert!( + !already_running, + "same-thread nesting (\"reentrance\") of proc macro executions is not supported" + ); + RunningSameThreadGuard(()) + } +} + +impl Drop for RunningSameThreadGuard { + fn drop(&mut self) { + ALREADY_RUNNING_SAME_THREAD.set(false); + } +} + pub struct MaybeCrossThread<P> { cross_thread: bool, marker: PhantomData<P>, @@ -167,7 +198,7 @@ where run_client: extern "C" fn(BridgeConfig<'_>) -> Buffer, force_show_panics: bool, ) -> Buffer { - if self.cross_thread { + if self.cross_thread || ALREADY_RUNNING_SAME_THREAD.get() { <CrossThread<P>>::new().run_bridge_and_client( dispatcher, input, @@ -190,6 +221,8 @@ impl ExecutionStrategy for SameThread { run_client: extern "C" fn(BridgeConfig<'_>) -> Buffer, force_show_panics: bool, ) -> Buffer { + let _guard = RunningSameThreadGuard::new(); + let mut dispatch = |buf| dispatcher.dispatch(buf); run_client(BridgeConfig { diff --git a/library/proc_macro/src/diagnostic.rs b/library/proc_macro/src/diagnostic.rs index 6e46dc036..5a209f7c7 100644 --- a/library/proc_macro/src/diagnostic.rs +++ b/library/proc_macro/src/diagnostic.rs @@ -161,22 +161,15 @@ impl Diagnostic { /// Emit the diagnostic. #[unstable(feature = "proc_macro_diagnostic", issue = "54140")] pub fn emit(self) { - fn to_internal(spans: Vec<Span>) -> crate::bridge::client::MultiSpan { - let mut multi_span = crate::bridge::client::MultiSpan::new(); - for span in spans { - multi_span.push(span.0); + fn to_internal(diag: Diagnostic) -> crate::bridge::Diagnostic<crate::bridge::client::Span> { + crate::bridge::Diagnostic { + level: diag.level, + message: diag.message, + spans: diag.spans.into_iter().map(|s| s.0).collect(), + children: diag.children.into_iter().map(to_internal).collect(), } - multi_span } - let mut diag = crate::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(); + crate::bridge::client::FreeFunctions::emit_diagnostic(to_internal(self)); } } diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index 8e478cd7b..495c1c5ae 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -1353,12 +1353,7 @@ impl Literal { /// Byte string literal. #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub fn byte_string(bytes: &[u8]) -> Literal { - let string = bytes - .iter() - .cloned() - .flat_map(std::ascii::escape_default) - .map(Into::<char>::into) - .collect::<String>(); + let string = bytes.escape_ascii().to_string(); Literal::new(bridge::LitKind::ByteStr, &string, None) } |