Skip to content

Commit 2dbd411

Browse files
authored
Rollup merge of #144897 - fee1-dead-contrib:raw_lifetimes_printing, r=fmease
print raw lifetime idents with r# This replaces #143185 and fixes #143150 cc ``@fmease``
2 parents 2bd3922 + 4970127 commit 2dbd411

File tree

21 files changed

+192
-73
lines changed

21 files changed

+192
-73
lines changed

compiler/rustc_ast/src/token.rs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ pub use NtPatKind::*;
77
pub use TokenKind::*;
88
use rustc_macros::{Decodable, Encodable, HashStable_Generic};
99
use rustc_span::edition::Edition;
10+
use rustc_span::symbol::IdentPrintMode;
1011
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, kw, sym};
1112
#[allow(clippy::useless_attribute)] // FIXME: following use of `hidden_glob_reexports` incorrectly triggers `useless_attribute` lint.
1213
#[allow(hidden_glob_reexports)]
@@ -344,15 +345,24 @@ pub enum IdentIsRaw {
344345
Yes,
345346
}
346347

347-
impl From<bool> for IdentIsRaw {
348-
fn from(b: bool) -> Self {
349-
if b { Self::Yes } else { Self::No }
348+
impl IdentIsRaw {
349+
pub fn to_print_mode_ident(self) -> IdentPrintMode {
350+
match self {
351+
IdentIsRaw::No => IdentPrintMode::Normal,
352+
IdentIsRaw::Yes => IdentPrintMode::RawIdent,
353+
}
354+
}
355+
pub fn to_print_mode_lifetime(self) -> IdentPrintMode {
356+
match self {
357+
IdentIsRaw::No => IdentPrintMode::Normal,
358+
IdentIsRaw::Yes => IdentPrintMode::RawLifetime,
359+
}
350360
}
351361
}
352362

353-
impl From<IdentIsRaw> for bool {
354-
fn from(is_raw: IdentIsRaw) -> bool {
355-
matches!(is_raw, IdentIsRaw::Yes)
363+
impl From<bool> for IdentIsRaw {
364+
fn from(b: bool) -> Self {
365+
if b { Self::Yes } else { Self::No }
356366
}
357367
}
358368

compiler/rustc_ast_pretty/src/pprust/state.rs

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use std::borrow::Cow;
1010
use std::sync::Arc;
1111

1212
use rustc_ast::attr::AttrIdGenerator;
13-
use rustc_ast::token::{self, CommentKind, Delimiter, IdentIsRaw, Token, TokenKind};
13+
use rustc_ast::token::{self, CommentKind, Delimiter, Token, TokenKind};
1414
use rustc_ast::tokenstream::{Spacing, TokenStream, TokenTree};
1515
use rustc_ast::util::classify;
1616
use rustc_ast::util::comments::{Comment, CommentStyle};
@@ -441,7 +441,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
441441
fn print_generic_args(&mut self, args: &ast::GenericArgs, colons_before_params: bool);
442442

443443
fn print_ident(&mut self, ident: Ident) {
444-
self.word(IdentPrinter::for_ast_ident(ident, ident.is_raw_guess()).to_string());
444+
self.word(IdentPrinter::for_ast_ident(ident, ident.guess_print_mode()).to_string());
445445
self.ann_post(ident)
446446
}
447447

@@ -1015,17 +1015,16 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
10151015

10161016
/* Name components */
10171017
token::Ident(name, is_raw) => {
1018-
IdentPrinter::new(name, is_raw.into(), convert_dollar_crate).to_string().into()
1018+
IdentPrinter::new(name, is_raw.to_print_mode_ident(), convert_dollar_crate)
1019+
.to_string()
1020+
.into()
10191021
}
10201022
token::NtIdent(ident, is_raw) => {
1021-
IdentPrinter::for_ast_ident(ident, is_raw.into()).to_string().into()
1023+
IdentPrinter::for_ast_ident(ident, is_raw.to_print_mode_ident()).to_string().into()
10221024
}
10231025

1024-
token::Lifetime(name, IdentIsRaw::No)
1025-
| token::NtLifetime(Ident { name, .. }, IdentIsRaw::No) => name.to_string().into(),
1026-
token::Lifetime(name, IdentIsRaw::Yes)
1027-
| token::NtLifetime(Ident { name, .. }, IdentIsRaw::Yes) => {
1028-
format!("'r#{}", &name.as_str()[1..]).into()
1026+
token::Lifetime(name, is_raw) | token::NtLifetime(Ident { name, .. }, is_raw) => {
1027+
IdentPrinter::new(name, is_raw.to_print_mode_lifetime(), None).to_string().into()
10291028
}
10301029

10311030
/* Other */

compiler/rustc_expand/src/proc_macro_server.rs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -250,20 +250,26 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec<TokenTree<TokenStre
250250
Question => op("?"),
251251
SingleQuote => op("'"),
252252

253-
Ident(sym, is_raw) => {
254-
trees.push(TokenTree::Ident(Ident { sym, is_raw: is_raw.into(), span }))
255-
}
253+
Ident(sym, is_raw) => trees.push(TokenTree::Ident(Ident {
254+
sym,
255+
is_raw: matches!(is_raw, IdentIsRaw::Yes),
256+
span,
257+
})),
256258
NtIdent(ident, is_raw) => trees.push(TokenTree::Ident(Ident {
257259
sym: ident.name,
258-
is_raw: is_raw.into(),
260+
is_raw: matches!(is_raw, IdentIsRaw::Yes),
259261
span: ident.span,
260262
})),
261263

262264
Lifetime(name, is_raw) => {
263265
let ident = rustc_span::Ident::new(name, span).without_first_quote();
264266
trees.extend([
265267
TokenTree::Punct(Punct { ch: b'\'', joint: true, span }),
266-
TokenTree::Ident(Ident { sym: ident.name, is_raw: is_raw.into(), span }),
268+
TokenTree::Ident(Ident {
269+
sym: ident.name,
270+
is_raw: matches!(is_raw, IdentIsRaw::Yes),
271+
span,
272+
}),
267273
]);
268274
}
269275
NtLifetime(ident, is_raw) => {

compiler/rustc_parse/messages.ftl

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -463,9 +463,6 @@ parse_invalid_dyn_keyword = invalid `dyn` keyword
463463
parse_invalid_expression_in_let_else = a `{$operator}` expression cannot be directly assigned in `let...else`
464464
parse_invalid_identifier_with_leading_number = identifiers cannot start with a number
465465
466-
parse_invalid_label =
467-
invalid label name `{$name}`
468-
469466
parse_invalid_literal_suffix_on_tuple_index = suffixes on a tuple index are invalid
470467
.label = invalid suffix `{$suffix}`
471468
.tuple_exception_line_1 = `{$suffix}` is *temporarily* accepted on tuple index fields as it was incorrectly accepted on stable for a few releases
@@ -495,6 +492,8 @@ parse_invalid_unicode_escape = invalid unicode character escape
495492
parse_invalid_variable_declaration =
496493
invalid variable declaration
497494
495+
parse_keyword_label = labels cannot use keyword names
496+
498497
parse_keyword_lifetime =
499498
lifetimes cannot use keyword names
500499

compiler/rustc_parse/src/errors.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2228,11 +2228,10 @@ pub(crate) struct KeywordLifetime {
22282228
}
22292229

22302230
#[derive(Diagnostic)]
2231-
#[diag(parse_invalid_label)]
2232-
pub(crate) struct InvalidLabel {
2231+
#[diag(parse_keyword_label)]
2232+
pub(crate) struct KeywordLabel {
22332233
#[primary_span]
22342234
pub span: Span,
2235-
pub name: Symbol,
22362235
}
22372236

22382237
#[derive(Diagnostic)]

compiler/rustc_parse/src/parser/expr.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3094,7 +3094,7 @@ impl<'a> Parser<'a> {
30943094
if let Some((ident, is_raw)) = self.token.lifetime() {
30953095
// Disallow `'fn`, but with a better error message than `expect_lifetime`.
30963096
if matches!(is_raw, IdentIsRaw::No) && ident.without_first_quote().is_reserved() {
3097-
self.dcx().emit_err(errors::InvalidLabel { span: ident.span, name: ident.name });
3097+
self.dcx().emit_err(errors::KeywordLabel { span: ident.span });
30983098
}
30993099

31003100
self.bump();

compiler/rustc_parse/src/parser/ty.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1502,8 +1502,7 @@ impl<'a> Parser<'a> {
15021502
pub(super) fn expect_lifetime(&mut self) -> Lifetime {
15031503
if let Some((ident, is_raw)) = self.token.lifetime() {
15041504
if matches!(is_raw, IdentIsRaw::No)
1505-
&& ident.without_first_quote().is_reserved()
1506-
&& ![kw::UnderscoreLifetime, kw::StaticLifetime].contains(&ident.name)
1505+
&& ident.without_first_quote().is_reserved_lifetime()
15071506
{
15081507
self.dcx().emit_err(errors::KeywordLifetime { span: ident.span });
15091508
}

compiler/rustc_resolve/src/late/diagnostics.rs

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3094,7 +3094,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
30943094
} else {
30953095
self.suggest_introducing_lifetime(
30963096
&mut err,
3097-
Some(lifetime_ref.ident.name.as_str()),
3097+
Some(lifetime_ref.ident),
30983098
|err, _, span, message, suggestion, span_suggs| {
30993099
err.multipart_suggestion_verbose(
31003100
message,
@@ -3112,7 +3112,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
31123112
fn suggest_introducing_lifetime(
31133113
&self,
31143114
err: &mut Diag<'_>,
3115-
name: Option<&str>,
3115+
name: Option<Ident>,
31163116
suggest: impl Fn(
31173117
&mut Diag<'_>,
31183118
bool,
@@ -3159,7 +3159,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
31593159
let mut rm_inner_binders: FxIndexSet<Span> = Default::default();
31603160
let (span, sugg) = if span.is_empty() {
31613161
let mut binder_idents: FxIndexSet<Ident> = Default::default();
3162-
binder_idents.insert(Ident::from_str(name.unwrap_or("'a")));
3162+
binder_idents.insert(name.unwrap_or(Ident::from_str("'a")));
31633163

31643164
// We need to special case binders in the following situation:
31653165
// Change `T: for<'a> Trait<T> + 'b` to `for<'a, 'b> T: Trait<T> + 'b`
@@ -3189,16 +3189,11 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
31893189
}
31903190
}
31913191

3192-
let binders_sugg = binder_idents.into_iter().enumerate().fold(
3193-
"".to_string(),
3194-
|mut binders, (i, x)| {
3195-
if i != 0 {
3196-
binders += ", ";
3197-
}
3198-
binders += x.as_str();
3199-
binders
3200-
},
3201-
);
3192+
let binders_sugg: String = binder_idents
3193+
.into_iter()
3194+
.map(|ident| ident.to_string())
3195+
.intersperse(", ".to_owned())
3196+
.collect();
32023197
let sugg = format!(
32033198
"{}<{}>{}",
32043199
if higher_ranked { "for" } else { "" },
@@ -3214,15 +3209,16 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
32143209
.source_map()
32153210
.span_through_char(span, '<')
32163211
.shrink_to_hi();
3217-
let sugg = format!("{}, ", name.unwrap_or("'a"));
3212+
let sugg =
3213+
format!("{}, ", name.map(|i| i.to_string()).as_deref().unwrap_or("'a"));
32183214
(span, sugg)
32193215
};
32203216

32213217
if higher_ranked {
32223218
let message = Cow::from(format!(
32233219
"consider making the {} lifetime-generic with a new `{}` lifetime",
32243220
kind.descr(),
3225-
name.unwrap_or("'a"),
3221+
name.map(|i| i.to_string()).as_deref().unwrap_or("'a"),
32263222
));
32273223
should_continue = suggest(
32283224
err,

compiler/rustc_span/src/symbol.rs

Lines changed: 61 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2533,10 +2533,16 @@ impl fmt::Debug for Ident {
25332533
/// except that AST identifiers don't keep the rawness flag, so we have to guess it.
25342534
impl fmt::Display for Ident {
25352535
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2536-
fmt::Display::fmt(&IdentPrinter::new(self.name, self.is_raw_guess(), None), f)
2536+
fmt::Display::fmt(&IdentPrinter::new(self.name, self.guess_print_mode(), None), f)
25372537
}
25382538
}
25392539

2540+
pub enum IdentPrintMode {
2541+
Normal,
2542+
RawIdent,
2543+
RawLifetime,
2544+
}
2545+
25402546
/// The most general type to print identifiers.
25412547
///
25422548
/// AST pretty-printer is used as a fallback for turning AST structures into token streams for
@@ -2552,40 +2558,59 @@ impl fmt::Display for Ident {
25522558
/// done for a token stream or a single token.
25532559
pub struct IdentPrinter {
25542560
symbol: Symbol,
2555-
is_raw: bool,
2561+
mode: IdentPrintMode,
25562562
/// Span used for retrieving the crate name to which `$crate` refers to,
25572563
/// if this field is `None` then the `$crate` conversion doesn't happen.
25582564
convert_dollar_crate: Option<Span>,
25592565
}
25602566

25612567
impl IdentPrinter {
25622568
/// The most general `IdentPrinter` constructor. Do not use this.
2563-
pub fn new(symbol: Symbol, is_raw: bool, convert_dollar_crate: Option<Span>) -> IdentPrinter {
2564-
IdentPrinter { symbol, is_raw, convert_dollar_crate }
2569+
pub fn new(
2570+
symbol: Symbol,
2571+
mode: IdentPrintMode,
2572+
convert_dollar_crate: Option<Span>,
2573+
) -> IdentPrinter {
2574+
IdentPrinter { symbol, mode, convert_dollar_crate }
25652575
}
25662576

25672577
/// This implementation is supposed to be used when printing identifiers
25682578
/// as a part of pretty-printing for larger AST pieces.
25692579
/// Do not use this either.
2570-
pub fn for_ast_ident(ident: Ident, is_raw: bool) -> IdentPrinter {
2571-
IdentPrinter::new(ident.name, is_raw, Some(ident.span))
2580+
pub fn for_ast_ident(ident: Ident, mode: IdentPrintMode) -> IdentPrinter {
2581+
IdentPrinter::new(ident.name, mode, Some(ident.span))
25722582
}
25732583
}
25742584

25752585
impl fmt::Display for IdentPrinter {
25762586
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2577-
if self.is_raw {
2578-
f.write_str("r#")?;
2579-
} else if self.symbol == kw::DollarCrate {
2580-
if let Some(span) = self.convert_dollar_crate {
2587+
let s = match self.mode {
2588+
IdentPrintMode::Normal
2589+
if self.symbol == kw::DollarCrate
2590+
&& let Some(span) = self.convert_dollar_crate =>
2591+
{
25812592
let converted = span.ctxt().dollar_crate_name();
25822593
if !converted.is_path_segment_keyword() {
25832594
f.write_str("::")?;
25842595
}
2585-
return fmt::Display::fmt(&converted, f);
2596+
converted
25862597
}
2587-
}
2588-
fmt::Display::fmt(&self.symbol, f)
2598+
IdentPrintMode::Normal => self.symbol,
2599+
IdentPrintMode::RawIdent => {
2600+
f.write_str("r#")?;
2601+
self.symbol
2602+
}
2603+
IdentPrintMode::RawLifetime => {
2604+
f.write_str("'r#")?;
2605+
let s = self
2606+
.symbol
2607+
.as_str()
2608+
.strip_prefix("'")
2609+
.expect("only lifetime idents should be passed with RawLifetime mode");
2610+
Symbol::intern(s)
2611+
}
2612+
};
2613+
s.fmt(f)
25892614
}
25902615
}
25912616

@@ -3020,6 +3045,29 @@ impl Ident {
30203045
self.name.can_be_raw() && self.is_reserved()
30213046
}
30223047

3048+
/// Given the name of a lifetime without the first quote (`'`),
3049+
/// returns whether the lifetime name is reserved (therefore invalid)
3050+
pub fn is_reserved_lifetime(self) -> bool {
3051+
self.is_reserved() && ![kw::Underscore, kw::Static].contains(&self.name)
3052+
}
3053+
3054+
pub fn is_raw_lifetime_guess(self) -> bool {
3055+
let name_without_apostrophe = self.without_first_quote();
3056+
name_without_apostrophe.name != self.name
3057+
&& name_without_apostrophe.name.can_be_raw()
3058+
&& name_without_apostrophe.is_reserved_lifetime()
3059+
}
3060+
3061+
pub fn guess_print_mode(self) -> IdentPrintMode {
3062+
if self.is_raw_lifetime_guess() {
3063+
IdentPrintMode::RawLifetime
3064+
} else if self.is_raw_guess() {
3065+
IdentPrintMode::RawIdent
3066+
} else {
3067+
IdentPrintMode::Normal
3068+
}
3069+
}
3070+
30233071
/// Whether this would be the identifier for a tuple field like `self.0`, as
30243072
/// opposed to a named field like `self.thing`.
30253073
pub fn is_numeric(self) -> bool {

tests/ui/closures/issue-52437.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
fn main() {
22
[(); &(&'static: loop { |x| {}; }) as *const _ as usize]
3-
//~^ ERROR: invalid label name `'static`
3+
//~^ ERROR: labels cannot use keyword names
44
//~| ERROR: type annotations needed
55
}

0 commit comments

Comments
 (0)