Add initial support for raw lifetimes
This commit is contained in:
parent
3b3e43a386
commit
97910580aa
18 changed files with 116 additions and 40 deletions
|
@ -13,7 +13,6 @@ use rustc_session::lint::builtin::{
|
|||
};
|
||||
use rustc_session::lint::BuiltinLintDiag;
|
||||
use rustc_session::parse::ParseSess;
|
||||
use rustc_span::edition::Edition;
|
||||
use rustc_span::symbol::Symbol;
|
||||
use rustc_span::{BytePos, Pos, Span};
|
||||
use tracing::debug;
|
||||
|
@ -284,7 +283,41 @@ impl<'psess, 'src> StringReader<'psess, 'src> {
|
|||
.stash(span, StashKey::LifetimeIsChar);
|
||||
}
|
||||
let ident = Symbol::intern(lifetime_name);
|
||||
token::Lifetime(ident)
|
||||
token::Lifetime(ident, IdentIsRaw::No)
|
||||
}
|
||||
rustc_lexer::TokenKind::RawLifetime => {
|
||||
self.last_lifetime = Some(self.mk_sp(start, start + BytePos(1)));
|
||||
|
||||
let ident_start = start + BytePos(3);
|
||||
let prefix_span = self.mk_sp(start, ident_start);
|
||||
|
||||
if prefix_span.at_least_rust_2021() {
|
||||
let lifetime_name_without_tick = self.str_from(ident_start);
|
||||
// Put the `'` back onto the lifetime name.
|
||||
let mut lifetime_name = String::with_capacity(lifetime_name_without_tick.len() + 1);
|
||||
lifetime_name.push('\'');
|
||||
lifetime_name += lifetime_name_without_tick;
|
||||
let sym = Symbol::intern(&lifetime_name);
|
||||
|
||||
token::Lifetime(sym, IdentIsRaw::Yes)
|
||||
} else {
|
||||
// Otherwise, this is just `'r`. Warn about it though.
|
||||
self.psess.buffer_lint(
|
||||
RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX,
|
||||
prefix_span,
|
||||
ast::CRATE_NODE_ID,
|
||||
BuiltinLintDiag::RawPrefix(prefix_span),
|
||||
);
|
||||
|
||||
// Reset the state so we just lex the `'r`.
|
||||
let lt_start = start + BytePos(2);
|
||||
self.pos = lt_start;
|
||||
self.cursor = Cursor::new(&str_before[2 as usize..]);
|
||||
|
||||
let lifetime_name = self.str_from(start);
|
||||
let ident = Symbol::intern(lifetime_name);
|
||||
token::Lifetime(ident, IdentIsRaw::No)
|
||||
}
|
||||
}
|
||||
rustc_lexer::TokenKind::Semi => token::Semi,
|
||||
rustc_lexer::TokenKind::Comma => token::Comma,
|
||||
|
@ -712,7 +745,7 @@ impl<'psess, 'src> StringReader<'psess, 'src> {
|
|||
|
||||
let expn_data = prefix_span.ctxt().outer_expn_data();
|
||||
|
||||
if expn_data.edition >= Edition::Edition2021 {
|
||||
if expn_data.edition.at_least_rust_2021() {
|
||||
// In Rust 2021, this is a hard error.
|
||||
let sugg = if prefix == "rb" {
|
||||
Some(errors::UnknownPrefixSugg::UseBr(prefix_span))
|
||||
|
|
|
@ -2050,7 +2050,7 @@ impl<'a> Parser<'a> {
|
|||
};
|
||||
// On an error path, eagerly consider a lifetime to be an unclosed character lit, if that
|
||||
// makes sense.
|
||||
if let Some(ident) = self.token.lifetime()
|
||||
if let Some((ident, IdentIsRaw::No)) = self.token.lifetime()
|
||||
&& could_be_unclosed_char_literal(ident)
|
||||
{
|
||||
let lt = self.expect_lifetime();
|
||||
|
@ -2925,9 +2925,9 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
|
||||
pub(crate) fn eat_label(&mut self) -> Option<Label> {
|
||||
if let Some(ident) = self.token.lifetime() {
|
||||
if let Some((ident, is_raw)) = self.token.lifetime() {
|
||||
// Disallow `'fn`, but with a better error message than `expect_lifetime`.
|
||||
if ident.without_first_quote().is_reserved() {
|
||||
if matches!(is_raw, IdentIsRaw::No) && ident.without_first_quote().is_reserved() {
|
||||
self.dcx().emit_err(errors::InvalidLabel { span: ident.span, name: ident.name });
|
||||
}
|
||||
|
||||
|
|
|
@ -1666,7 +1666,7 @@ enum FlatToken {
|
|||
pub enum ParseNtResult {
|
||||
Tt(TokenTree),
|
||||
Ident(Ident, IdentIsRaw),
|
||||
Lifetime(Ident),
|
||||
Lifetime(Ident, IdentIsRaw),
|
||||
|
||||
/// This case will eventually be removed, along with `Token::Interpolate`.
|
||||
Nt(Lrc<Nonterminal>),
|
||||
|
|
|
@ -88,7 +88,7 @@ impl<'a> Parser<'a> {
|
|||
},
|
||||
NonterminalKind::Pat(pat_kind) => token.can_begin_pattern(pat_kind),
|
||||
NonterminalKind::Lifetime => match &token.kind {
|
||||
token::Lifetime(_) | token::NtLifetime(..) => true,
|
||||
token::Lifetime(..) | token::NtLifetime(..) => true,
|
||||
_ => false,
|
||||
},
|
||||
NonterminalKind::TT | NonterminalKind::Item | NonterminalKind::Stmt => {
|
||||
|
@ -171,9 +171,9 @@ impl<'a> Parser<'a> {
|
|||
NonterminalKind::Lifetime => {
|
||||
// We want to keep `'keyword` parsing, just like `keyword` is still
|
||||
// an ident for nonterminal purposes.
|
||||
return if let Some(ident) = self.token.lifetime() {
|
||||
return if let Some((ident, is_raw)) = self.token.lifetime() {
|
||||
self.bump();
|
||||
Ok(ParseNtResult::Lifetime(ident))
|
||||
Ok(ParseNtResult::Lifetime(ident, is_raw))
|
||||
} else {
|
||||
Err(self.dcx().create_err(UnexpectedNonterminal::Lifetime {
|
||||
span: self.token.span,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use rustc_ast::mut_visit::{walk_pat, MutVisitor};
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::token::{self, BinOpToken, Delimiter, Token};
|
||||
use rustc_ast::token::{self, BinOpToken, Delimiter, IdentIsRaw, Token};
|
||||
use rustc_ast::{
|
||||
self as ast, AttrVec, BindingMode, ByRef, Expr, ExprKind, MacCall, Mutability, Pat, PatField,
|
||||
PatFieldsRest, PatKind, Path, QSelf, RangeEnd, RangeSyntax,
|
||||
|
@ -548,7 +548,7 @@ impl<'a> Parser<'a> {
|
|||
None => PatKind::Path(qself, path),
|
||||
}
|
||||
}
|
||||
} else if let Some(lt) = self.token.lifetime()
|
||||
} else if let Some((lt, IdentIsRaw::No)) = self.token.lifetime()
|
||||
// In pattern position, we're totally fine with using "next token isn't colon"
|
||||
// as a heuristic. We could probably just always try to recover if it's a lifetime,
|
||||
// because we never have `'a: label {}` in a pattern position anyways, but it does
|
||||
|
@ -689,7 +689,7 @@ impl<'a> Parser<'a> {
|
|||
/// Parse `&pat` / `&mut pat`.
|
||||
fn parse_pat_deref(&mut self, expected: Option<Expected>) -> PResult<'a, PatKind> {
|
||||
self.expect_and()?;
|
||||
if let Some(lifetime) = self.token.lifetime() {
|
||||
if let Some((lifetime, _)) = self.token.lifetime() {
|
||||
self.bump(); // `'a`
|
||||
|
||||
self.dcx().emit_err(UnexpectedLifetimeInPattern {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::token::{self, BinOpToken, Delimiter, Token, TokenKind};
|
||||
use rustc_ast::token::{self, BinOpToken, Delimiter, IdentIsRaw, Token, TokenKind};
|
||||
use rustc_ast::util::case::Case;
|
||||
use rustc_ast::{
|
||||
self as ast, BareFnTy, BoundAsyncness, BoundConstness, BoundPolarity, FnRetTy, GenericBound,
|
||||
|
@ -1285,8 +1285,9 @@ impl<'a> Parser<'a> {
|
|||
|
||||
/// Parses a single lifetime `'a` or panics.
|
||||
pub(super) fn expect_lifetime(&mut self) -> Lifetime {
|
||||
if let Some(ident) = self.token.lifetime() {
|
||||
if ident.without_first_quote().is_reserved()
|
||||
if let Some((ident, is_raw)) = self.token.lifetime() {
|
||||
if matches!(is_raw, IdentIsRaw::No)
|
||||
&& ident.without_first_quote().is_reserved()
|
||||
&& ![kw::UnderscoreLifetime, kw::StaticLifetime].contains(&ident.name)
|
||||
{
|
||||
self.dcx().emit_err(errors::KeywordLifetime { span: ident.span });
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue