mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-28 02:57:37 +00:00
proc_macro: Add Span::mixed_site
exposing macro_rules
hygiene
This commit is contained in:
parent
c6293e3598
commit
d1310dc6c9
@ -148,6 +148,7 @@ macro_rules! with_api {
|
||||
fn debug($self: $S::Span) -> String;
|
||||
fn def_site() -> $S::Span;
|
||||
fn call_site() -> $S::Span;
|
||||
fn mixed_site() -> $S::Span;
|
||||
fn source_file($self: $S::Span) -> $S::SourceFile;
|
||||
fn parent($self: $S::Span) -> Option<$S::Span>;
|
||||
fn source($self: $S::Span) -> $S::Span;
|
||||
|
@ -271,6 +271,15 @@ impl Span {
|
||||
Span(bridge::client::Span::call_site())
|
||||
}
|
||||
|
||||
/// A span that represents `macro_rules` hygiene, and sometimes resolves at the macro
|
||||
/// definition site (local variables, labels, `$crate`) and sometimes at the macro
|
||||
/// call site (everything else).
|
||||
/// The span location is taken from the call-site.
|
||||
#[unstable(feature = "proc_macro_mixed_site", issue = "65049")]
|
||||
pub fn mixed_site() -> Span {
|
||||
Span(bridge::client::Span::mixed_site())
|
||||
}
|
||||
|
||||
/// The original source file into which this span points.
|
||||
#[unstable(feature = "proc_macro_span", issue = "54725")]
|
||||
pub fn source_file(&self) -> SourceFile {
|
||||
|
@ -953,6 +953,12 @@ impl<'a> ExtCtxt<'a> {
|
||||
span.with_call_site_ctxt(self.current_expansion.id)
|
||||
}
|
||||
|
||||
/// Equivalent of `Span::mixed_site` from the proc macro API,
|
||||
/// except that the location is taken from the span passed as an argument.
|
||||
pub fn with_mixed_site_ctxt(&self, span: Span) -> Span {
|
||||
span.with_mixed_site_ctxt(self.current_expansion.id)
|
||||
}
|
||||
|
||||
/// Returns span for the macro which originally caused the current expansion to happen.
|
||||
///
|
||||
/// Stops backtracing at include! boundary.
|
||||
|
@ -355,6 +355,7 @@ pub(crate) struct Rustc<'a> {
|
||||
sess: &'a ParseSess,
|
||||
def_site: Span,
|
||||
call_site: Span,
|
||||
mixed_site: Span,
|
||||
}
|
||||
|
||||
impl<'a> Rustc<'a> {
|
||||
@ -364,6 +365,7 @@ impl<'a> Rustc<'a> {
|
||||
sess: cx.parse_sess,
|
||||
def_site: cx.with_def_site_ctxt(expn_data.def_site),
|
||||
call_site: cx.with_call_site_ctxt(expn_data.call_site),
|
||||
mixed_site: cx.with_mixed_site_ctxt(expn_data.call_site),
|
||||
}
|
||||
}
|
||||
|
||||
@ -664,6 +666,9 @@ impl server::Span for Rustc<'_> {
|
||||
fn call_site(&mut self) -> Self::Span {
|
||||
self.call_site
|
||||
}
|
||||
fn mixed_site(&mut self) -> Self::Span {
|
||||
self.mixed_site
|
||||
}
|
||||
fn source_file(&mut self, span: Self::Span) -> Self::SourceFile {
|
||||
self.sess.source_map().lookup_char_pos(span.lo()).file
|
||||
}
|
||||
|
@ -526,6 +526,12 @@ impl Span {
|
||||
self.with_ctxt_from_mark(expn_id, Transparency::Transparent)
|
||||
}
|
||||
|
||||
/// Equivalent of `Span::mixed_site` from the proc macro API,
|
||||
/// except that the location is taken from the `self` span.
|
||||
pub fn with_mixed_site_ctxt(&self, expn_id: ExpnId) -> Span {
|
||||
self.with_ctxt_from_mark(expn_id, Transparency::SemiTransparent)
|
||||
}
|
||||
|
||||
/// Produces a span with the same location as `self` and context produced by a macro with the
|
||||
/// given ID and transparency, assuming that macro was defined directly and not produced by
|
||||
/// some other macro (which is the case for built-in and procedural macros).
|
||||
|
42
src/test/ui/proc-macro/auxiliary/mixed-site-span.rs
Normal file
42
src/test/ui/proc-macro/auxiliary/mixed-site-span.rs
Normal file
@ -0,0 +1,42 @@
|
||||
// force-host
|
||||
// no-prefer-dynamic
|
||||
|
||||
#![feature(proc_macro_hygiene)]
|
||||
#![feature(proc_macro_mixed_site)]
|
||||
#![feature(proc_macro_quote)]
|
||||
|
||||
#![crate_type = "proc-macro"]
|
||||
|
||||
extern crate proc_macro;
|
||||
use proc_macro::*;
|
||||
|
||||
#[proc_macro]
|
||||
pub fn proc_macro_rules(input: TokenStream) -> TokenStream {
|
||||
if input.is_empty() {
|
||||
let id = |s| TokenTree::from(Ident::new(s, Span::mixed_site()));
|
||||
let item_def = id("ItemDef");
|
||||
let local_def = id("local_def");
|
||||
let item_use = id("ItemUse");
|
||||
let local_use = id("local_use");
|
||||
let mut single_quote = Punct::new('\'', Spacing::Joint);
|
||||
single_quote.set_span(Span::mixed_site());
|
||||
let label_use: TokenStream = [
|
||||
TokenTree::from(single_quote),
|
||||
id("label_use"),
|
||||
].iter().cloned().collect();
|
||||
quote!(
|
||||
struct $item_def;
|
||||
let $local_def = 0;
|
||||
|
||||
$item_use; // OK
|
||||
$local_use; // ERROR
|
||||
break $label_use; // ERROR
|
||||
)
|
||||
} else {
|
||||
let mut dollar_crate = input.into_iter().next().unwrap();
|
||||
dollar_crate.set_span(Span::mixed_site());
|
||||
quote!(
|
||||
type A = $dollar_crate::ItemUse;
|
||||
)
|
||||
}
|
||||
}
|
@ -59,54 +59,54 @@ PRINT-ATTR RE-COLLECTED (DISPLAY): struct B (identity ! ($crate :: S)) ;
|
||||
PRINT-ATTR INPUT (DEBUG): TokenStream [
|
||||
Ident {
|
||||
ident: "struct",
|
||||
span: #8 bytes(LO..HI),
|
||||
span: #10 bytes(LO..HI),
|
||||
},
|
||||
Ident {
|
||||
ident: "B",
|
||||
span: #8 bytes(LO..HI),
|
||||
span: #10 bytes(LO..HI),
|
||||
},
|
||||
Group {
|
||||
delimiter: Parenthesis,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
ident: "identity",
|
||||
span: #8 bytes(LO..HI),
|
||||
span: #10 bytes(LO..HI),
|
||||
},
|
||||
Punct {
|
||||
ch: '!',
|
||||
spacing: Alone,
|
||||
span: #8 bytes(LO..HI),
|
||||
span: #10 bytes(LO..HI),
|
||||
},
|
||||
Group {
|
||||
delimiter: Parenthesis,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
ident: "$crate",
|
||||
span: #8 bytes(LO..HI),
|
||||
span: #10 bytes(LO..HI),
|
||||
},
|
||||
Punct {
|
||||
ch: ':',
|
||||
spacing: Joint,
|
||||
span: #8 bytes(LO..HI),
|
||||
span: #10 bytes(LO..HI),
|
||||
},
|
||||
Punct {
|
||||
ch: ':',
|
||||
spacing: Alone,
|
||||
span: #8 bytes(LO..HI),
|
||||
span: #10 bytes(LO..HI),
|
||||
},
|
||||
Ident {
|
||||
ident: "S",
|
||||
span: #8 bytes(LO..HI),
|
||||
span: #10 bytes(LO..HI),
|
||||
},
|
||||
],
|
||||
span: #8 bytes(LO..HI),
|
||||
span: #10 bytes(LO..HI),
|
||||
},
|
||||
],
|
||||
span: #8 bytes(LO..HI),
|
||||
span: #10 bytes(LO..HI),
|
||||
},
|
||||
Punct {
|
||||
ch: ';',
|
||||
spacing: Alone,
|
||||
span: #8 bytes(LO..HI),
|
||||
span: #10 bytes(LO..HI),
|
||||
},
|
||||
]
|
||||
|
@ -124,40 +124,40 @@ PRINT-BANG INPUT (DISPLAY): struct M ($crate :: S) ;
|
||||
PRINT-BANG INPUT (DEBUG): TokenStream [
|
||||
Ident {
|
||||
ident: "struct",
|
||||
span: #10 bytes(LO..HI),
|
||||
span: #13 bytes(LO..HI),
|
||||
},
|
||||
Ident {
|
||||
ident: "M",
|
||||
span: #10 bytes(LO..HI),
|
||||
span: #13 bytes(LO..HI),
|
||||
},
|
||||
Group {
|
||||
delimiter: Parenthesis,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
ident: "$crate",
|
||||
span: #10 bytes(LO..HI),
|
||||
span: #13 bytes(LO..HI),
|
||||
},
|
||||
Punct {
|
||||
ch: ':',
|
||||
spacing: Joint,
|
||||
span: #10 bytes(LO..HI),
|
||||
span: #13 bytes(LO..HI),
|
||||
},
|
||||
Punct {
|
||||
ch: ':',
|
||||
spacing: Alone,
|
||||
span: #10 bytes(LO..HI),
|
||||
span: #13 bytes(LO..HI),
|
||||
},
|
||||
Ident {
|
||||
ident: "S",
|
||||
span: #10 bytes(LO..HI),
|
||||
span: #13 bytes(LO..HI),
|
||||
},
|
||||
],
|
||||
span: #10 bytes(LO..HI),
|
||||
span: #13 bytes(LO..HI),
|
||||
},
|
||||
Punct {
|
||||
ch: ';',
|
||||
spacing: Alone,
|
||||
span: #10 bytes(LO..HI),
|
||||
span: #13 bytes(LO..HI),
|
||||
},
|
||||
]
|
||||
PRINT-ATTR INPUT (DISPLAY): struct A(::dollar_crate_external::S);
|
||||
@ -165,40 +165,40 @@ PRINT-ATTR RE-COLLECTED (DISPLAY): struct A ($crate :: S) ;
|
||||
PRINT-ATTR INPUT (DEBUG): TokenStream [
|
||||
Ident {
|
||||
ident: "struct",
|
||||
span: #10 bytes(LO..HI),
|
||||
span: #13 bytes(LO..HI),
|
||||
},
|
||||
Ident {
|
||||
ident: "A",
|
||||
span: #10 bytes(LO..HI),
|
||||
span: #13 bytes(LO..HI),
|
||||
},
|
||||
Group {
|
||||
delimiter: Parenthesis,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
ident: "$crate",
|
||||
span: #10 bytes(LO..HI),
|
||||
span: #13 bytes(LO..HI),
|
||||
},
|
||||
Punct {
|
||||
ch: ':',
|
||||
spacing: Joint,
|
||||
span: #10 bytes(LO..HI),
|
||||
span: #13 bytes(LO..HI),
|
||||
},
|
||||
Punct {
|
||||
ch: ':',
|
||||
spacing: Alone,
|
||||
span: #10 bytes(LO..HI),
|
||||
span: #13 bytes(LO..HI),
|
||||
},
|
||||
Ident {
|
||||
ident: "S",
|
||||
span: #10 bytes(LO..HI),
|
||||
span: #13 bytes(LO..HI),
|
||||
},
|
||||
],
|
||||
span: #10 bytes(LO..HI),
|
||||
span: #13 bytes(LO..HI),
|
||||
},
|
||||
Punct {
|
||||
ch: ';',
|
||||
spacing: Alone,
|
||||
span: #10 bytes(LO..HI),
|
||||
span: #13 bytes(LO..HI),
|
||||
},
|
||||
]
|
||||
PRINT-DERIVE INPUT (DISPLAY): struct D(::dollar_crate_external::S);
|
||||
@ -206,39 +206,39 @@ PRINT-DERIVE RE-COLLECTED (DISPLAY): struct D ($crate :: S) ;
|
||||
PRINT-DERIVE INPUT (DEBUG): TokenStream [
|
||||
Ident {
|
||||
ident: "struct",
|
||||
span: #10 bytes(LO..HI),
|
||||
span: #13 bytes(LO..HI),
|
||||
},
|
||||
Ident {
|
||||
ident: "D",
|
||||
span: #10 bytes(LO..HI),
|
||||
span: #13 bytes(LO..HI),
|
||||
},
|
||||
Group {
|
||||
delimiter: Parenthesis,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
ident: "$crate",
|
||||
span: #10 bytes(LO..HI),
|
||||
span: #13 bytes(LO..HI),
|
||||
},
|
||||
Punct {
|
||||
ch: ':',
|
||||
spacing: Joint,
|
||||
span: #10 bytes(LO..HI),
|
||||
span: #13 bytes(LO..HI),
|
||||
},
|
||||
Punct {
|
||||
ch: ':',
|
||||
spacing: Alone,
|
||||
span: #10 bytes(LO..HI),
|
||||
span: #13 bytes(LO..HI),
|
||||
},
|
||||
Ident {
|
||||
ident: "S",
|
||||
span: #10 bytes(LO..HI),
|
||||
span: #13 bytes(LO..HI),
|
||||
},
|
||||
],
|
||||
span: #10 bytes(LO..HI),
|
||||
span: #13 bytes(LO..HI),
|
||||
},
|
||||
Punct {
|
||||
ch: ';',
|
||||
spacing: Alone,
|
||||
span: #10 bytes(LO..HI),
|
||||
span: #13 bytes(LO..HI),
|
||||
},
|
||||
]
|
||||
|
26
src/test/ui/proc-macro/mixed-site-span.rs
Normal file
26
src/test/ui/proc-macro/mixed-site-span.rs
Normal file
@ -0,0 +1,26 @@
|
||||
// Proc macros using `mixed_site` spans exhibit usual properties of `macro_rules` hygiene.
|
||||
|
||||
// aux-build:mixed-site-span.rs
|
||||
|
||||
#![feature(proc_macro_hygiene)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate mixed_site_span;
|
||||
|
||||
struct ItemUse;
|
||||
|
||||
fn main() {
|
||||
'label_use: loop {
|
||||
let local_use = 1;
|
||||
proc_macro_rules!();
|
||||
//~^ ERROR use of undeclared label `'label_use`
|
||||
//~| ERROR cannot find value `local_use` in this scope
|
||||
ItemDef; // OK
|
||||
local_def; //~ ERROR cannot find value `local_def` in this scope
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! pass_dollar_crate {
|
||||
() => (proc_macro_rules!($crate);) //~ ERROR cannot find type `ItemUse` in crate `$crate`
|
||||
}
|
||||
pass_dollar_crate!();
|
49
src/test/ui/proc-macro/mixed-site-span.stderr
Normal file
49
src/test/ui/proc-macro/mixed-site-span.stderr
Normal file
@ -0,0 +1,49 @@
|
||||
error[E0426]: use of undeclared label `'label_use`
|
||||
--> $DIR/mixed-site-span.rs:15:9
|
||||
|
|
||||
LL | proc_macro_rules!();
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| undeclared label `'label_use`
|
||||
| in this macro invocation
|
||||
|
||||
error[E0425]: cannot find value `local_use` in this scope
|
||||
--> $DIR/mixed-site-span.rs:15:9
|
||||
|
|
||||
LL | proc_macro_rules!();
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| not found in this scope
|
||||
| in this macro invocation
|
||||
|
||||
error[E0425]: cannot find value `local_def` in this scope
|
||||
--> $DIR/mixed-site-span.rs:19:9
|
||||
|
|
||||
LL | local_def;
|
||||
| ^^^^^^^^^ not found in this scope
|
||||
|
||||
error[E0412]: cannot find type `ItemUse` in crate `$crate`
|
||||
--> $DIR/auxiliary/mixed-site-span.rs:14:1
|
||||
|
|
||||
LL | / pub fn proc_macro_rules(input: TokenStream) -> TokenStream {
|
||||
LL | | if input.is_empty() {
|
||||
LL | | let id = |s| TokenTree::from(Ident::new(s, Span::mixed_site()));
|
||||
LL | | let item_def = id("ItemDef");
|
||||
... |
|
||||
LL | | }
|
||||
LL | | }
|
||||
| |_^ not found in `$crate`
|
||||
|
|
||||
::: $DIR/mixed-site-span.rs:26:1
|
||||
|
|
||||
LL | pass_dollar_crate!();
|
||||
| --------------------- in this macro invocation
|
||||
help: possible candidate is found in another module, you can import it into scope
|
||||
|
|
||||
LL | use ItemUse;
|
||||
|
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0412, E0425, E0426.
|
||||
For more information about an error, try `rustc --explain E0412`.
|
Loading…
Reference in New Issue
Block a user