Skip to content

ICE caused by ill-formed frontmatter #146847

@mattheww

Description

@mattheww

Code

---
🦀---
 ---
fn main() {}

Meta

rustc --version --verbose:

rustc 1.92.0-nightly (dd7fda570 2025-09-20)
binary: rustc
commit-hash: dd7fda570040e8a736f7d8bc28ddd1b444aabc82
commit-date: 2025-09-20
host: x86_64-unknown-linux-gnu
release: 1.92.0-nightly
LLVM version: 21.1.1

I also see the ICE with rustc 1.91.0-beta.3 (bb624dcb4 2025-09-20).

I don't see it with rustc 1.90.0 (1159e78c4 2025-09-14).

The frontmatter feature doesn't have to be enabled to trigger the ICE.

Error output

thread 'rustc' panicked at compiler/rustc_lexer/src/cursor.rs:107:35:
byte index 2 is not a char boundary; it is inside '🦀' (bytes 1..5) of `
🦀---
 ---
fn main() {}
`
Backtrace

   0:     0x7fc61b1cdb3b - std::backtrace::Backtrace::create::h06ccc4de5e73e7e1
   1:     0x7fc61b1cda85 - std::backtrace::Backtrace::force_capture::h4765cb67bc9e21a4
   2:     0x7fc61a1f2b32 - std[aa543e5c3b33e14e]::panicking::update_hook::<alloc[25bb32ac37752f7b]::boxed::Box<rustc_driver_impl[4e82038d4654c963]::install_ice_hook::{closure#1}>>::{closure#0}
   3:     0x7fc61b1cea7f - std::panicking::panic_with_hook::h8cbd8c4377e6572b
   4:     0x7fc61b1ce83a - std::panicking::panic_handler::{{closure}}::h335ded1aca77b6b6
   5:     0x7fc61b1c8839 - std::sys::backtrace::__rust_end_short_backtrace::hd229ab5df32e8172
   6:     0x7fc61b1a936d - __rustc[8ed8e68a5aa5849d]::rust_begin_unwind
   7:     0x7fc6181f3dd0 - core::panicking::panic_fmt::hb55754338c38e2ee
   8:     0x7fc619be66aa - core::str::slice_error_fail_rt::h1fd793c762d93745
   9:     0x7fc619afd41a - core::str::slice_error_fail::h9e0a180626673ba0
  10:     0x7fc61a669571 - <rustc_lexer[b996fa3129a85722]::cursor::Cursor>::bump_bytes
  11:     0x7fc61a6699ae - <rustc_lexer[b996fa3129a85722]::cursor::Cursor>::frontmatter
  12:     0x7fc61d1d8d4c - <rustc_lexer[b996fa3129a85722]::cursor::Cursor>::advance_token.cold
  13:     0x7fc6180d41a2 - <rustc_parse[21bbc4d95d28445f]::lexer::Lexer>::bump_minimal
  14:     0x7fc61ce607e8 - <rustc_parse[21bbc4d95d28445f]::lexer::Lexer>::lex_token_trees
  15:     0x7fc61ce60124 - rustc_parse[21bbc4d95d28445f]::source_file_to_stream
  16:     0x7fc61c0a7eba - rustc_parse[21bbc4d95d28445f]::new_parser_from_source_file
  17:     0x7fc61ce5dfcb - rustc_interface[ddde8db7de1554b0]::passes::parse
  18:     0x7fc61cc14fd8 - rustc_interface[ddde8db7de1554b0]::interface::run_compiler::<(), rustc_driver_impl[4e82038d4654c963]::run_compiler::{closure#0}>::{closure#1}
  19:     0x7fc61cb97db8 - std[aa543e5c3b33e14e]::sys::backtrace::__rust_begin_short_backtrace::<rustc_interface[ddde8db7de1554b0]::util::run_in_thread_with_globals<rustc_interface[ddde8db7de1554b0]::util::run_in_thread_pool_with_globals<rustc_interface[ddde8db7de1554b0]::interface::run_compiler<(), rustc_driver_impl[4e82038d4654c963]::run_compiler::{closure#0}>::{closure#1}, ()>::{closure#0}, ()>::{closure#0}::{closure#0}, ()>
  20:     0x7fc61cb97a88 - <<std[aa543e5c3b33e14e]::thread::Builder>::spawn_unchecked_<rustc_interface[ddde8db7de1554b0]::util::run_in_thread_with_globals<rustc_interface[ddde8db7de1554b0]::util::run_in_thread_pool_with_globals<rustc_interface[ddde8db7de1554b0]::interface::run_compiler<(), rustc_driver_impl[4e82038d4654c963]::run_compiler::{closure#0}>::{closure#1}, ()>::{closure#0}, ()>::{closure#0}::{closure#0}, ()>::{closure#1} as core[e1f2d92e823976a5]::ops::function::FnOnce<()>>::call_once::{shim:vtable#0}
  21:     0x7fc61cb9ddcd - std::sys::thread::unix::Thread::new::thread_start::ha9de35456108e0f3
  22:     0x7fc6164a71f5 - start_thread
                               at ./nptl/pthread_create.c:442:8
  23:     0x7fc6165278dc - clone3
                               at ./misc/../sysdeps/unix/sysv/linux/x86_64/clone3.S:81:0
  24:                0x0 - <unknown>

Notes

I think the problem is in the "less fortunate recovery" path in rustc_lexer::cursor::Cursor::frontmatter().

potential_closing is supposed to be an offset from the current cursor, but when that path examines more than one candidate potential_closing ends up being an offset from the end of previous candidate.

(So I think even when there isn't an ICE, the recovery isn't working as intended if there's a --- which isn't chosen by recovery.)

Metadata

Metadata

Assignees

Labels

A-lexerArea: lexerC-bugCategory: This is a bug.F-frontmatter`#![feature(frontmatter)]`I-ICEIssue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions