Skip to content

Commit e9991a0

Browse files
author
Alexander Regueiro
committed
Fixed bug with modification of SyntaxContext for escaped idents.
1 parent 8c000de commit e9991a0

File tree

4 files changed

+82
-55
lines changed

4 files changed

+82
-55
lines changed

src/libsyntax/ext/tt/macro_rules.rs

+9-5
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ pub fn compile(sess: &ParseSess, features: &Features, def: &ast::Item) -> Syntax
202202
quoted::TokenTree::Sequence(DUMMY_SP, Lrc::new(quoted::SequenceRepetition {
203203
tts: vec![
204204
quoted::TokenTree::MetaVarDecl(DUMMY_SP, lhs_nm, ast::Ident::from_str("tt")),
205-
quoted::TokenTree::Token(DUMMY_SP, token::FatArrow, false),
205+
quoted::TokenTree::Token(DUMMY_SP, token::FatArrow, quoted::TokenHygiene::DefSite),
206206
quoted::TokenTree::MetaVarDecl(DUMMY_SP, rhs_nm, ast::Ident::from_str("tt")),
207207
],
208208
separator: Some(if body.legacy { token::Semi } else { token::Comma }),
@@ -211,7 +211,8 @@ pub fn compile(sess: &ParseSess, features: &Features, def: &ast::Item) -> Syntax
211211
})),
212212
// to phase into semicolon-termination instead of semicolon-separation
213213
quoted::TokenTree::Sequence(DUMMY_SP, Lrc::new(quoted::SequenceRepetition {
214-
tts: vec![quoted::TokenTree::Token(DUMMY_SP, token::Semi, false)],
214+
tts: vec![quoted::TokenTree::Token(DUMMY_SP, token::Semi,
215+
quoted::TokenHygiene::DefSite)],
215216
separator: None,
216217
op: quoted::KleeneOp::ZeroOrMore,
217218
num_captures: 0
@@ -454,7 +455,8 @@ impl FirstSets {
454455

455456
if let (Some(ref sep), true) = (seq_rep.separator.clone(),
456457
subfirst.maybe_empty) {
457-
first.add_one_maybe(TokenTree::Token(sp, sep.clone(), false));
458+
first.add_one_maybe(TokenTree::Token(sp, sep.clone(),
459+
quoted::TokenHygiene::DefSite));
458460
}
459461

460462
// Reverse scan: Sequence comes before `first`.
@@ -503,7 +505,8 @@ impl FirstSets {
503505

504506
if let (Some(ref sep), true) = (seq_rep.separator.clone(),
505507
subfirst.maybe_empty) {
506-
first.add_one_maybe(TokenTree::Token(sp, sep.clone(), false));
508+
first.add_one_maybe(TokenTree::Token(sp, sep.clone(),
509+
quoted::TokenHygiene::DefSite));
507510
}
508511

509512
assert!(first.maybe_empty);
@@ -710,7 +713,8 @@ fn check_matcher_core(sess: &ParseSess,
710713
let mut new;
711714
let my_suffix = if let Some(ref u) = seq_rep.separator {
712715
new = suffix_first.clone();
713-
new.add_one_maybe(TokenTree::Token(sp, u.clone(), false));
716+
new.add_one_maybe(TokenTree::Token(sp, u.clone(),
717+
quoted::TokenHygiene::DefSite));
714718
&new
715719
} else {
716720
&suffix_first

src/libsyntax/ext/tt/quoted.rs

+25-25
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ impl Delimited {
4646
} else {
4747
span.with_lo(span.lo() + BytePos(self.delim.len() as u32))
4848
};
49-
TokenTree::Token(open_span, self.open_token(), false)
49+
TokenTree::Token(open_span, self.open_token(), TokenHygiene::DefSite)
5050
}
5151

5252
/// Return a `self::TokenTree` with a `Span` corresponding to the closing delimiter.
@@ -56,7 +56,7 @@ impl Delimited {
5656
} else {
5757
span.with_lo(span.hi() - BytePos(self.delim.len() as u32))
5858
};
59-
TokenTree::Token(close_span, self.close_token(), false)
59+
TokenTree::Token(close_span, self.close_token(), TokenHygiene::DefSite)
6060
}
6161
}
6262

@@ -88,20 +88,12 @@ pub enum KleeneOp {
8888
/// are "first-class" token trees. Useful for parsing macros.
8989
#[derive(Debug, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash)]
9090
pub enum TokenTree {
91-
Token(
92-
Span,
93-
token::Token,
94-
bool, /* escape hygiene */
95-
),
91+
Token(Span, token::Token, TokenHygiene),
9692
Delimited(Span, Lrc<Delimited>),
9793
/// A Kleene-style repetition sequence
9894
Sequence(Span, Lrc<SequenceRepetition>),
9995
/// E.g. `$var`
100-
MetaVar(
101-
Span,
102-
ast::Ident,
103-
bool, /* escape hygiene */
104-
),
96+
MetaVar(Span, ast::Ident, TokenHygiene),
10597
/// E.g. `$var:expr`. This is only used in the left hand side of MBE macros.
10698
MetaVarDecl(
10799
Span,
@@ -168,6 +160,13 @@ impl TokenTree {
168160
}
169161
}
170162

163+
/// Syntaxt context to apply to a token when invoking a macro.
164+
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
165+
pub enum TokenHygiene {
166+
DefSite,
167+
CallSite,
168+
}
169+
171170
/// Takes a `tokenstream::TokenStream` and returns a `Vec<self::TokenTree>`. Specifically, this
172171
/// takes a generic `TokenStream`, such as is used in the rest of the compiler, and returns a
173172
/// collection of `TokenTree` for use in parsing a macro.
@@ -279,8 +278,8 @@ where
279278
tokenstream::TokenTree::Token(span, token::Pound) if hygiene_optout => match trees.peek() {
280279
Some(tokenstream::TokenTree::Token(_, token::Dollar)) => {
281280
if let tokenstream::TokenTree::Token(span, token::Dollar) = trees.next().unwrap() {
282-
parse_meta_var(true,
283-
span,
281+
parse_meta_var(span,
282+
TokenHygiene::CallSite,
284283
trees,
285284
hygiene_optout,
286285
expect_matchers,
@@ -295,7 +294,7 @@ where
295294
Some(tokenstream::TokenTree::Token(_, token::Ident(..))) => {
296295
if let tokenstream::TokenTree::Token(span, tok @ token::Ident(..)) =
297296
trees.next().unwrap() {
298-
TokenTree::Token(span, tok, true)
297+
TokenTree::Token(span, tok, TokenHygiene::CallSite)
299298
} else {
300299
unreachable!();
301300
}
@@ -304,19 +303,19 @@ where
304303
Some(tokenstream::TokenTree::Token(_, token::Lifetime(..))) => {
305304
if let tokenstream::TokenTree::Token(span, tok @ token::Lifetime(..)) =
306305
trees.next().unwrap() {
307-
TokenTree::Token(span, tok, true)
306+
TokenTree::Token(span, tok, TokenHygiene::CallSite)
308307
} else {
309308
unreachable!();
310309
}
311310
}
312311

313-
_ => TokenTree::Token(span, token::Pound, false),
312+
_ => TokenTree::Token(span, token::Pound, TokenHygiene::DefSite),
314313
}
315314

316315
// `tree` is a `$` token. Look at the next token in `trees`.
317316
tokenstream::TokenTree::Token(span, token::Dollar) =>
318-
parse_meta_var(false,
319-
span,
317+
parse_meta_var(span,
318+
TokenHygiene::DefSite,
320319
trees,
321320
hygiene_optout,
322321
expect_matchers,
@@ -325,7 +324,8 @@ where
325324
attrs),
326325

327326
// `tree` is an arbitrary token. Keep it.
328-
tokenstream::TokenTree::Token(span, tok) => TokenTree::Token(span, tok, false),
327+
tokenstream::TokenTree::Token(span, tok) =>
328+
TokenTree::Token(span, tok, TokenHygiene::DefSite),
329329

330330
// `tree` is the beginning of a delimited set of tokens (e.g. `(` or `{`). We need to
331331
// descend into the delimited set and further parse it.
@@ -346,8 +346,8 @@ where
346346

347347
/// Attempt to parse a single meta variable or meta variable sequence.
348348
fn parse_meta_var<I>(
349-
escape_hygiene: bool,
350349
span: Span,
350+
token_hygiene: TokenHygiene,
351351
trees: &mut Peekable<I>,
352352
hygiene_optout: bool,
353353
expect_matchers: bool,
@@ -399,9 +399,9 @@ where
399399
let span = ident_span.with_lo(span.lo());
400400
if ident.name == keywords::Crate.name() && !is_raw {
401401
let ident = ast::Ident::new(keywords::DollarCrate.name(), ident.span);
402-
TokenTree::Token(span, token::Ident(ident, is_raw), escape_hygiene)
402+
TokenTree::Token(span, token::Ident(ident, is_raw), token_hygiene)
403403
} else {
404-
TokenTree::MetaVar(span, ident, escape_hygiene)
404+
TokenTree::MetaVar(span, ident, token_hygiene)
405405
}
406406
}
407407

@@ -412,11 +412,11 @@ where
412412
pprust::token_to_string(&tok)
413413
);
414414
sess.span_diagnostic.span_err(span, &msg);
415-
TokenTree::MetaVar(span, keywords::Invalid.ident(), escape_hygiene)
415+
TokenTree::MetaVar(span, keywords::Invalid.ident(), token_hygiene)
416416
}
417417

418418
// There are no more tokens. Just return the `$` we already have.
419-
None => TokenTree::Token(span, token::Dollar, false),
419+
None => TokenTree::Token(span, token::Dollar, TokenHygiene::DefSite),
420420
}
421421
}
422422

src/libsyntax/ext/tt/transcribe.rs

+24-25
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ use ext::base::ExtCtxt;
1313
use ext::expand::Marker;
1414
use ext::tt::macro_parser::{NamedMatch, MatchedSeq, MatchedNonterminal};
1515
use ext::tt::quoted;
16-
use fold::noop_fold_tt;
16+
use fold::{Folder, noop_fold_tt};
1717
use parse::token::{self, Token, NtTT};
18-
use syntax_pos::{Span, DUMMY_SP};
18+
use syntax_pos::{Span, SyntaxContext, DUMMY_SP};
1919
use tokenstream::{TokenStream, TokenTree, Delimited};
2020
use util::small_vector::SmallVector;
2121

@@ -177,31 +177,15 @@ pub fn transcribe(cx: &ExtCtxt,
177177
stack.push(Frame::Delimited { forest: delimited, idx: 0, span: span });
178178
result_stack.push(mem::replace(&mut result, Vec::new()));
179179
}
180-
quoted::TokenTree::Token(sp, tok, escape_hygiene) => {
181-
let sp_ctxt = if escape_hygiene { cx.call_site() } else { sp }.ctxt();
182-
let sp = sp.with_ctxt(sp_ctxt.apply_mark(cx.current_expansion.mark));
183-
184-
let update_ident_ctxt = |ident: Ident| {
185-
let new_span = if escape_hygiene {
186-
cx.call_site()
187-
} else {
188-
ident.span.apply_mark(cx.current_expansion.mark)
189-
};
190-
Ident::new(ident.name, new_span)
191-
};
192-
193-
let result_tok = match tok {
194-
token::Ident(ident, is_raw) =>
195-
TokenTree::Token(sp, token::Ident(update_ident_ctxt(ident), is_raw)),
196-
token::Lifetime(ident) =>
197-
TokenTree::Token(sp, token::Lifetime()),
198-
_ => {
199-
let mut marker = Marker(cx.current_expansion.mark);
200-
noop_fold_tt(TokenTree::Token(sp, tok), &mut marker)
201-
}
180+
quoted::TokenTree::Token(sp, tok, hygiene) => {
181+
let mut new_tok = match hygiene {
182+
quoted::TokenHygiene::DefSite => noop_fold_tt(TokenTree::Token(sp, tok),
183+
&mut Marker(cx.current_expansion.mark)),
184+
quoted::TokenHygiene::CallSite => noop_fold_tt(TokenTree::Token(sp, tok),
185+
&mut Escaper(cx.call_site().ctxt())),
202186
};
203187

204-
result.push(result_tok.into());
188+
result.push(new_tok.into());
205189
}
206190
quoted::TokenTree::MetaVarDecl(..) => panic!("unexpected `TokenTree::MetaVarDecl"),
207191
}
@@ -282,3 +266,18 @@ fn lockstep_iter_size(tree: &quoted::TokenTree,
282266
TokenTree::Token(..) => LockstepIterSize::Unconstrained,
283267
}
284268
}
269+
270+
// An Escaper escapes the syntax context with the given syntax context.
271+
#[derive(Debug)]
272+
pub struct Escaper(pub SyntaxContext);
273+
274+
impl Folder for Escaper {
275+
fn fold_ident(&mut self, mut ident: Ident) -> Ident {
276+
ident.span = ident.span.with_ctxt(self.0);
277+
ident
278+
}
279+
280+
fn new_span(&mut self, span: Span) -> Span {
281+
span.with_ctxt(self.0)
282+
}
283+
}
+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(decl_macro)]
12+
13+
macro m() {
14+
struct #S;
15+
16+
impl S {
17+
//~^ ERROR cannot find type `S` in this scope
18+
fn f() {}
19+
}
20+
}
21+
22+
fn main() {
23+
m!();
24+
}

0 commit comments

Comments
 (0)