diff --git a/src/libproc_macro/bridge/mod.rs b/src/libproc_macro/bridge/mod.rs index 3c48466fffa28..f80a567a6888d 100644 --- a/src/libproc_macro/bridge/mod.rs +++ b/src/libproc_macro/bridge/mod.rs @@ -146,6 +146,7 @@ macro_rules! with_api { }, Span { fn debug($self: $S::Span) -> String; + fn unique_site() -> $S::Span; fn def_site() -> $S::Span; fn call_site() -> $S::Span; fn source_file($self: $S::Span) -> $S::SourceFile; diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs index 1e0f1ed578aae..e213491f9de6c 100644 --- a/src/libproc_macro/lib.rs +++ b/src/libproc_macro/lib.rs @@ -255,6 +255,14 @@ macro_rules! diagnostic_method { } impl Span { + /// A span that resolves at a unique site. Each call to this method will return a new unique + /// span that is inaccessible from other sites. For those familiar with Lisp, this is similar to + /// [gensym](http://www.lispworks.com/documentation/lw50/CLHS/Body/f_gensym.htm). + #[unstable(feature = "proc_macro_unique_site", issue = "54725")] + pub fn unique_site() -> Span { + Span(bridge::client::Span::unique_site()) + } + /// A span that resolves at the macro definition site. #[unstable(feature = "proc_macro_def_site", issue = "54724")] pub fn def_site() -> Span { diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 864fc2ebaec77..73d3daa58d4c2 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -2306,7 +2306,7 @@ impl<'a> Resolver<'a> { let mut result = None; // Find the last modern mark from the end if it exists. while let Some(&(mark, transparency)) = iter.peek() { - if transparency == Transparency::Opaque { + if transparency >= Transparency::Opaque { result = Some(mark); iter.next(); } else { diff --git a/src/libsyntax_ext/proc_macro_server.rs b/src/libsyntax_ext/proc_macro_server.rs index 09dce77579001..855a0d5e2fb25 100644 --- a/src/libsyntax_ext/proc_macro_server.rs +++ b/src/libsyntax_ext/proc_macro_server.rs @@ -8,12 +8,13 @@ use proc_macro::{Delimiter, Level, LineColumn, Spacing}; use rustc_data_structures::sync::Lrc; use std::ascii; use std::ops::Bound; +use std::sync::atomic; use syntax::ast; use syntax::ext::base::ExtCtxt; use syntax::parse::lexer::comments; use syntax::parse::{self, token, ParseSess}; use syntax::tokenstream::{self, DelimSpan, IsJoint::*, TokenStream, TreeAndJoint}; -use syntax_pos::hygiene::{SyntaxContext, Transparency}; +use syntax_pos::hygiene::{Mark, SyntaxContext, Transparency}; use syntax_pos::symbol::{keywords, Symbol}; use syntax_pos::{BytePos, FileName, MultiSpan, Pos, SourceFile, Span}; @@ -363,6 +364,7 @@ pub(crate) struct Rustc<'a> { sess: &'a ParseSess, def_site: Span, call_site: Span, + mark: Mark, } impl<'a> Rustc<'a> { @@ -379,6 +381,7 @@ impl<'a> Rustc<'a> { sess: cx.parse_sess, def_site: to_span(Transparency::Opaque), call_site: to_span(Transparency::Transparent), + mark: cx.current_expansion.mark, } } } @@ -698,6 +701,13 @@ impl server::Span for Rustc<'_> { fn debug(&mut self, span: Self::Span) -> String { format!("{:?} bytes({}..{})", span.ctxt(), span.lo().0, span.hi().0) } + fn unique_site(&mut self) -> Self::Span { + static UNIQUE: atomic::AtomicU64 = atomic::AtomicU64::new(0); + let transparency = Transparency::Unique(UNIQUE.fetch_add(1, atomic::Ordering::Relaxed)); + self.mark.expn_info().unwrap().call_site.with_ctxt( + SyntaxContext::empty().apply_mark_with_transparency(self.mark, transparency), + ) + } fn def_site(&mut self) -> Self::Span { self.def_site } diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index 1ffecea44edf2..97677b9b4108c 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -60,6 +60,7 @@ pub enum Transparency { /// Identifier produced by an opaque expansion is always resolved at definition-site. /// Def-site spans in procedural macros, identifiers from `macro` by default use this. Opaque, + Unique(u64), } impl Mark { @@ -273,7 +274,7 @@ impl SyntaxContext { pub fn apply_mark_with_transparency(self, mark: Mark, transparency: Transparency) -> SyntaxContext { assert_ne!(mark, Mark::root()); - if transparency == Transparency::Opaque { + if transparency >= Transparency::Opaque { return self.apply_mark_internal(mark, transparency); }