mirror of
https://github.com/rust-lang/rust.git
synced 2025-06-06 20:28:33 +00:00
parser: Do not call bump
recursively
Token normalization is merged directly into `bump`. Special "unknown macro variable" diagnostic for unexpected `$`s is removed as preventing legal code from compiling.
This commit is contained in:
parent
0176a9eef8
commit
d33b3562e5
@ -856,8 +856,6 @@ fn parse_nt(p: &mut Parser<'_>, sp: Span, name: Symbol) -> Nonterminal {
|
|||||||
if name == sym::tt {
|
if name == sym::tt {
|
||||||
return token::NtTT(p.parse_token_tree());
|
return token::NtTT(p.parse_token_tree());
|
||||||
}
|
}
|
||||||
// check at the beginning and the parser checks after each bump
|
|
||||||
p.process_potential_macro_variable();
|
|
||||||
match parse_nt_inner(p, sp, name) {
|
match parse_nt_inner(p, sp, name) {
|
||||||
Ok(nt) => nt,
|
Ok(nt) => nt,
|
||||||
Err(mut err) => {
|
Err(mut err) => {
|
||||||
|
@ -267,7 +267,6 @@ fn generic_extension<'cx>(
|
|||||||
cx.current_expansion.module.mod_path.last().map(|id| id.to_string());
|
cx.current_expansion.module.mod_path.last().map(|id| id.to_string());
|
||||||
p.last_type_ascription = cx.current_expansion.prior_type_ascription;
|
p.last_type_ascription = cx.current_expansion.prior_type_ascription;
|
||||||
|
|
||||||
p.process_potential_macro_variable();
|
|
||||||
// Let the context choose how to interpret the result.
|
// Let the context choose how to interpret the result.
|
||||||
// Weird, but useful for X-macros.
|
// Weird, but useful for X-macros.
|
||||||
return Box::new(ParserAnyMacro {
|
return Box::new(ParserAnyMacro {
|
||||||
|
@ -404,7 +404,8 @@ impl<'a> Parser<'a> {
|
|||||||
subparser_name,
|
subparser_name,
|
||||||
};
|
};
|
||||||
|
|
||||||
parser.token = parser.next_tok();
|
// Make parser point to the first token.
|
||||||
|
parser.bump();
|
||||||
|
|
||||||
if let Some(directory) = directory {
|
if let Some(directory) = directory {
|
||||||
parser.directory = directory;
|
parser.directory = directory;
|
||||||
@ -418,7 +419,6 @@ impl<'a> Parser<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
parser.process_potential_macro_variable();
|
|
||||||
parser
|
parser
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -430,7 +430,7 @@ impl<'a> Parser<'a> {
|
|||||||
self.unnormalized_prev_token.as_ref().unwrap_or(&self.prev_token)
|
self.unnormalized_prev_token.as_ref().unwrap_or(&self.prev_token)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next_tok(&mut self) -> Token {
|
fn next_tok(&mut self, fallback_span: Span) -> Token {
|
||||||
let mut next = if self.desugar_doc_comments {
|
let mut next = if self.desugar_doc_comments {
|
||||||
self.token_cursor.next_desugared()
|
self.token_cursor.next_desugared()
|
||||||
} else {
|
} else {
|
||||||
@ -438,7 +438,7 @@ impl<'a> Parser<'a> {
|
|||||||
};
|
};
|
||||||
if next.span.is_dummy() {
|
if next.span.is_dummy() {
|
||||||
// Tweak the location for better diagnostics, but keep syntactic context intact.
|
// Tweak the location for better diagnostics, but keep syntactic context intact.
|
||||||
next.span = self.unnormalized_token().span.with_ctxt(next.span.ctxt());
|
next.span = fallback_span.with_ctxt(next.span.ctxt());
|
||||||
}
|
}
|
||||||
next
|
next
|
||||||
}
|
}
|
||||||
@ -896,6 +896,24 @@ impl<'a> Parser<'a> {
|
|||||||
self.parse_delim_comma_seq(token::Paren, f)
|
self.parse_delim_comma_seq(token::Paren, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Interpolated identifier (`$i: ident`) and lifetime (`$l: lifetime`)
|
||||||
|
// tokens are replaced with usual identifier and lifetime tokens,
|
||||||
|
// so the former are never encountered during normal parsing.
|
||||||
|
fn normalize_token(token: &Token) -> Option<Token> {
|
||||||
|
match &token.kind {
|
||||||
|
token::Interpolated(nt) => match **nt {
|
||||||
|
token::NtIdent(ident, is_raw) => {
|
||||||
|
Some(Token::new(token::Ident(ident.name, is_raw), ident.span))
|
||||||
|
}
|
||||||
|
token::NtLifetime(ident) => {
|
||||||
|
Some(Token::new(token::Lifetime(ident.name), ident.span))
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Advance the parser by one token.
|
/// Advance the parser by one token.
|
||||||
pub fn bump(&mut self) {
|
pub fn bump(&mut self) {
|
||||||
if self.prev_token.kind == TokenKind::Eof {
|
if self.prev_token.kind == TokenKind::Eof {
|
||||||
@ -905,16 +923,17 @@ impl<'a> Parser<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update the current and previous tokens.
|
// Update the current and previous tokens.
|
||||||
let next_token = self.next_tok();
|
self.prev_token = self.token.take();
|
||||||
self.prev_token = mem::replace(&mut self.token, next_token);
|
|
||||||
self.unnormalized_prev_token = self.unnormalized_token.take();
|
self.unnormalized_prev_token = self.unnormalized_token.take();
|
||||||
|
self.token = self.next_tok(self.unnormalized_prev_token().span);
|
||||||
|
if let Some(normalized_token) = Self::normalize_token(&self.token) {
|
||||||
|
self.unnormalized_token = Some(mem::replace(&mut self.token, normalized_token));
|
||||||
|
}
|
||||||
|
|
||||||
// Update fields derived from the previous token.
|
// Update fields derived from the previous token.
|
||||||
self.prev_span = self.unnormalized_prev_token().span;
|
self.prev_span = self.unnormalized_prev_token().span;
|
||||||
|
|
||||||
self.expected_tokens.clear();
|
self.expected_tokens.clear();
|
||||||
// Check after each token.
|
|
||||||
self.process_potential_macro_variable();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Advances the parser using provided token as a next one. Use this when
|
/// Advances the parser using provided token as a next one. Use this when
|
||||||
@ -924,9 +943,12 @@ impl<'a> Parser<'a> {
|
|||||||
/// Correct token kinds and spans need to be calculated instead.
|
/// Correct token kinds and spans need to be calculated instead.
|
||||||
fn bump_with(&mut self, next: TokenKind, span: Span) {
|
fn bump_with(&mut self, next: TokenKind, span: Span) {
|
||||||
// Update the current and previous tokens.
|
// Update the current and previous tokens.
|
||||||
let next_token = Token::new(next, span);
|
self.prev_token = self.token.take();
|
||||||
self.prev_token = mem::replace(&mut self.token, next_token);
|
|
||||||
self.unnormalized_prev_token = self.unnormalized_token.take();
|
self.unnormalized_prev_token = self.unnormalized_token.take();
|
||||||
|
self.token = Token::new(next, span);
|
||||||
|
if let Some(normalized_token) = Self::normalize_token(&self.token) {
|
||||||
|
self.unnormalized_token = Some(mem::replace(&mut self.token, normalized_token));
|
||||||
|
}
|
||||||
|
|
||||||
// Update fields derived from the previous token.
|
// Update fields derived from the previous token.
|
||||||
self.prev_span = self.unnormalized_prev_token().span.with_hi(span.lo());
|
self.prev_span = self.unnormalized_prev_token().span.with_hi(span.lo());
|
||||||
@ -1066,39 +1088,6 @@ impl<'a> Parser<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn process_potential_macro_variable(&mut self) {
|
|
||||||
let normalized_token = match self.token.kind {
|
|
||||||
token::Dollar
|
|
||||||
if self.token.span.from_expansion() && self.look_ahead(1, |t| t.is_ident()) =>
|
|
||||||
{
|
|
||||||
self.bump();
|
|
||||||
let name = match self.token.kind {
|
|
||||||
token::Ident(name, _) => name,
|
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
|
||||||
let span = self.prev_span.to(self.token.span);
|
|
||||||
self.struct_span_err(span, &format!("unknown macro variable `{}`", name))
|
|
||||||
.span_label(span, "unknown macro variable")
|
|
||||||
.emit();
|
|
||||||
self.bump();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
token::Interpolated(ref nt) => {
|
|
||||||
// Interpolated identifier and lifetime tokens are replaced with usual identifier
|
|
||||||
// and lifetime tokens, so the former are never encountered during normal parsing.
|
|
||||||
match **nt {
|
|
||||||
token::NtIdent(ident, is_raw) => {
|
|
||||||
Token::new(token::Ident(ident.name, is_raw), ident.span)
|
|
||||||
}
|
|
||||||
token::NtLifetime(ident) => Token::new(token::Lifetime(ident.name), ident.span),
|
|
||||||
_ => return,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => return,
|
|
||||||
};
|
|
||||||
self.unnormalized_token = Some(mem::replace(&mut self.token, normalized_token));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Parses a single token tree from the input.
|
/// Parses a single token tree from the input.
|
||||||
pub fn parse_token_tree(&mut self) -> TokenTree {
|
pub fn parse_token_tree(&mut self) -> TokenTree {
|
||||||
match self.token.kind {
|
match self.token.kind {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
macro_rules! e {
|
macro_rules! e {
|
||||||
($inp:ident) => (
|
($inp:ident) => (
|
||||||
$nonexistent
|
$nonexistent
|
||||||
//~^ ERROR unknown macro variable `nonexistent`
|
//~^ ERROR expected expression, found `$`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
error: unknown macro variable `nonexistent`
|
error: expected expression, found `$`
|
||||||
--> $DIR/issue-6596-1.rs:3:9
|
--> $DIR/issue-6596-1.rs:3:9
|
||||||
|
|
|
|
||||||
LL | $nonexistent
|
LL | $nonexistent
|
||||||
| ^^^^^^^^^^^^ unknown macro variable
|
| ^^^^^^^^^^^^ expected expression
|
||||||
...
|
...
|
||||||
LL | e!(foo);
|
LL | e!(foo);
|
||||||
| -------- in this macro invocation
|
| -------- in this macro invocation
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
macro_rules! g {
|
macro_rules! g {
|
||||||
($inp:ident) => (
|
($inp:ident) => (
|
||||||
{ $inp $nonexistent }
|
{ $inp $nonexistent }
|
||||||
//~^ ERROR unknown macro variable `nonexistent`
|
//~^ ERROR expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `$`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
error: unknown macro variable `nonexistent`
|
error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `$`
|
||||||
--> $DIR/issue-6596-2.rs:5:16
|
--> $DIR/issue-6596-2.rs:5:16
|
||||||
|
|
|
|
||||||
LL | { $inp $nonexistent }
|
LL | { $inp $nonexistent }
|
||||||
| ^^^^^^^^^^^^ unknown macro variable
|
| ^^^^^^^^^^^^ expected one of 8 possible tokens
|
||||||
...
|
...
|
||||||
LL | g!(foo);
|
LL | g!(foo);
|
||||||
| -------- in this macro invocation
|
| -------- in this macro invocation
|
||||||
|
Loading…
Reference in New Issue
Block a user