diff options
Diffstat (limited to 'compiler/rustc_parse/src/parser/mod.rs')
| -rw-r--r-- | compiler/rustc_parse/src/parser/mod.rs | 65 |
1 files changed, 56 insertions, 9 deletions
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index d865fd42764..392a1c1057a 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -24,8 +24,8 @@ pub use pat::{CommaRecoveryMode, RecoverColon, RecoverComma}; use path::PathStyle; use rustc_ast::ptr::P; use rustc_ast::token::{ - self, Delimiter, IdentIsRaw, InvisibleOrigin, MetaVarKind, Nonterminal, NtPatKind, Token, - TokenKind, + self, Delimiter, IdentIsRaw, InvisibleOrigin, MetaVarKind, Nonterminal, NtExprKind, NtPatKind, + Token, TokenKind, }; use rustc_ast::tokenstream::{AttrsTarget, Spacing, TokenStream, TokenTree}; use rustc_ast::util::case::Case; @@ -101,6 +101,7 @@ pub enum ForceCollect { #[macro_export] macro_rules! maybe_whole { ($p:expr, $constructor:ident, |$x:ident| $e:expr) => { + #[allow(irrefutable_let_patterns)] // FIXME: temporary if let token::Interpolated(nt) = &$p.token.kind && let token::$constructor(x) = &**nt { @@ -299,6 +300,10 @@ impl TokenTreeCursor { self.stream.get(self.index) } + fn look_ahead(&self, n: usize) -> Option<&TokenTree> { + self.stream.get(self.index + n) + } + #[inline] fn bump(&mut self) { self.index += 1; @@ -1290,6 +1295,17 @@ impl<'a> Parser<'a> { looker(&token) } + /// Like `lookahead`, but skips over token trees rather than tokens. Useful + /// when looking past possible metavariable pasting sites. + pub fn tree_look_ahead<R>( + &self, + dist: usize, + looker: impl FnOnce(&TokenTree) -> R, + ) -> Option<R> { + assert_ne!(dist, 0); + self.token_cursor.curr.look_ahead(dist - 1).map(looker) + } + /// Returns whether any of the given keywords are `dist` tokens ahead of the current one. pub(crate) fn is_keyword_ahead(&self, dist: usize, kws: &[Symbol]) -> bool { self.look_ahead(dist, |t| kws.iter().any(|&kw| t.is_keyword(kw))) @@ -1297,14 +1313,14 @@ impl<'a> Parser<'a> { /// Parses asyncness: `async` or nothing. fn parse_coroutine_kind(&mut self, case: Case) -> Option<CoroutineKind> { - let span = self.token.uninterpolated_span(); + let span = self.token_uninterpolated_span(); if self.eat_keyword_case(exp!(Async), case) { // FIXME(gen_blocks): Do we want to unconditionally parse `gen` and then // error if edition <= 2024, like we do with async and edition <= 2018? - if self.token.uninterpolated_span().at_least_rust_2024() + if self.token_uninterpolated_span().at_least_rust_2024() && self.eat_keyword_case(exp!(Gen), case) { - let gen_span = self.prev_token.uninterpolated_span(); + let gen_span = self.prev_token_uninterpolated_span(); Some(CoroutineKind::AsyncGen { span: span.to(gen_span), closure_id: DUMMY_NODE_ID, @@ -1317,7 +1333,7 @@ impl<'a> Parser<'a> { return_impl_trait_id: DUMMY_NODE_ID, }) } - } else if self.token.uninterpolated_span().at_least_rust_2024() + } else if self.token_uninterpolated_span().at_least_rust_2024() && self.eat_keyword_case(exp!(Gen), case) { Some(CoroutineKind::Gen { @@ -1333,9 +1349,9 @@ impl<'a> Parser<'a> { /// Parses fn unsafety: `unsafe`, `safe` or nothing. fn parse_safety(&mut self, case: Case) -> Safety { if self.eat_keyword_case(exp!(Unsafe), case) { - Safety::Unsafe(self.prev_token.uninterpolated_span()) + Safety::Unsafe(self.prev_token_uninterpolated_span()) } else if self.eat_keyword_case(exp!(Safe), case) { - Safety::Safe(self.prev_token.uninterpolated_span()) + Safety::Safe(self.prev_token_uninterpolated_span()) } else { Safety::Default } @@ -1362,7 +1378,7 @@ impl<'a> Parser<'a> { .look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Brace) || t.is_whole_block()) && self.eat_keyword_case(exp!(Const), case) { - Const::Yes(self.prev_token.uninterpolated_span()) + Const::Yes(self.prev_token_uninterpolated_span()) } else { Const::No } @@ -1706,6 +1722,35 @@ impl<'a> Parser<'a> { pub fn approx_token_stream_pos(&self) -> u32 { self.num_bump_calls } + + /// For interpolated `self.token`, returns a span of the fragment to which + /// the interpolated token refers. For all other tokens this is just a + /// regular span. It is particularly important to use this for identifiers + /// and lifetimes for which spans affect name resolution and edition + /// checks. Note that keywords are also identifiers, so they should use + /// this if they keep spans or perform edition checks. + pub fn token_uninterpolated_span(&self) -> Span { + match &self.token.kind { + token::NtIdent(ident, _) | token::NtLifetime(ident, _) => ident.span, + token::Interpolated(nt) => nt.use_span(), + token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(_))) => { + self.look_ahead(1, |t| t.span) + } + _ => self.token.span, + } + } + + /// Like `token_uninterpolated_span`, but works on `self.prev_token`. + pub fn prev_token_uninterpolated_span(&self) -> Span { + match &self.prev_token.kind { + token::NtIdent(ident, _) | token::NtLifetime(ident, _) => ident.span, + token::Interpolated(nt) => nt.use_span(), + token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(_))) => { + self.look_ahead(0, |t| t.span) + } + _ => self.prev_token.span, + } + } } pub(crate) fn make_unclosed_delims_error( @@ -1758,6 +1803,8 @@ pub enum ParseNtResult { Item(P<ast::Item>), Stmt(P<ast::Stmt>), Pat(P<ast::Pat>, NtPatKind), + Expr(P<ast::Expr>, NtExprKind), + Literal(P<ast::Expr>), Ty(P<ast::Ty>), Meta(P<ast::AttrItem>), Path(P<ast::Path>), |
