Skip to content

Commit d1310dc

Browse files
committed
proc_macro: Add Span::mixed_site exposing macro_rules hygiene
1 parent c6293e3 commit d1310dc

File tree

10 files changed

+179
-35
lines changed

10 files changed

+179
-35
lines changed

src/libproc_macro/bridge/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ macro_rules! with_api {
148148
fn debug($self: $S::Span) -> String;
149149
fn def_site() -> $S::Span;
150150
fn call_site() -> $S::Span;
151+
fn mixed_site() -> $S::Span;
151152
fn source_file($self: $S::Span) -> $S::SourceFile;
152153
fn parent($self: $S::Span) -> Option<$S::Span>;
153154
fn source($self: $S::Span) -> $S::Span;

src/libproc_macro/lib.rs

+9
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,15 @@ impl Span {
271271
Span(bridge::client::Span::call_site())
272272
}
273273

274+
/// A span that represents `macro_rules` hygiene, and sometimes resolves at the macro
275+
/// definition site (local variables, labels, `$crate`) and sometimes at the macro
276+
/// call site (everything else).
277+
/// The span location is taken from the call-site.
278+
#[unstable(feature = "proc_macro_mixed_site", issue = "65049")]
279+
pub fn mixed_site() -> Span {
280+
Span(bridge::client::Span::mixed_site())
281+
}
282+
274283
/// The original source file into which this span points.
275284
#[unstable(feature = "proc_macro_span", issue = "54725")]
276285
pub fn source_file(&self) -> SourceFile {

src/libsyntax/ext/base.rs

+6
Original file line numberDiff line numberDiff line change
@@ -953,6 +953,12 @@ impl<'a> ExtCtxt<'a> {
953953
span.with_call_site_ctxt(self.current_expansion.id)
954954
}
955955

956+
/// Equivalent of `Span::mixed_site` from the proc macro API,
957+
/// except that the location is taken from the span passed as an argument.
958+
pub fn with_mixed_site_ctxt(&self, span: Span) -> Span {
959+
span.with_mixed_site_ctxt(self.current_expansion.id)
960+
}
961+
956962
/// Returns span for the macro which originally caused the current expansion to happen.
957963
///
958964
/// Stops backtracing at include! boundary.

src/libsyntax/ext/proc_macro_server.rs

+5
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,7 @@ pub(crate) struct Rustc<'a> {
355355
sess: &'a ParseSess,
356356
def_site: Span,
357357
call_site: Span,
358+
mixed_site: Span,
358359
}
359360

360361
impl<'a> Rustc<'a> {
@@ -364,6 +365,7 @@ impl<'a> Rustc<'a> {
364365
sess: cx.parse_sess,
365366
def_site: cx.with_def_site_ctxt(expn_data.def_site),
366367
call_site: cx.with_call_site_ctxt(expn_data.call_site),
368+
mixed_site: cx.with_mixed_site_ctxt(expn_data.call_site),
367369
}
368370
}
369371

@@ -664,6 +666,9 @@ impl server::Span for Rustc<'_> {
664666
fn call_site(&mut self) -> Self::Span {
665667
self.call_site
666668
}
669+
fn mixed_site(&mut self) -> Self::Span {
670+
self.mixed_site
671+
}
667672
fn source_file(&mut self, span: Self::Span) -> Self::SourceFile {
668673
self.sess.source_map().lookup_char_pos(span.lo()).file
669674
}

src/libsyntax_pos/lib.rs

+6
Original file line numberDiff line numberDiff line change
@@ -526,6 +526,12 @@ impl Span {
526526
self.with_ctxt_from_mark(expn_id, Transparency::Transparent)
527527
}
528528

529+
/// Equivalent of `Span::mixed_site` from the proc macro API,
530+
/// except that the location is taken from the `self` span.
531+
pub fn with_mixed_site_ctxt(&self, expn_id: ExpnId) -> Span {
532+
self.with_ctxt_from_mark(expn_id, Transparency::SemiTransparent)
533+
}
534+
529535
/// Produces a span with the same location as `self` and context produced by a macro with the
530536
/// given ID and transparency, assuming that macro was defined directly and not produced by
531537
/// some other macro (which is the case for built-in and procedural macros).
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// force-host
2+
// no-prefer-dynamic
3+
4+
#![feature(proc_macro_hygiene)]
5+
#![feature(proc_macro_mixed_site)]
6+
#![feature(proc_macro_quote)]
7+
8+
#![crate_type = "proc-macro"]
9+
10+
extern crate proc_macro;
11+
use proc_macro::*;
12+
13+
#[proc_macro]
14+
pub fn proc_macro_rules(input: TokenStream) -> TokenStream {
15+
if input.is_empty() {
16+
let id = |s| TokenTree::from(Ident::new(s, Span::mixed_site()));
17+
let item_def = id("ItemDef");
18+
let local_def = id("local_def");
19+
let item_use = id("ItemUse");
20+
let local_use = id("local_use");
21+
let mut single_quote = Punct::new('\'', Spacing::Joint);
22+
single_quote.set_span(Span::mixed_site());
23+
let label_use: TokenStream = [
24+
TokenTree::from(single_quote),
25+
id("label_use"),
26+
].iter().cloned().collect();
27+
quote!(
28+
struct $item_def;
29+
let $local_def = 0;
30+
31+
$item_use; // OK
32+
$local_use; // ERROR
33+
break $label_use; // ERROR
34+
)
35+
} else {
36+
let mut dollar_crate = input.into_iter().next().unwrap();
37+
dollar_crate.set_span(Span::mixed_site());
38+
quote!(
39+
type A = $dollar_crate::ItemUse;
40+
)
41+
}
42+
}

src/test/ui/proc-macro/dollar-crate-issue-62325.stdout

+11-11
Original file line numberDiff line numberDiff line change
@@ -59,54 +59,54 @@ PRINT-ATTR RE-COLLECTED (DISPLAY): struct B (identity ! ($crate :: S)) ;
5959
PRINT-ATTR INPUT (DEBUG): TokenStream [
6060
Ident {
6161
ident: "struct",
62-
span: #8 bytes(LO..HI),
62+
span: #10 bytes(LO..HI),
6363
},
6464
Ident {
6565
ident: "B",
66-
span: #8 bytes(LO..HI),
66+
span: #10 bytes(LO..HI),
6767
},
6868
Group {
6969
delimiter: Parenthesis,
7070
stream: TokenStream [
7171
Ident {
7272
ident: "identity",
73-
span: #8 bytes(LO..HI),
73+
span: #10 bytes(LO..HI),
7474
},
7575
Punct {
7676
ch: '!',
7777
spacing: Alone,
78-
span: #8 bytes(LO..HI),
78+
span: #10 bytes(LO..HI),
7979
},
8080
Group {
8181
delimiter: Parenthesis,
8282
stream: TokenStream [
8383
Ident {
8484
ident: "$crate",
85-
span: #8 bytes(LO..HI),
85+
span: #10 bytes(LO..HI),
8686
},
8787
Punct {
8888
ch: ':',
8989
spacing: Joint,
90-
span: #8 bytes(LO..HI),
90+
span: #10 bytes(LO..HI),
9191
},
9292
Punct {
9393
ch: ':',
9494
spacing: Alone,
95-
span: #8 bytes(LO..HI),
95+
span: #10 bytes(LO..HI),
9696
},
9797
Ident {
9898
ident: "S",
99-
span: #8 bytes(LO..HI),
99+
span: #10 bytes(LO..HI),
100100
},
101101
],
102-
span: #8 bytes(LO..HI),
102+
span: #10 bytes(LO..HI),
103103
},
104104
],
105-
span: #8 bytes(LO..HI),
105+
span: #10 bytes(LO..HI),
106106
},
107107
Punct {
108108
ch: ';',
109109
spacing: Alone,
110-
span: #8 bytes(LO..HI),
110+
span: #10 bytes(LO..HI),
111111
},
112112
]

src/test/ui/proc-macro/dollar-crate.stdout

+24-24
Original file line numberDiff line numberDiff line change
@@ -124,121 +124,121 @@ PRINT-BANG INPUT (DISPLAY): struct M ($crate :: S) ;
124124
PRINT-BANG INPUT (DEBUG): TokenStream [
125125
Ident {
126126
ident: "struct",
127-
span: #10 bytes(LO..HI),
127+
span: #13 bytes(LO..HI),
128128
},
129129
Ident {
130130
ident: "M",
131-
span: #10 bytes(LO..HI),
131+
span: #13 bytes(LO..HI),
132132
},
133133
Group {
134134
delimiter: Parenthesis,
135135
stream: TokenStream [
136136
Ident {
137137
ident: "$crate",
138-
span: #10 bytes(LO..HI),
138+
span: #13 bytes(LO..HI),
139139
},
140140
Punct {
141141
ch: ':',
142142
spacing: Joint,
143-
span: #10 bytes(LO..HI),
143+
span: #13 bytes(LO..HI),
144144
},
145145
Punct {
146146
ch: ':',
147147
spacing: Alone,
148-
span: #10 bytes(LO..HI),
148+
span: #13 bytes(LO..HI),
149149
},
150150
Ident {
151151
ident: "S",
152-
span: #10 bytes(LO..HI),
152+
span: #13 bytes(LO..HI),
153153
},
154154
],
155-
span: #10 bytes(LO..HI),
155+
span: #13 bytes(LO..HI),
156156
},
157157
Punct {
158158
ch: ';',
159159
spacing: Alone,
160-
span: #10 bytes(LO..HI),
160+
span: #13 bytes(LO..HI),
161161
},
162162
]
163163
PRINT-ATTR INPUT (DISPLAY): struct A(::dollar_crate_external::S);
164164
PRINT-ATTR RE-COLLECTED (DISPLAY): struct A ($crate :: S) ;
165165
PRINT-ATTR INPUT (DEBUG): TokenStream [
166166
Ident {
167167
ident: "struct",
168-
span: #10 bytes(LO..HI),
168+
span: #13 bytes(LO..HI),
169169
},
170170
Ident {
171171
ident: "A",
172-
span: #10 bytes(LO..HI),
172+
span: #13 bytes(LO..HI),
173173
},
174174
Group {
175175
delimiter: Parenthesis,
176176
stream: TokenStream [
177177
Ident {
178178
ident: "$crate",
179-
span: #10 bytes(LO..HI),
179+
span: #13 bytes(LO..HI),
180180
},
181181
Punct {
182182
ch: ':',
183183
spacing: Joint,
184-
span: #10 bytes(LO..HI),
184+
span: #13 bytes(LO..HI),
185185
},
186186
Punct {
187187
ch: ':',
188188
spacing: Alone,
189-
span: #10 bytes(LO..HI),
189+
span: #13 bytes(LO..HI),
190190
},
191191
Ident {
192192
ident: "S",
193-
span: #10 bytes(LO..HI),
193+
span: #13 bytes(LO..HI),
194194
},
195195
],
196-
span: #10 bytes(LO..HI),
196+
span: #13 bytes(LO..HI),
197197
},
198198
Punct {
199199
ch: ';',
200200
spacing: Alone,
201-
span: #10 bytes(LO..HI),
201+
span: #13 bytes(LO..HI),
202202
},
203203
]
204204
PRINT-DERIVE INPUT (DISPLAY): struct D(::dollar_crate_external::S);
205205
PRINT-DERIVE RE-COLLECTED (DISPLAY): struct D ($crate :: S) ;
206206
PRINT-DERIVE INPUT (DEBUG): TokenStream [
207207
Ident {
208208
ident: "struct",
209-
span: #10 bytes(LO..HI),
209+
span: #13 bytes(LO..HI),
210210
},
211211
Ident {
212212
ident: "D",
213-
span: #10 bytes(LO..HI),
213+
span: #13 bytes(LO..HI),
214214
},
215215
Group {
216216
delimiter: Parenthesis,
217217
stream: TokenStream [
218218
Ident {
219219
ident: "$crate",
220-
span: #10 bytes(LO..HI),
220+
span: #13 bytes(LO..HI),
221221
},
222222
Punct {
223223
ch: ':',
224224
spacing: Joint,
225-
span: #10 bytes(LO..HI),
225+
span: #13 bytes(LO..HI),
226226
},
227227
Punct {
228228
ch: ':',
229229
spacing: Alone,
230-
span: #10 bytes(LO..HI),
230+
span: #13 bytes(LO..HI),
231231
},
232232
Ident {
233233
ident: "S",
234-
span: #10 bytes(LO..HI),
234+
span: #13 bytes(LO..HI),
235235
},
236236
],
237-
span: #10 bytes(LO..HI),
237+
span: #13 bytes(LO..HI),
238238
},
239239
Punct {
240240
ch: ';',
241241
spacing: Alone,
242-
span: #10 bytes(LO..HI),
242+
span: #13 bytes(LO..HI),
243243
},
244244
]
+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Proc macros using `mixed_site` spans exhibit usual properties of `macro_rules` hygiene.
2+
3+
// aux-build:mixed-site-span.rs
4+
5+
#![feature(proc_macro_hygiene)]
6+
7+
#[macro_use]
8+
extern crate mixed_site_span;
9+
10+
struct ItemUse;
11+
12+
fn main() {
13+
'label_use: loop {
14+
let local_use = 1;
15+
proc_macro_rules!();
16+
//~^ ERROR use of undeclared label `'label_use`
17+
//~| ERROR cannot find value `local_use` in this scope
18+
ItemDef; // OK
19+
local_def; //~ ERROR cannot find value `local_def` in this scope
20+
}
21+
}
22+
23+
macro_rules! pass_dollar_crate {
24+
() => (proc_macro_rules!($crate);) //~ ERROR cannot find type `ItemUse` in crate `$crate`
25+
}
26+
pass_dollar_crate!();

0 commit comments

Comments
 (0)