rust-lang/rust · critical

expected error

Error message

expected error

What it means

Internal assertion in the lexer's raw-lifetime handling on Edition 2021+. When a raw lifetime token (e.g. `r#'a`) is immediately followed by another `'`, the lexer reinterprets the sequence as a malformed character literal and calls `emit_unescape_error` for `MoreThanOneChar`, which must return an `Err`. The `.expect("expected error")` asserts an error was actually emitted; if the unescape machinery returns `Ok`, the lexer's internal model is inconsistent and it panics rather than silently miscompile.

Source

Thrown at compiler/rustc_parse/src/lexer/mod.rs:356

                    if prefix_span.at_least_rust_2021() {
                        // If the raw lifetime is followed by \' then treat it a normal
                        // lifetime followed by a \', which is to interpret it as a character
                        // literal. In this case, it's always an invalid character literal
                        // since the literal must necessarily have >3 characters (r#...) inside
                        // of it, which is invalid.
                        if self.cursor.as_str().starts_with('\'') {
                            let lit_span = self.mk_sp(start, self.pos + BytePos(1));
                            let contents = self.str_from_to(start + BytePos(1), self.pos);
                            emit_unescape_error(
                                self.dcx(),
                                contents,
                                lit_span,
                                lit_span,
                                Mode::Char,
                                0..contents.len(),
                                EscapeError::MoreThanOneChar,
                            )
                            .expect("expected error");
                        }

                        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(
                                crate::diagnostics::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.as_str().len() + 1);

View on GitHub (pinned to 22057b88b0)

Solutions

  1. Determine whether the offending token is generator output; if so, fix the generator to avoid emitting `r#'<ident>'` sequences
  2. Reduce the triggering source to a minimal file and report it as a rustc lexer ICE with the backtrace
  3. Run on stable to confirm whether it is a nightly regression in the raw-identifier/lifetime lexer
Defensive patterns

Strategy: validation

Validate before calling

use rustc_span::BytePos;
// Verify the source window is actually malformed the way the lexer expects it to be
// before invoking the error-expecting path in rustc_parse::lexer.
fn source_window_is_errored(src: &str, start: BytePos, end: BytePos) -> bool {
    let s = &src[start.to_usize()..end.to_usize()];
    // crude check: contains a known-bad token sequence
    s.contains("\\") || !rustc_lexer::is_terminal(s)
}
if !source_window_is_errored(src, lo, hi) { return Ok(()); }

Try / catch

use std::panic;
match panic::catch_unwind(panic::AssertUnwindSafe(|| lexer.expect_error(token))) {
    Ok(()) => {},
    Err(_) => /* lexer disagreed about erroneousness; skip the diagnostic */ {},
}

Prevention

When it happens

Trigger: Lexing a raw lifetime immediately followed by a quote character in an Edition 2021+ crate — the `MoreThanOneChar` escape-error path of `emit_unescape_error` returns `Ok` instead of `Err`.

Common situations: Typo'd or machine-generated/proc-macro-emitted tokens of the shape `r#'<ident>'` in a 2021+ crate; exceedingly rare in hand-written source. Almost always indicates a lexer regression on nightly.

Related errors


AI-assisted analysis of rust-lang/rust@22057b88b0 (2026-08-03). Data as JSON: /data/errors/aec9ac8f4d52c20e.json. Report an issue: GitHub.