Skip to content

Commit 3bc3857

Browse files
Initial support for raw lifetimes
1 parent f158600 commit 3bc3857

File tree

14 files changed

+72
-35
lines changed

14 files changed

+72
-35
lines changed

compiler/rustc_ast/src/mut_visit.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -776,7 +776,7 @@ fn visit_lazy_tts<T: MutVisitor>(lazy_tts: &mut Option<LazyAttrTokenStream>, vis
776776
pub fn visit_token<T: MutVisitor>(t: &mut Token, vis: &mut T) {
777777
let Token { kind, span } = t;
778778
match kind {
779-
token::Ident(name, _) | token::Lifetime(name) => {
779+
token::Ident(name, _) | token::Lifetime(name, _) => {
780780
let mut ident = Ident::new(*name, *span);
781781
vis.visit_ident(&mut ident);
782782
*name = ident.name;
@@ -786,7 +786,7 @@ pub fn visit_token<T: MutVisitor>(t: &mut Token, vis: &mut T) {
786786
token::NtIdent(ident, _is_raw) => {
787787
vis.visit_ident(ident);
788788
}
789-
token::NtLifetime(ident) => {
789+
token::NtLifetime(ident, _is_raw) => {
790790
vis.visit_ident(ident);
791791
}
792792
token::Interpolated(nt) => {

compiler/rustc_ast/src/token.rs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -328,11 +328,11 @@ pub enum TokenKind {
328328
/// Do not forget about `NtLifetime` when you want to match on lifetime identifiers.
329329
/// It's recommended to use `Token::(lifetime,uninterpolate,uninterpolated_span)` to
330330
/// treat regular and interpolated lifetime identifiers in the same way.
331-
Lifetime(Symbol),
331+
Lifetime(Symbol, IdentIsRaw),
332332
/// This identifier (and its span) is the lifetime passed to the
333333
/// declarative macro. The span in the surrounding `Token` is the span of
334334
/// the `lifetime` metavariable in the macro's RHS.
335-
NtLifetime(Ident),
335+
NtLifetime(Ident, IdentIsRaw),
336336

337337
/// An embedded AST node, as produced by a macro. This only exists for
338338
/// historical reasons. We'd like to get rid of it, for multiple reasons.
@@ -455,7 +455,7 @@ impl Token {
455455
/// if they keep spans or perform edition checks.
456456
pub fn uninterpolated_span(&self) -> Span {
457457
match self.kind {
458-
NtIdent(ident, _) | NtLifetime(ident) => ident.span,
458+
NtIdent(ident, _) | NtLifetime(ident, _) => ident.span,
459459
Interpolated(ref nt) => nt.use_span(),
460460
_ => self.span,
461461
}
@@ -627,7 +627,9 @@ impl Token {
627627
pub fn uninterpolate(&self) -> Cow<'_, Token> {
628628
match self.kind {
629629
NtIdent(ident, is_raw) => Cow::Owned(Token::new(Ident(ident.name, is_raw), ident.span)),
630-
NtLifetime(ident) => Cow::Owned(Token::new(Lifetime(ident.name), ident.span)),
630+
NtLifetime(ident, is_raw) => {
631+
Cow::Owned(Token::new(Lifetime(ident.name, is_raw), ident.span))
632+
}
631633
_ => Cow::Borrowed(self),
632634
}
633635
}
@@ -645,11 +647,11 @@ impl Token {
645647

646648
/// Returns a lifetime identifier if this token is a lifetime.
647649
#[inline]
648-
pub fn lifetime(&self) -> Option<Ident> {
650+
pub fn lifetime(&self) -> Option<(Ident, IdentIsRaw)> {
649651
// We avoid using `Token::uninterpolate` here because it's slow.
650652
match self.kind {
651-
Lifetime(name) => Some(Ident::new(name, self.span)),
652-
NtLifetime(ident) => Some(ident),
653+
Lifetime(name, is_raw) => Some((Ident::new(name, self.span), is_raw)),
654+
NtLifetime(ident, is_raw) => Some((ident, is_raw)),
653655
_ => None,
654656
}
655657
}
@@ -832,7 +834,7 @@ impl Token {
832834
_ => return None,
833835
},
834836
SingleQuote => match joint.kind {
835-
Ident(name, IdentIsRaw::No) => Lifetime(Symbol::intern(&format!("'{name}"))),
837+
Ident(name, is_raw) => Lifetime(Symbol::intern(&format!("'{name}")), is_raw),
836838
_ => return None,
837839
},
838840

compiler/rustc_ast/src/tokenstream.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -487,11 +487,11 @@ impl TokenStream {
487487
token::NtIdent(ident, is_raw) => {
488488
TokenTree::Token(Token::new(token::Ident(ident.name, is_raw), ident.span), spacing)
489489
}
490-
token::NtLifetime(ident) => TokenTree::Delimited(
490+
token::NtLifetime(ident, is_raw) => TokenTree::Delimited(
491491
DelimSpan::from_single(token.span),
492492
DelimSpacing::new(Spacing::JointHidden, spacing),
493493
Delimiter::Invisible,
494-
TokenStream::token_alone(token::Lifetime(ident.name), ident.span),
494+
TokenStream::token_alone(token::Lifetime(ident.name, is_raw), ident.span),
495495
),
496496
token::Interpolated(ref nt) => TokenTree::Delimited(
497497
DelimSpan::from_single(token.span),

compiler/rustc_ast_pretty/src/pprust/state.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ use crate::pprust::state::fixup::FixupContext;
1212
use ast::TraitBoundModifiers;
1313
use rustc_ast::attr::AttrIdGenerator;
1414
use rustc_ast::ptr::P;
15-
use rustc_ast::token::{self, BinOpToken, CommentKind, Delimiter, Nonterminal, Token, TokenKind};
15+
use rustc_ast::token::{
16+
self, BinOpToken, CommentKind, Delimiter, IdentIsRaw, Nonterminal, Token, TokenKind,
17+
};
1618
use rustc_ast::tokenstream::{Spacing, TokenStream, TokenTree};
1719
use rustc_ast::util::classify;
1820
use rustc_ast::util::comments::{Comment, CommentStyle};
@@ -946,8 +948,13 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
946948
token::NtIdent(ident, is_raw) => {
947949
IdentPrinter::for_ast_ident(ident, is_raw.into()).to_string().into()
948950
}
949-
token::Lifetime(name) => name.to_string().into(),
950-
token::NtLifetime(ident) => ident.name.to_string().into(),
951+
952+
token::Lifetime(name, IdentIsRaw::No)
953+
| token::NtLifetime(Ident { name, .. }, IdentIsRaw::No) => name.to_string().into(),
954+
token::Lifetime(name, IdentIsRaw::Yes)
955+
| token::NtLifetime(Ident { name, .. }, IdentIsRaw::Yes) => {
956+
format!("'r#{}", &name.as_str()[1..]).into()
957+
}
951958

952959
/* Other */
953960
token::DocComment(comment_kind, attr_style, data) => {

compiler/rustc_expand/src/mbe/macro_parser.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -398,8 +398,10 @@ pub(crate) enum NamedMatch {
398398
fn token_name_eq(t1: &Token, t2: &Token) -> bool {
399399
if let (Some((ident1, is_raw1)), Some((ident2, is_raw2))) = (t1.ident(), t2.ident()) {
400400
ident1.name == ident2.name && is_raw1 == is_raw2
401-
} else if let (Some(ident1), Some(ident2)) = (t1.lifetime(), t2.lifetime()) {
402-
ident1.name == ident2.name
401+
} else if let (Some((ident1, is_raw1)), Some((ident2, is_raw2))) =
402+
(t1.lifetime(), t2.lifetime())
403+
{
404+
ident1.name == ident2.name && is_raw1 == is_raw2
403405
} else {
404406
t1.kind == t2.kind
405407
}

compiler/rustc_expand/src/mbe/transcribe.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -278,9 +278,9 @@ pub(super) fn transcribe<'a>(
278278
let kind = token::NtIdent(*ident, *is_raw);
279279
TokenTree::token_alone(kind, sp)
280280
}
281-
MatchedSingle(ParseNtResult::Lifetime(ident)) => {
281+
MatchedSingle(ParseNtResult::Lifetime(ident, is_raw)) => {
282282
marker.visit_span(&mut sp);
283-
let kind = token::NtLifetime(*ident);
283+
let kind = token::NtLifetime(*ident, *is_raw);
284284
TokenTree::token_alone(kind, sp)
285285
}
286286
MatchedSingle(ParseNtResult::Nt(nt)) => {

compiler/rustc_expand/src/proc_macro_server.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -227,15 +227,16 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec<TokenTree<TokenStre
227227
span: ident.span,
228228
})),
229229

230-
Lifetime(name) => {
230+
Lifetime(name, is_raw) => {
231231
let ident = symbol::Ident::new(name, span).without_first_quote();
232232
trees.extend([
233233
TokenTree::Punct(Punct { ch: b'\'', joint: true, span }),
234-
TokenTree::Ident(Ident { sym: ident.name, is_raw: false, span }),
234+
TokenTree::Ident(Ident { sym: ident.name, is_raw: is_raw.into(), span }),
235235
]);
236236
}
237-
NtLifetime(ident) => {
238-
let stream = TokenStream::token_alone(token::Lifetime(ident.name), ident.span);
237+
NtLifetime(ident, is_raw) => {
238+
let stream =
239+
TokenStream::token_alone(token::Lifetime(ident.name, is_raw), ident.span);
239240
trees.push(TokenTree::Group(Group {
240241
delimiter: pm::Delimiter::None,
241242
stream: Some(stream),

compiler/rustc_lexer/src/lib.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,9 @@ pub enum TokenKind {
104104
/// "'a"
105105
Lifetime { starts_with_number: bool },
106106

107+
/// `'r#async`
108+
RawLifetime,
109+
107110
// One-char tokens:
108111
/// ";"
109112
Semi,
@@ -676,9 +679,18 @@ impl Cursor<'_> {
676679
return Literal { kind, suffix_start };
677680
}
678681

682+
if self.first() == 'r' && self.second() == '#' && is_id_start(self.third()) {
683+
// Eat "r" character.
684+
self.bump();
685+
// Eat "#" symbol.
686+
self.bump();
687+
// Eat the identifier part of RawIdent.
688+
self.eat_identifier();
689+
return RawLifetime;
690+
}
691+
679692
// Either a lifetime or a character literal with
680693
// length greater than 1.
681-
682694
let starts_with_number = self.first().is_ascii_digit();
683695

684696
// Skip the literal contents.

compiler/rustc_parse/src/lexer/mod.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,19 @@ impl<'psess, 'src> StringReader<'psess, 'src> {
273273
.stash(span, StashKey::LifetimeIsChar);
274274
}
275275
let ident = Symbol::intern(lifetime_name);
276-
token::Lifetime(ident)
276+
token::Lifetime(ident, IdentIsRaw::No)
277+
}
278+
rustc_lexer::TokenKind::RawLifetime => {
279+
// Include the leading `'` in the real identifier, for macro
280+
// expansion purposes. See #12512 for the gory details of why
281+
// this is necessary.
282+
let lifetime_name_without_tick = self.str_from(start + BytePos(3));
283+
let mut lifetime_name = String::with_capacity(lifetime_name_without_tick.len() + 1);
284+
lifetime_name.push('\'');
285+
lifetime_name += lifetime_name_without_tick;
286+
self.last_lifetime = Some(self.mk_sp(start, start + BytePos(1)));
287+
let ident = Symbol::intern(&lifetime_name);
288+
token::Lifetime(ident, IdentIsRaw::Yes)
277289
}
278290
rustc_lexer::TokenKind::Semi => token::Semi,
279291
rustc_lexer::TokenKind::Comma => token::Comma,

compiler/rustc_parse/src/parser/expr.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2081,7 +2081,7 @@ impl<'a> Parser<'a> {
20812081
};
20822082
// On an error path, eagerly consider a lifetime to be an unclosed character lit, if that
20832083
// makes sense.
2084-
if let Some(ident) = self.token.lifetime()
2084+
if let Some((ident, IdentIsRaw::No)) = self.token.lifetime()
20852085
&& could_be_unclosed_char_literal(ident)
20862086
{
20872087
let lt = self.expect_lifetime();
@@ -2931,7 +2931,7 @@ impl<'a> Parser<'a> {
29312931
}
29322932

29332933
pub(crate) fn eat_label(&mut self) -> Option<Label> {
2934-
self.token.lifetime().map(|ident| {
2934+
self.token.lifetime().map(|(ident, _)| {
29352935
self.bump();
29362936
Label { ident }
29372937
})

compiler/rustc_parse/src/parser/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1639,7 +1639,7 @@ enum FlatToken {
16391639
pub enum ParseNtResult {
16401640
Tt(TokenTree),
16411641
Ident(Ident, IdentIsRaw),
1642-
Lifetime(Ident),
1642+
Lifetime(Ident, IdentIsRaw),
16431643

16441644
/// This case will eventually be removed, along with `Token::Interpolate`.
16451645
Nt(Lrc<Nonterminal>),

compiler/rustc_parse/src/parser/nonterminal.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ impl<'a> Parser<'a> {
9595
_ => false,
9696
},
9797
NonterminalKind::Lifetime => match &token.kind {
98-
token::Lifetime(_) | token::NtLifetime(..) => true,
98+
token::Lifetime(..) | token::NtLifetime(..) => true,
9999
_ => false,
100100
},
101101
NonterminalKind::TT | NonterminalKind::Item | NonterminalKind::Stmt => {
@@ -182,8 +182,9 @@ impl<'a> Parser<'a> {
182182
.collect_tokens_no_attrs(|this| this.parse_visibility(FollowedByType::Yes))?))
183183
}
184184
NonterminalKind::Lifetime => {
185-
return if self.check_lifetime() {
186-
Ok(ParseNtResult::Lifetime(self.expect_lifetime().ident))
185+
return if let Some((ident, is_raw)) = self.token.lifetime() {
186+
self.bump();
187+
Ok(ParseNtResult::Lifetime(ident, is_raw))
187188
} else {
188189
Err(self.dcx().create_err(UnexpectedNonterminal::Lifetime {
189190
span: self.token.span,

compiler/rustc_parse/src/parser/pat.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use crate::parser::expr::could_be_unclosed_char_literal;
1414
use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
1515
use rustc_ast::mut_visit::{noop_visit_pat, MutVisitor};
1616
use rustc_ast::ptr::P;
17-
use rustc_ast::token::{self, BinOpToken, Delimiter, Token};
17+
use rustc_ast::token::{self, BinOpToken, Delimiter, IdentIsRaw, Token};
1818
use rustc_ast::{
1919
self as ast, AttrVec, BindingMode, ByRef, Expr, ExprKind, MacCall, Mutability, Pat, PatField,
2020
PatFieldsRest, PatKind, Path, QSelf, RangeEnd, RangeSyntax,
@@ -539,7 +539,7 @@ impl<'a> Parser<'a> {
539539
None => PatKind::Path(qself, path),
540540
}
541541
}
542-
} else if let token::Lifetime(lt) = self.token.kind
542+
} else if let token::Lifetime(lt, IdentIsRaw::No) = self.token.kind
543543
// In pattern position, we're totally fine with using "next token isn't colon"
544544
// as a heuristic. We could probably just always try to recover if it's a lifetime,
545545
// because we never have `'a: label {}` in a pattern position anyways, but it does
@@ -672,7 +672,7 @@ impl<'a> Parser<'a> {
672672
/// Parse `&pat` / `&mut pat`.
673673
fn parse_pat_deref(&mut self, expected: Option<Expected>) -> PResult<'a, PatKind> {
674674
self.expect_and()?;
675-
if let token::Lifetime(name) = self.token.kind {
675+
if let token::Lifetime(name, _) = self.token.kind {
676676
self.bump(); // `'a`
677677

678678
self.dcx()

compiler/rustc_parse/src/parser/ty.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1201,7 +1201,7 @@ impl<'a> Parser<'a> {
12011201

12021202
/// Parses a single lifetime `'a` or panics.
12031203
pub(super) fn expect_lifetime(&mut self) -> Lifetime {
1204-
if let Some(ident) = self.token.lifetime() {
1204+
if let Some((ident, _)) = self.token.lifetime() {
12051205
self.bump();
12061206
Lifetime { ident, id: ast::DUMMY_NODE_ID }
12071207
} else {

0 commit comments

Comments
 (0)