{"id":"aec9ac8f4d52c20e","repo":"rust-lang/rust","slug":"expected-error","errorCode":null,"errorMessage":"expected error","messagePattern":"expected error","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"compiler/rustc_parse/src/lexer/mod.rs","lineNumber":356,"sourceCode":"                    if prefix_span.at_least_rust_2021() {\n                        // If the raw lifetime is followed by \\' then treat it a normal\n                        // lifetime followed by a \\', which is to interpret it as a character\n                        // literal. In this case, it's always an invalid character literal\n                        // since the literal must necessarily have >3 characters (r#...) inside\n                        // of it, which is invalid.\n                        if self.cursor.as_str().starts_with('\\'') {\n                            let lit_span = self.mk_sp(start, self.pos + BytePos(1));\n                            let contents = self.str_from_to(start + BytePos(1), self.pos);\n                            emit_unescape_error(\n                                self.dcx(),\n                                contents,\n                                lit_span,\n                                lit_span,\n                                Mode::Char,\n                                0..contents.len(),\n                                EscapeError::MoreThanOneChar,\n                            )\n                            .expect(\"expected error\");\n                        }\n\n                        let span = self.mk_sp(start, self.pos);\n\n                        let lifetime_name_without_tick =\n                            Symbol::intern(&self.str_from(ident_start));\n                        if !lifetime_name_without_tick.can_be_raw() {\n                            self.dcx().emit_err(\n                                crate::diagnostics::CannotBeRawLifetime {\n                                    span,\n                                    ident: lifetime_name_without_tick\n                                }\n                            );\n                        }\n\n                        // Put the `'` back onto the lifetime name.\n                        let mut lifetime_name =\n                            String::with_capacity(lifetime_name_without_tick.as_str().len() + 1);","sourceCodeStart":338,"sourceCodeEnd":374,"githubUrl":"https://github.com/rust-lang/rust/blob/22057b88b091743bc0fd8d592a9264f0a6951403/compiler/rustc_parse/src/lexer/mod.rs#L338-L374","documentation":"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.","triggerScenarios":"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`.","commonSituations":"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.","solutions":["Determine whether the offending token is generator output; if so, fix the generator to avoid emitting `r#'<ident>'` sequences","Reduce the triggering source to a minimal file and report it as a rustc lexer ICE with the backtrace","Run on stable to confirm whether it is a nightly regression in the raw-identifier/lifetime lexer"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"use rustc_span::BytePos;\n// Verify the source window is actually malformed the way the lexer expects it to be\n// before invoking the error-expecting path in rustc_parse::lexer.\nfn source_window_is_errored(src: &str, start: BytePos, end: BytePos) -> bool {\n    let s = &src[start.to_usize()..end.to_usize()];\n    // crude check: contains a known-bad token sequence\n    s.contains(\"\\\\\") || !rustc_lexer::is_terminal(s)\n}\nif !source_window_is_errored(src, lo, hi) { return Ok(()); }","typeGuard":null,"tryCatchPattern":"use std::panic;\nmatch panic::catch_unwind(panic::AssertUnwindSafe(|| lexer.expect_error(token))) {\n    Ok(()) => {},\n    Err(_) => /* lexer disagreed about erroneousness; skip the diagnostic */ {},\n}","preventionTips":["Only call the error-expecting lexer path for source spans you have already classified as erroneous via a pre-scan.","Keep your source classification in sync with rustc_lexer's token table so 'expected error' assertions never mismatch.","Avoid hand-feeding token windows to the lexer; prefer full-source tokenization so the lexer's own state machine stays consistent.","If you mutate source text between lexing passes, re-tokenize from scratch rather than reusing spans."],"tags":["compiler-ice","lexer","raw-identifiers","edition-2021"],"analyzedSha":"22057b88b091743bc0fd8d592a9264f0a6951403","analyzedAt":"2026-08-03T08:09:25.915Z","schemaVersion":2}