Skip to content

ICE: called Option::unwrap() on a None value in when using proc macro #141764

Closed
@FrTerstappen

Description

@FrTerstappen

Hello,

I encountered an ICE while writing a proc-macro. The idea is to wrap the content of a function with the attribute on it in a closure and then call it. (The real code does some extra steps but those are not important here).

This looks like the following in quote!:

let closure = move || {
    #block
};

let mut result = closure();

result

The problem is the missing mut when the original function mutates any of its arguments.
It works without problems for functions that do not mutate their arguments.

When the code produced by the proc-macro is inlined by hand the compiler correctly identifies the missing mut and works as expected.

Code

I uploaded my reproduction on https://github.com/FrTerstappen/rust-ice-20250530

Cargo.toml

[workspace]
resolver = "3"
exclude = []

members = ["crates/ice_proc_macro", "crates/ice_test"]
default-members = ["crates/ice_test"]

[workspace.package]
version = "0.0.0"
edition = "2024"
license = "UNLICENSED"
publish = false
readme = "README.md"
authors = ["Dummy"]
rust-version = "1.87.0"
repository = "Dummy"

[workspace.dependencies]
proc-macro2 = { version = "1.0.95", default-features = false }
quote = { version = "1.0.40", default-features = false }
syn = { version = "2.0.101", default-features = true, features = ["full"] }
ice_proc_macro = { version = "0.0.0", path = "crates/ice_proc_macro" }

ice_test/Cargo.toml

[package]
name = "ice_test"
description = "TODO"
version.workspace = true
edition.workspace = true
license.workspace = true
publish.workspace = true
readme.workspace = true
authors.workspace = true
rust-version.workspace = true
repository.workspace = true

[dependencies]
ice_proc_macro.workspace = true

ice_test/src/main.rs

fn main() {
    let mut dummy = 0;
    test_ice(&mut dummy);
}

#[ice_proc_macro::slow_warning()]
pub fn test_ice(dummy: &mut i32) {
    *dummy += 1;
}

ice_proc_macro/Cargo.toml

[package]
name = "ice_proc_macro"
version.workspace = true
edition.workspace = true
license.workspace = true
publish.workspace = true
readme.workspace = true
authors.workspace = true
rust-version.workspace = true
repository.workspace = true

[lib]
proc-macro = true

[dependencies]
proc-macro2.workspace = true
quote.workspace = true
syn = { workspace = true, features = ["full"] }

ice_proc_macro/src/lib.rs

use proc_macro::TokenStream;
use quote::{ToTokens as _, quote};
use syn::{parse, *};

#[proc_macro_attribute]
pub fn slow_warning(_attr: TokenStream, item: TokenStream) -> TokenStream {
    let parsed = parse(item).unwrap();

    let Item::Fn(function) = parsed else {
        panic!("This can only be used on functions");
    };

    let block = Block {
        brace_token: function.block.brace_token,
        stmts: vec![],
    };

    let mut wrapped_function = ItemFn {
        attrs: function.attrs.clone(),
        vis: function.vis.clone(),
        sig: function.sig.clone(),
        block: Box::new(block),
    };

    let block = function.block;

    let quoted = quote! {{
        let closure = move || {
            #block
        };

        let mut result = closure();

        result
    }};

    let token_stream = quoted.into();
    let parsed = parse(token_stream).unwrap();

    wrapped_function.block = parsed;

    let token_stream = wrapped_function.into_token_stream();
    token_stream.into()
}

Meta

rustc --version --verbose:

rustc 1.89.0-nightly (1bbd62e54 2025-05-29)
binary: rustc
commit-hash: 1bbd62e547ba5cc08ccb44c27def3d33195d2dd5
commit-date: 2025-05-29
host: x86_64-unknown-linux-gnu
release: 1.89.0-nightly
LLVM version: 20.1.5

Error output

   Compiling ice_test v0.0.0 (/home/username/Documents/IceTest/crates/ice_test)

thread 'rustc' panicked at compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs:847:56:
called `Option::unwrap()` on a `None` value
stack backtrace:
   0:     0x76e930aa5273 - <std::sys::backtrace::BacktraceLock::print::DisplayBacktrace as core::fmt::Display>::fmt::h05e9f29e57dbb2e9
   1:     0x76e931202af7 - core::fmt::write::hd2dec42d1c7eed2b
   2:     0x76e930a9b0f3 - std::io::Write::write_fmt::he35f7ccd30502a06
   3:     0x76e930aa50d2 - std::sys::backtrace::BacktraceLock::print::h0f7594efff5cfc74
   4:     0x76e930aa8cca - std::panicking::default_hook::{{closure}}::h8c1a12024f8172d5
   5:     0x76e930aa884f - std::panicking::default_hook::h9b1e5be56a49e97f
   6:     0x76e92fb0d693 - std[aebe2beb07d4602e]::panicking::update_hook::<alloc[afc79f7023c726bc]::boxed::Box<rustc_driver_impl[fce054646584467]::install_ice_hook::{closure#1}>>::{closure#0}
   7:     0x76e930aa9543 - std::panicking::rust_panic_with_hook::h466604244439fd1e
   8:     0x76e930aa9206 - std::panicking::begin_panic_handler::{{closure}}::h6ba0bdba6613eee2
   9:     0x76e930aa5739 - std::sys::backtrace::__rust_end_short_backtrace::h1c6dac257377e0cf
  10:     0x76e930aa8efd - __rustc[9ea1f2a0e5b4e008]::rust_begin_unwind
  11:     0x76e92d2a7820 - core::panicking::panic_fmt::h5eca1388f6f924aa
  12:     0x76e92d2ad8cc - core::panicking::panic::h8b23f86cb3cf8301
  13:     0x76e92d2a9379 - core::option::unwrap_failed::h0567c92acfdde0c7
  14:     0x76e92f8ac898 - <rustc_borrowck[16831c75c4923d8d]::MirBorrowckCtxt>::show_mutating_upvar
  15:     0x76e92f13c6c8 - <rustc_borrowck[16831c75c4923d8d]::MirBorrowckCtxt>::report_mutability_error
  16:     0x76e9324bb7f7 - rustc_borrowck[16831c75c4923d8d]::do_mir_borrowck
  17:     0x76e9314db80a - rustc_borrowck[16831c75c4923d8d]::mir_borrowck
  18:     0x76e9314db519 - rustc_query_impl[b8ddf5711aeae68a]::plumbing::__rust_begin_short_backtrace::<rustc_query_impl[b8ddf5711aeae68a]::query_impl::mir_borrowck::dynamic_query::{closure#2}::{closure#0}, rustc_middle[f62d8e2871d7ed5a]::query::erase::Erased<[u8; 8usize]>>
  19:     0x76e9314e291f - rustc_query_system[e527f3fe7b1ba41c]::query::plumbing::try_execute_query::<rustc_query_impl[b8ddf5711aeae68a]::DynamicConfig<rustc_data_structures[63644864ec52dfbb]::vec_cache::VecCache<rustc_span[674833ee7b2aca12]::def_id::LocalDefId, rustc_middle[f62d8e2871d7ed5a]::query::erase::Erased<[u8; 8usize]>, rustc_query_system[e527f3fe7b1ba41c]::dep_graph::graph::DepNodeIndex>, false, false, false>, rustc_query_impl[b8ddf5711aeae68a]::plumbing::QueryCtxt, true>
  20:     0x76e9313a2d97 - rustc_query_impl[b8ddf5711aeae68a]::query_impl::mir_borrowck::get_query_incr::__rust_end_short_backtrace
  21:     0x76e931d3095b - rustc_mir_transform[8802a7a466bf19d]::mir_drops_elaborated_and_const_checked
  22:     0x76e931d2ffef - rustc_query_impl[b8ddf5711aeae68a]::plumbing::__rust_begin_short_backtrace::<rustc_query_impl[b8ddf5711aeae68a]::query_impl::mir_drops_elaborated_and_const_checked::dynamic_query::{closure#2}::{closure#0}, rustc_middle[f62d8e2871d7ed5a]::query::erase::Erased<[u8; 8usize]>>
  23:     0x76e9314e291f - rustc_query_system[e527f3fe7b1ba41c]::query::plumbing::try_execute_query::<rustc_query_impl[b8ddf5711aeae68a]::DynamicConfig<rustc_data_structures[63644864ec52dfbb]::vec_cache::VecCache<rustc_span[674833ee7b2aca12]::def_id::LocalDefId, rustc_middle[f62d8e2871d7ed5a]::query::erase::Erased<[u8; 8usize]>, rustc_query_system[e527f3fe7b1ba41c]::dep_graph::graph::DepNodeIndex>, false, false, false>, rustc_query_impl[b8ddf5711aeae68a]::plumbing::QueryCtxt, true>
  24:     0x76e9313a25e5 - rustc_query_impl[b8ddf5711aeae68a]::query_impl::mir_drops_elaborated_and_const_checked::get_query_incr::__rust_end_short_backtrace
  25:     0x76e92ff709a5 - <rustc_middle[f62d8e2871d7ed5a]::ty::context::TyCtxt>::par_hir_body_owners::<rustc_interface[82c1fd2543dc0997]::passes::run_required_analyses::{closure#2}::{closure#0}>::{closure#0}
  26:     0x76e92ff4dd6c - rustc_data_structures[63644864ec52dfbb]::sync::parallel::par_slice::par_rec::<&rustc_span[674833ee7b2aca12]::def_id::LocalDefId, rustc_data_structures[63644864ec52dfbb]::sync::parallel::par_for_each_in<&rustc_span[674833ee7b2aca12]::def_id::LocalDefId, &[rustc_span[674833ee7b2aca12]::def_id::LocalDefId], <rustc_middle[f62d8e2871d7ed5a]::ty::context::TyCtxt>::par_hir_body_owners<rustc_interface[82c1fd2543dc0997]::passes::run_required_analyses::{closure#2}::{closure#0}>::{closure#0}>::{closure#0}::{closure#0}>
  27:     0x76e92ffaa6e0 - <rayon_core[6e5c1cc81dd3488b]::job::StackJob<rayon_core[6e5c1cc81dd3488b]::latch::SpinLatch, rayon_core[6e5c1cc81dd3488b]::join::join_context::call_b<(), rayon_core[6e5c1cc81dd3488b]::join::join::call<(), rustc_data_structures[63644864ec52dfbb]::sync::parallel::par_slice::par_rec<&rustc_span[674833ee7b2aca12]::def_id::LocalDefId, rustc_data_structures[63644864ec52dfbb]::sync::parallel::par_for_each_in<&rustc_span[674833ee7b2aca12]::def_id::LocalDefId, &[rustc_span[674833ee7b2aca12]::def_id::LocalDefId], <rustc_middle[f62d8e2871d7ed5a]::ty::context::TyCtxt>::par_hir_body_owners<rustc_interface[82c1fd2543dc0997]::passes::run_required_analyses::{closure#2}::{closure#0}>::{closure#0}>::{closure#0}::{closure#0}>::{closure#2}>::{closure#0}>::{closure#0}, ()> as rayon_core[6e5c1cc81dd3488b]::job::Job>::execute
  28:     0x76e92f5f833e - <rayon_core[6e5c1cc81dd3488b]::registry::WorkerThread>::wait_until_cold
  29:     0x76e92f5f5cc1 - <rayon_core[6e5c1cc81dd3488b]::registry::ThreadBuilder>::run
  30:     0x76e92fb035bd - std[aebe2beb07d4602e]::sys::backtrace::__rust_begin_short_backtrace::<<rayon_core[6e5c1cc81dd3488b]::ThreadPoolBuilder>::build_scoped<rustc_interface[82c1fd2543dc0997]::util::run_in_thread_pool_with_globals<rustc_interface[82c1fd2543dc0997]::interface::run_compiler<(), rustc_driver_impl[fce054646584467]::run_compiler::{closure#0}>::{closure#1}, ()>::{closure#5}::{closure#0}::{closure#0}, rustc_interface[82c1fd2543dc0997]::util::run_in_thread_pool_with_globals<rustc_interface[82c1fd2543dc0997]::interface::run_compiler<(), rustc_driver_impl[fce054646584467]::run_compiler::{closure#0}>::{closure#1}, ()>::{closure#5}::{closure#0}::{closure#1}, ()>::{closure#0}::{closure#0}::{closure#0}, ()>
  31:     0x76e92fb12592 - <<std[aebe2beb07d4602e]::thread::Builder>::spawn_unchecked_<<rayon_core[6e5c1cc81dd3488b]::ThreadPoolBuilder>::build_scoped<rustc_interface[82c1fd2543dc0997]::util::run_in_thread_pool_with_globals<rustc_interface[82c1fd2543dc0997]::interface::run_compiler<(), rustc_driver_impl[fce054646584467]::run_compiler::{closure#0}>::{closure#1}, ()>::{closure#5}::{closure#0}::{closure#0}, rustc_interface[82c1fd2543dc0997]::util::run_in_thread_pool_with_globals<rustc_interface[82c1fd2543dc0997]::interface::run_compiler<(), rustc_driver_impl[fce054646584467]::run_compiler::{closure#0}>::{closure#1}, ()>::{closure#5}::{closure#0}::{closure#1}, ()>::{closure#0}::{closure#0}::{closure#0}, ()>::{closure#1} as core[50b5a8f5e07183b8]::ops::function::FnOnce<()>>::call_once::{shim:vtable#0}
  32:     0x76e9323baebd - std::sys::pal::unix::thread::Thread::new::thread_start::h45be790786894548
  33:     0x76e92bea57eb - <unknown>
  34:     0x76e92bf2918c - <unknown>
  35:                0x0 - <unknown>

error: the compiler unexpectedly panicked. this is a bug.

note: we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md

note: please make sure that you have updated to the latest nightly

note: please attach the file at `/home/username/Documents/IceTest/rustc-ice-2025-05-30T11_08_17-190002.txt` to your bug report

note: compiler flags: --crate-type bin -C embed-bitcode=no -C debuginfo=2 -C linker=clang -C incremental=[REDACTED] -C link-arg=-fuse-ld=/usr/bin/mold -C link-arg=-Wl,--no-rosegment -Z share-generics=y -Z threads=0 -C target-feature=+x87

note: some of the compiler flags provided by cargo are hidden

query stack during panic:
#0 [mir_borrowck] borrow-checking `test_ice`
#1 [mir_drops_elaborated_and_const_checked] elaborating drops for `test_ice::{closure#0}`
#2 [analysis] running analysis passes on this crate
end of query stack
error: could not compile `ice_test` (bin "ice_test")

Caused by:
  process didn't exit successfully: `/home/username/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/rustc --crate-name ice_test --edition=2024 crates/ice_test/src/main.rs --error-format=json --json=diagnostic-rendered-ansi,artifacts,future-incompat --diagnostic-width=259 --crate-type bin --emit=dep-info,link -C embed-bitcode=no -C debuginfo=2 --check-cfg 'cfg(docsrs,test)' --check-cfg 'cfg(feature, values())' -C metadata=a97ebdd71087afaa -C extra-filename=-4e58fb3e312afec5 --out-dir /home/username/Documents/IceTest/target/x86_64-unknown-linux-gnu/debug/deps --target x86_64-unknown-linux-gnu -C linker=clang -C incremental=/home/username/Documents/IceTest/target/x86_64-unknown-linux-gnu/debug/incremental -L dependency=/home/username/Documents/IceTest/target/x86_64-unknown-linux-gnu/debug/deps -L dependency=/home/username/Documents/IceTest/target/debug/deps --extern ice_proc_macro=/home/username/Documents/IceTest/target/debug/deps/libice_proc_macro-30ef8dc7428832ac.so -Clink-arg=-fuse-ld=/usr/bin/mold -Clink-arg=-Wl,--no-rosegment -Zshare-generics=y -Zthreads=0 -Ctarget-feature=+x87` (exit status: 101)
Backtrace

RUST_BACKTRACE=1 cargo run
   Compiling ice_test v0.0.0 (/home/username/Documents/IceTest/crates/ice_test)

thread 'rustc' panicked at compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs:847:56:
called `Option::unwrap()` on a `None` value
stack backtrace:
   0: __rustc::rust_begin_unwind
   1: core::panicking::panic_fmt
   2: core::panicking::panic
   3: core::option::unwrap_failed
   4: <rustc_borrowck::MirBorrowckCtxt>::show_mutating_upvar
   5: <rustc_borrowck::MirBorrowckCtxt>::report_mutability_error
   6: rustc_borrowck::do_mir_borrowck
   7: rustc_borrowck::mir_borrowck
      [... omitted 1 frame ...]
   8: rustc_mir_transform::mir_drops_elaborated_and_const_checked
      [... omitted 1 frame ...]
   9: <rustc_middle::ty::context::TyCtxt>::par_hir_body_owners::<rustc_interface::passes::run_required_analyses::{closure#2}::{closure#0}>::{closure#0}
  10: rustc_data_structures::sync::parallel::par_slice::par_rec::<&rustc_span::def_id::LocalDefId, rustc_data_structures::sync::parallel::par_for_each_in<&rustc_span::def_id::LocalDefId, &[rustc_span::def_id::LocalDefId], <rustc_middle::ty::context::TyCtxt>::par_hir_body_owners<rustc_interface::passes::run_required_analyses::{closure#2}::{closure#0}>::{closure#0}>::{closure#0}::{closure#0}>
  11: <rayon_core::job::StackJob<rayon_core::latch::SpinLatch, rayon_core::join::join_context::call_b<(), rayon_core::join::join::call<(), rustc_data_structures::sync::parallel::par_slice::par_rec<&rustc_span::def_id::LocalDefId, rustc_data_structures::sync::parallel::par_for_each_in<&rustc_span::def_id::LocalDefId, &[rustc_span::def_id::LocalDefId], <rustc_middle::ty::context::TyCtxt>::par_hir_body_owners<rustc_interface::passes::run_required_analyses::{closure#2}::{closure#0}>::{closure#0}>::{closure#0}::{closure#0}>::{closure#2}>::{closure#0}>::{closure#0}, ()> as rayon_core::job::Job>::execute
  12: <rayon_core::registry::WorkerThread>::wait_until_cold
  13: <rayon_core::registry::ThreadBuilder>::run
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

error: the compiler unexpectedly panicked. this is a bug.

note: we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md

note: please make sure that you have updated to the latest nightly

note: please attach the file at `/home/username/Documents/IceTest/rustc-ice-2025-05-30T11_13_14-190503.txt` to your bug report

note: compiler flags: --crate-type bin -C embed-bitcode=no -C debuginfo=2 -C linker=clang -C incremental=[REDACTED] -C link-arg=-fuse-ld=/usr/bin/mold -C link-arg=-Wl,--no-rosegment -Z share-generics=y -Z threads=0 -C target-feature=+x87

note: some of the compiler flags provided by cargo are hidden

query stack during panic:
#0 [mir_borrowck] borrow-checking `test_ice`
#1 [mir_drops_elaborated_and_const_checked] elaborating drops for `test_ice::{closure#0}`
#2 [analysis] running analysis passes on this crate
end of query stack
error: could not compile `ice_test` (bin "ice_test")

Caused by:
  process didn't exit successfully: `/home/username/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/rustc --crate-name ice_test --edition=2024 crates/ice_test/src/main.rs --error-format=json --json=diagnostic-rendered-ansi,artifacts,future-incompat --diagnostic-width=242 --crate-type bin --emit=dep-info,link -C embed-bitcode=no -C debuginfo=2 --check-cfg 'cfg(docsrs,test)' --check-cfg 'cfg(feature, values())' -C metadata=a97ebdd71087afaa -C extra-filename=-4e58fb3e312afec5 --out-dir /home/username/Documents/IceTest/target/x86_64-unknown-linux-gnu/debug/deps --target x86_64-unknown-linux-gnu -C linker=clang -C incremental=/home/username/Documents/IceTest/target/x86_64-unknown-linux-gnu/debug/incremental -L dependency=/home/username/Documents/IceTest/target/x86_64-unknown-linux-gnu/debug/deps -L dependency=/home/username/Documents/IceTest/target/debug/deps --extern ice_proc_macro=/home/username/Documents/IceTest/target/debug/deps/libice_proc_macro-30ef8dc7428832ac.so -Clink-arg=-fuse-ld=/usr/bin/mold -Clink-arg=-Wl,--no-rosegment -Zshare-generics=y -Zthreads=0 -Ctarget-feature=+x87` (exit status: 101)

rustc-ice-2025-05-30T11_13_14-190503.txt

Metadata

Metadata

Assignees

Labels

A-proc-macrosArea: Procedural macrosC-bugCategory: This is a bug.I-ICEIssue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️S-has-bisectionStatus: A bisection has been found for this issueS-has-mcveStatus: A Minimal Complete and Verifiable Example has been found for this issueT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.regression-from-stable-to-betaPerformance or correctness regression from stable to beta.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions