Skip to content

[rustc] ICE in SimplifyLocals: LocalUpdater unwraps None when optimizing MIR for main combining enum with #[rustc_dummy] variants, String drop, and reborrow across codegen units #153601

@YuanchengJiang

Description

@YuanchengJiang

Related to #147485

Description

rustc panics with called Option::unwrap() on a None value in SimplifyLocals::run_passLocalUpdater::super_basic_block_data when compiling a crate where main calls two functions from different logical origins: one involving an enum whose variants are annotated with #[rustc_dummy] and a String parameter (introducing drop glue), and one involving a reference reborrow. The crash only manifests under -C opt-level=3 -C codegen-units=16 -g -C debug-assertions=yes.

Reproducer

#![allow(non_camel_case_types)]
#![feature(rustc_attrs)]

enum crew_of_enterprise_d {
    #[rustc_dummy] worf,
}

fn boldly_go(_crew_member: crew_of_enterprise_d, _where: String) {}

fn main_d1342639() {
    boldly_go(crew_of_enterprise_d::worf, "x".to_string());
}

fn foo(x: &isize) {
    let a = 1;
    let mut z = x;
    z = &a;
}

fn main_c31c2192() {
    foo(&1);
}

fn main() {
    main_d1342639();
    main_c31c2192();
}

Command

rustc -C opt-level=3 -C codegen-units=16 -g -C debug-assertions=yes reproduce.rs

Expected behavior

The program compiles successfully. None of the code is invalid Rust; #[rustc_dummy] is an internal attribute but should not cause a compiler panic.

Actual behavior

thread 'rustc' panicked at compiler/rustc_mir_transform/src/simplify.rs:677:27:
called `Option::unwrap()` on a `None` value
error: the compiler unexpectedly panicked. This is a bug

query stack during panic:
#0 [optimized_mir] optimizing MIR for `main`
#1 [items_of_instance] collecting items used by `main`
... and 1 other queries...

Root cause analysis

The call chain is:

run_optimization_passes
  → SimplifyLocals::run_pass          (simplify.rs:455)
    → LocalUpdater::visit_body_preserves_cfg
      → LocalUpdater::super_basic_block_data  (simplify.rs:677)  ← panic

SimplifyLocals builds a remapping table of live locals and then LocalUpdater walks the MIR rewriting all local references through that table. The unwrap() at line 677 fires when a local is referenced in the MIR body but has no entry in the remapping — meaning SimplifyLocals incorrectly classified it as removable while it was still live. The combination of #[rustc_dummy] on enum variants (which affects attribute processing during MIR construction), String drop glue (which introduces additional MIR locals for the destructor), and a reference reborrow in the same main under debuginfo (-g, which adds StorageLive/StorageDead scope locals) with -C codegen-units=16 appears to confuse the liveness analysis, causing a local to be placed in the remove set while still being referenced.

Environment

  • Compiler: rustc 1.95.0-nightly
  • Commit: 9b1f8ff42d110b0ca138116745be921df5dc97e7
  • Host: x86_64-unknown-linux-gnu
  • Required flags: -C opt-level=3 -C codegen-units=16 -g -C debug-assertions=yes
  • Requires: #![feature(rustc_attrs)]

Metadata

Metadata

Assignees

Labels

A-mir-optArea: MIR optimizationsC-bugCategory: This is a bug.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.requires-debug-assertionsThis issue requires a build of rustc or tooling with debug-assertions in some way

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions