diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 1af7fb9b86a..ef259703f0c 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -77,6 +77,8 @@ parse_box_syntax_removed_suggestion = use `Box::new()` instead parse_cannot_be_raw_ident = `{$ident}` cannot be a raw identifier +parse_cannot_be_raw_lifetime = `{$ident}` cannot be a raw lifetime + parse_catch_after_try = keyword `catch` cannot follow a `try` block .help = try using `match` on the result of the `try` block instead diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index fdd500e90f8..7ec4ad6dc35 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -2018,6 +2018,14 @@ pub(crate) struct CannotBeRawIdent { pub ident: Symbol, } +#[derive(Diagnostic)] +#[diag(parse_cannot_be_raw_lifetime)] +pub(crate) struct CannotBeRawLifetime { + #[primary_span] + pub span: Span, + pub ident: Symbol, +} + #[derive(Diagnostic)] #[diag(parse_keyword_lifetime)] pub(crate) struct KeywordLifetime { diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index d627ef3d2cb..226de65445c 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -294,15 +294,21 @@ impl<'psess, 'src> StringReader<'psess, 'src> { 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); + let span = self.mk_sp(start, self.pos); + + let lifetime_name_without_tick = Symbol::intern(&self.str_from(ident_start)); + if !lifetime_name_without_tick.can_be_raw() { + self.dcx().emit_err(errors::CannotBeRawLifetime { span, ident: lifetime_name_without_tick }); + } + // Put the `'` back onto the lifetime name. - let mut lifetime_name = String::with_capacity(lifetime_name_without_tick.len() + 1); + let mut lifetime_name = String::with_capacity(lifetime_name_without_tick.as_str().len() + 1); lifetime_name.push('\''); - lifetime_name += lifetime_name_without_tick; + lifetime_name += lifetime_name_without_tick.as_str(); let sym = Symbol::intern(&lifetime_name); // Make sure we mark this as a raw identifier. - self.psess.raw_identifier_spans.push(self.mk_sp(start, self.pos)); + self.psess.raw_identifier_spans.push(span); token::Lifetime(sym, IdentIsRaw::Yes) } else { diff --git a/tests/ui/lifetimes/raw/raw-lt-invalid-raw-id.rs b/tests/ui/lifetimes/raw/raw-lt-invalid-raw-id.rs new file mode 100644 index 00000000000..882fad925f3 --- /dev/null +++ b/tests/ui/lifetimes/raw/raw-lt-invalid-raw-id.rs @@ -0,0 +1,20 @@ +//@ edition: 2021 + +// Reject raw lifetimes with identifier parts that wouldn't be valid raw identifiers. + +macro_rules! w { + ($tt:tt) => {}; +} + +w!('r#_); +//~^ ERROR `_` cannot be a raw lifetime +w!('r#self); +//~^ ERROR `self` cannot be a raw lifetime +w!('r#super); +//~^ ERROR `super` cannot be a raw lifetime +w!('r#Self); +//~^ ERROR `Self` cannot be a raw lifetime +w!('r#crate); +//~^ ERROR `crate` cannot be a raw lifetime + +fn main() {} diff --git a/tests/ui/lifetimes/raw/raw-lt-invalid-raw-id.stderr b/tests/ui/lifetimes/raw/raw-lt-invalid-raw-id.stderr new file mode 100644 index 00000000000..4cbb89b7a55 --- /dev/null +++ b/tests/ui/lifetimes/raw/raw-lt-invalid-raw-id.stderr @@ -0,0 +1,32 @@ +error: `_` cannot be a raw lifetime + --> $DIR/raw-lt-invalid-raw-id.rs:9:4 + | +LL | w!('r#_); + | ^^^^ + +error: `self` cannot be a raw lifetime + --> $DIR/raw-lt-invalid-raw-id.rs:11:4 + | +LL | w!('r#self); + | ^^^^^^^ + +error: `super` cannot be a raw lifetime + --> $DIR/raw-lt-invalid-raw-id.rs:13:4 + | +LL | w!('r#super); + | ^^^^^^^^ + +error: `Self` cannot be a raw lifetime + --> $DIR/raw-lt-invalid-raw-id.rs:15:4 + | +LL | w!('r#Self); + | ^^^^^^^ + +error: `crate` cannot be a raw lifetime + --> $DIR/raw-lt-invalid-raw-id.rs:17:4 + | +LL | w!('r#crate); + | ^^^^^^^^ + +error: aborting due to 5 previous errors +