Skip to content

ICE when using reference variable from iterator (instead of copying it): thread 'rustc' panicked at 'already borrowed: BorrowMutError' #66353

Closed
@azriel91

Description

@azriel91

When using zipped iterators in a certain section of code, I hit an ICE.

I've attached the project source -- sorry I could not produce a minimum example though I tried. Also, it's closed source, though I own it so can choose to provide the snapshot.

Symptoms:

  • Normally using zipped iterators doesn't cause an ICE, but in this case it is consistent (clean build, using rustc 1.39.0 (4560ea788 2019-11-04), and rustc 1.40.0-nightly (1423bec54 2019-11-05)).
  • Not zipping the iterators, and using .get(..) prevents the ICE from occurring.

This code fails to compile:

// These are calls to `slotmap::SparseSecondaryMap::get`
let ui_menu_items = asset_ui_menu_items.get(asset_id);
let ui_labels = asset_ui_labels.get(asset_id);
let position_inits = asset_position_inits.get(asset_id);

if let (Some(ui_menu_items), Some(ui_labels), Some(position_inits)) =
    (ui_menu_items, ui_labels, position_inits)
{
    let menu_items = ui_menu_items
        .iter()
        .enumerate()
        .zip(position_inits.iter())
        .zip(ui_labels.iter())
        .map(|(((order, ui_menu_item), position_init), ui_label)| {
            // ..
        });
}

This code compiles:

// These are calls to `slotmap::SparseSecondaryMap::get`
let ui_menu_items = asset_ui_menu_items.get(asset_id);
let ui_labels = asset_ui_labels.get(asset_id);
let position_inits = asset_position_inits.get(asset_id);

if let (Some(ui_menu_items), Some(ui_labels), Some(position_inits)) =
    (ui_menu_items, ui_labels, position_inits)
{
    let menu_items = ui_menu_items
        .iter()
        .enumerate()
        .map(|(order, ui_menu_item)| {
            //..
            let ui_label = ui_labels.get(order).unwrap_or_else(|| { /**/ });
            let position_init = position_inits.get(order).copied().unwrap_or_else(|| { /**/ });

            // ..
        });
}

Compilation error message:

thread 'rustc' panicked at 'already borrowed: BorrowMutError', src/libcore/result.rs:1165:5

# stack trace omitted, I've included it further down

note: rustc 1.39.0 (4560ea788 2019-11-04) running on x86_64-unknown-linux-gnu
note: compiler flags: -C debuginfo=2 -C incremental --crate-type lib
note: some of the compiler flags provided by cargo are hidden

query stack during panic:
#0 [typeck_tables_of] processing `system::game_mode_selection_widget_ui_system::GameModeSelectionWidgetUiSystem::initialize_ui`
#1 [typeck_item_bodies] type-checking all item bodies
#2 [analysis] running analysis passes on this crate
end of query stack
error: could not compile `game_mode_selection_ui`.

Meta

rustc --version --verbose:

  • 1.39 (stable):

    rustc 1.39.0 (4560ea788 2019-11-04)
    binary: rustc
    commit-hash: 4560ea788cb760f0a34127156c78e2552949f734
    commit-date: 2019-11-04
    host: x86_64-unknown-linux-gnu
    release: 1.39.0
    LLVM version: 9.0
    
  • 1.40 (nightly):

    rustc 1.40.0-nightly (1423bec54 2019-11-05)
    binary: rustc
    commit-hash: 1423bec54cf2db283b614e527cfd602b481485d1
    commit-date: 2019-11-05
    host: x86_64-unknown-linux-gnu
    release: 1.40.0-nightly
    LLVM version: 9.0
    

Backtrace:

1.39 stable
stack backtrace:
   0: backtrace::backtrace::libunwind::trace
             at /cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.37/src/backtrace/libunwind.rs:88
   1: backtrace::backtrace::trace_unsynchronized
             at /cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.37/src/backtrace/mod.rs:66
   2: std::sys_common::backtrace::_print_fmt
             at src/libstd/sys_common/backtrace.rs:76
   3: <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt
             at src/libstd/sys_common/backtrace.rs:60
   4: core::fmt::write
             at src/libcore/fmt/mod.rs:1030
   5: std::io::Write::write_fmt
             at src/libstd/io/mod.rs:1412
   6: std::sys_common::backtrace::_print
             at src/libstd/sys_common/backtrace.rs:64
   7: std::sys_common::backtrace::print
             at src/libstd/sys_common/backtrace.rs:49
   8: std::panicking::default_hook::{{closure}}
             at src/libstd/panicking.rs:196
   9: std::panicking::default_hook
             at src/libstd/panicking.rs:210
  10: rustc_driver::report_ice
  11: std::panicking::rust_panic_with_hook
             at src/libstd/panicking.rs:477
  12: std::panicking::continue_panic_fmt
             at src/libstd/panicking.rs:380
  13: rust_begin_unwind
             at src/libstd/panicking.rs:307
  14: core::panicking::panic_fmt
             at src/libcore/panicking.rs:85
  15: core::result::unwrap_failed
             at src/libcore/result.rs:1165
  16: rustc_typeck::check::Inherited::register_predicate
  17: rustc_typeck::check::Inherited::register_predicates
  18: <rustc_typeck::check::FnCtxt as rustc_typeck::astconv::AstConv>::normalize_ty
  19: <dyn rustc_typeck::astconv::AstConv>::res_to_ty
  20: <dyn rustc_typeck::astconv::AstConv>::ast_ty_to_ty
  21: rustc_typeck::check::FnCtxt::check_argument_types
  22: rustc_typeck::check::callee::<impl rustc_typeck::check::FnCtxt>::confirm_builtin_call
  23: rustc_typeck::check::callee::<impl rustc_typeck::check::FnCtxt>::check_call
  24: rustc_typeck::check::expr::<impl rustc_typeck::check::FnCtxt>::check_expr_kind
  25: rustc_typeck::check::expr::<impl rustc_typeck::check::FnCtxt>::check_expr_with_expectation_and_needs
  26: rustc_typeck::check::FnCtxt::check_decl_initializer
  27: rustc_typeck::check::FnCtxt::check_decl_local
  28: rustc_typeck::check::FnCtxt::check_stmt
  29: rustc_typeck::check::FnCtxt::check_block_with_expected
  30: rustc_typeck::check::expr::<impl rustc_typeck::check::FnCtxt>::check_expr_kind
  31: rustc_typeck::check::expr::<impl rustc_typeck::check::FnCtxt>::check_expr_with_expectation_and_needs
  32: rustc_typeck::check::expr::<impl rustc_typeck::check::FnCtxt>::check_return_expr
  33: rustc_typeck::check::check_fn
  34: rustc_typeck::check::closure::<impl rustc_typeck::check::FnCtxt>::check_expr_closure
  35: rustc_typeck::check::expr::<impl rustc_typeck::check::FnCtxt>::check_expr_kind
  36: rustc_typeck::check::expr::<impl rustc_typeck::check::FnCtxt>::check_expr_with_expectation_and_needs
  37: rustc_typeck::check::FnCtxt::check_argument_types
  38: rustc_typeck::check::FnCtxt::check_method_argument_types
  39: rustc_typeck::check::expr::<impl rustc_typeck::check::FnCtxt>::check_expr_kind
  40: rustc_typeck::check::expr::<impl rustc_typeck::check::FnCtxt>::check_expr_with_expectation_and_needs
  41: rustc_typeck::check::expr::<impl rustc_typeck::check::FnCtxt>::check_expr_kind
  42: rustc_typeck::check::expr::<impl rustc_typeck::check::FnCtxt>::check_expr_with_expectation_and_needs
  43: rustc_typeck::check::FnCtxt::check_decl_initializer
  44: rustc_typeck::check::FnCtxt::check_decl_local
  45: rustc_typeck::check::FnCtxt::check_stmt
  46: rustc_typeck::check::FnCtxt::check_block_with_expected
  47: rustc_typeck::check::expr::<impl rustc_typeck::check::FnCtxt>::check_expr_kind
  48: rustc_typeck::check::expr::<impl rustc_typeck::check::FnCtxt>::check_expr_with_expectation_and_needs
  49: rustc_typeck::check::_match::<impl rustc_typeck::check::FnCtxt>::check_match
  50: rustc_typeck::check::expr::<impl rustc_typeck::check::FnCtxt>::check_expr_kind
  51: rustc_typeck::check::expr::<impl rustc_typeck::check::FnCtxt>::check_expr_with_expectation_and_needs
  52: rustc_typeck::check::FnCtxt::check_block_with_expected
  53: rustc_typeck::check::expr::<impl rustc_typeck::check::FnCtxt>::check_expr_kind
  54: rustc_typeck::check::expr::<impl rustc_typeck::check::FnCtxt>::check_expr_with_expectation_and_needs
  55: rustc_typeck::check::_match::<impl rustc_typeck::check::FnCtxt>::check_match
  56: rustc_typeck::check::expr::<impl rustc_typeck::check::FnCtxt>::check_expr_kind
  57: rustc_typeck::check::expr::<impl rustc_typeck::check::FnCtxt>::check_expr_with_expectation_and_needs
  58: rustc_typeck::check::FnCtxt::check_block_with_expected
  59: rustc_typeck::check::expr::<impl rustc_typeck::check::FnCtxt>::check_expr_kind
  60: rustc_typeck::check::expr::<impl rustc_typeck::check::FnCtxt>::check_expr_with_expectation_and_needs
  61: rustc_typeck::check::expr::<impl rustc_typeck::check::FnCtxt>::check_return_expr
  62: rustc_typeck::check::check_fn
  63: rustc::ty::context::GlobalCtxt::enter_local
  64: rustc_typeck::check::typeck_tables_of
  65: rustc::ty::query::__query_compute::typeck_tables_of
  66: rustc::ty::query::<impl rustc::ty::query::config::QueryAccessors for rustc::ty::query::queries::typeck_tables_of>::compute
  67: rustc::dep_graph::graph::DepGraph::with_task_impl
  68: rustc::ty::query::plumbing::<impl rustc::ty::context::TyCtxt>::get_query
  69: rustc::ty::<impl rustc::ty::context::TyCtxt>::par_body_owners
  70: rustc_typeck::check::typeck_item_bodies
  71: rustc::ty::query::__query_compute::typeck_item_bodies
  72: rustc::dep_graph::graph::DepGraph::with_task_impl
  73: rustc::ty::query::plumbing::<impl rustc::ty::context::TyCtxt>::get_query
  74: rustc::util::common::time
  75: rustc_typeck::check_crate
  76: rustc_interface::passes::analysis
  77: rustc::ty::query::__query_compute::analysis
  78: rustc::ty::query::plumbing::<impl rustc::ty::context::TyCtxt>::get_query
  79: rustc_interface::passes::BoxedGlobalCtxt::access::{{closure}}
  80: rustc_interface::passes::create_global_ctxt::{{closure}}
  81: rustc_interface::interface::run_compiler_in_existing_thread_pool
  82: std::thread::local::LocalKey<T>::with
  83: scoped_tls::ScopedKey<T>::set
  84: syntax::with_globals
1.40 nightly
stack backtrace:
   0: backtrace::backtrace::libunwind::trace
             at /cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.40/src/backtrace/libunwind.rs:88
   1: backtrace::backtrace::trace_unsynchronized
             at /cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.40/src/backtrace/mod.rs:66
   2: std::sys_common::backtrace::_print_fmt
             at src/libstd/sys_common/backtrace.rs:77
   3: <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt
             at src/libstd/sys_common/backtrace.rs:61
   4: core::fmt::write
             at src/libcore/fmt/mod.rs:1028
   5: std::io::Write::write_fmt
             at src/libstd/io/mod.rs:1412
   6: std::sys_common::backtrace::_print
             at src/libstd/sys_common/backtrace.rs:65
   7: std::sys_common::backtrace::print
             at src/libstd/sys_common/backtrace.rs:50
   8: std::panicking::default_hook::{{closure}}
             at src/libstd/panicking.rs:188
   9: std::panicking::default_hook
             at src/libstd/panicking.rs:205
  10: rustc_driver::report_ice
  11: <alloc::boxed::Box<F> as core::ops::function::Fn<A>>::call
             at /rustc/1423bec54cf2db283b614e527cfd602b481485d1/src/liballoc/boxed.rs:956
  12: proc_macro::bridge::client::<impl proc_macro::bridge::Bridge>::enter::{{closure}}::{{closure}}
             at /rustc/1423bec54cf2db283b614e527cfd602b481485d1/src/libproc_macro/bridge/client.rs:305
  13: std::panicking::rust_panic_with_hook
             at src/libstd/panicking.rs:468
  14: std::panicking::continue_panic_fmt
             at src/libstd/panicking.rs:373
  15: rust_begin_unwind
             at src/libstd/panicking.rs:302
  16: core::panicking::panic_fmt
             at src/libcore/panicking.rs:139
  17: core::result::unwrap_failed
             at src/libcore/result.rs:1165
  18: rustc_typeck::check::Inherited::register_predicate
  19: rustc_typeck::check::Inherited::register_predicates
  20: <rustc_typeck::check::FnCtxt as rustc_typeck::astconv::AstConv>::normalize_ty
  21: <dyn rustc_typeck::astconv::AstConv>::res_to_ty
  22: <dyn rustc_typeck::astconv::AstConv>::ast_ty_to_ty
  23: rustc_typeck::check::FnCtxt::check_argument_types
  24: rustc_typeck::check::callee::<impl rustc_typeck::check::FnCtxt>::confirm_builtin_call
  25: rustc_typeck::check::callee::<impl rustc_typeck::check::FnCtxt>::check_call
  26: rustc_typeck::check::expr::<impl rustc_typeck::check::FnCtxt>::check_expr_kind
  27: rustc_typeck::check::expr::<impl rustc_typeck::check::FnCtxt>::check_expr_with_expectation_and_needs
  28: rustc_typeck::check::FnCtxt::check_decl_initializer
  29: rustc_typeck::check::FnCtxt::check_decl_local
  30: rustc_typeck::check::FnCtxt::check_stmt
  31: rustc_typeck::check::FnCtxt::check_block_with_expected
  32: rustc_typeck::check::expr::<impl rustc_typeck::check::FnCtxt>::check_expr_kind
  33: rustc_typeck::check::expr::<impl rustc_typeck::check::FnCtxt>::check_expr_with_expectation_and_needs
  34: rustc_typeck::check::expr::<impl rustc_typeck::check::FnCtxt>::check_return_expr
  35: rustc_typeck::check::check_fn
  36: rustc_typeck::check::closure::<impl rustc_typeck::check::FnCtxt>::check_expr_closure
  37: rustc_typeck::check::expr::<impl rustc_typeck::check::FnCtxt>::check_expr_kind
  38: rustc_typeck::check::expr::<impl rustc_typeck::check::FnCtxt>::check_expr_with_expectation_and_needs
  39: rustc_typeck::check::FnCtxt::check_argument_types
  40: rustc_typeck::check::FnCtxt::check_method_argument_types
  41: rustc_typeck::check::expr::<impl rustc_typeck::check::FnCtxt>::check_expr_kind
  42: rustc_typeck::check::expr::<impl rustc_typeck::check::FnCtxt>::check_expr_with_expectation_and_needs
  43: rustc_typeck::check::expr::<impl rustc_typeck::check::FnCtxt>::check_expr_kind
  44: rustc_typeck::check::expr::<impl rustc_typeck::check::FnCtxt>::check_expr_with_expectation_and_needs
  45: rustc_typeck::check::FnCtxt::check_decl_initializer
  46: rustc_typeck::check::FnCtxt::check_decl_local
  47: rustc_typeck::check::FnCtxt::check_stmt
  48: rustc_typeck::check::FnCtxt::check_block_with_expected
  49: rustc_typeck::check::expr::<impl rustc_typeck::check::FnCtxt>::check_expr_kind
  50: rustc_typeck::check::expr::<impl rustc_typeck::check::FnCtxt>::check_expr_with_expectation_and_needs
  51: rustc_typeck::check::_match::<impl rustc_typeck::check::FnCtxt>::check_match
  52: rustc_typeck::check::expr::<impl rustc_typeck::check::FnCtxt>::check_expr_kind
  53: rustc_typeck::check::expr::<impl rustc_typeck::check::FnCtxt>::check_expr_with_expectation_and_needs
  54: rustc_typeck::check::FnCtxt::check_block_with_expected
  55: rustc_typeck::check::expr::<impl rustc_typeck::check::FnCtxt>::check_expr_kind
  56: rustc_typeck::check::expr::<impl rustc_typeck::check::FnCtxt>::check_expr_with_expectation_and_needs
  57: rustc_typeck::check::_match::<impl rustc_typeck::check::FnCtxt>::check_match
  58: rustc_typeck::check::expr::<impl rustc_typeck::check::FnCtxt>::check_expr_kind
  59: rustc_typeck::check::expr::<impl rustc_typeck::check::FnCtxt>::check_expr_with_expectation_and_needs
  60: rustc_typeck::check::FnCtxt::check_block_with_expected
  61: rustc_typeck::check::expr::<impl rustc_typeck::check::FnCtxt>::check_expr_kind
  62: rustc_typeck::check::expr::<impl rustc_typeck::check::FnCtxt>::check_expr_with_expectation_and_needs
  63: rustc_typeck::check::expr::<impl rustc_typeck::check::FnCtxt>::check_return_expr
  64: rustc_typeck::check::check_fn
  65: rustc::ty::context::tls::with_context::{{closure}}
  66: rustc_typeck::check::typeck_tables_of
  67: rustc::ty::query::__query_compute::typeck_tables_of
  68: rustc::ty::query::<impl rustc::ty::query::config::QueryAccessors for rustc::ty::query::queries::typeck_tables_of>::compute
  69: rustc::dep_graph::graph::DepGraph::with_task_impl
  70: rustc::ty::query::plumbing::<impl rustc::ty::context::TyCtxt>::get_query
  71: rustc::ty::<impl rustc::ty::context::TyCtxt>::par_body_owners
  72: rustc_typeck::check::typeck_item_bodies
  73: rustc::ty::query::__query_compute::typeck_item_bodies
  74: rustc::dep_graph::graph::DepGraph::with_task_impl
  75: rustc::ty::query::plumbing::<impl rustc::ty::context::TyCtxt>::get_query
  76: rustc::util::common::time
  77: rustc_typeck::check_crate
  78: rustc_interface::passes::analysis
  79: rustc::ty::query::__query_compute::analysis
  80: rustc::dep_graph::graph::DepGraph::with_task_impl
  81: rustc::ty::query::plumbing::<impl rustc::ty::context::TyCtxt>::get_query
  82: rustc_interface::passes::BoxedGlobalCtxt::access::{{closure}}
  83: rustc_interface::passes::create_global_ctxt::{{closure}}
  84: rustc_interface::passes::BoxedGlobalCtxt::enter
  85: rustc_interface::interface::run_compiler_in_existing_thread_pool
  86: std::thread::local::LocalKey<T>::with
  87: scoped_tls::ScopedKey<T>::set
  88: syntax::with_globals

Investigation:

Steps to reproduce:

  1. Download ICE-borrow-mut.zip
  2. Extract and run cargo build

Relevant source file:

# from project root, lines 168 onwards of
crate/game_mode_selection_ui/src/system/game_mode_selection_widget_ui_system.rs

Interestingly, using .copied() on the position_inits iterator on the ICE-ing code allows it to compile:

.zip(position_inits.iter().copied())

Also interestingly, using the position_inits.get(order) version within .map(..) without .copied() also causes the ICE, so it's not the zipping that's causing it, but rather something to do with the position_init being a reference rather than an owned value.

Metadata

Metadata

Labels

A-type-systemArea: Type systemC-bugCategory: This is a bug.E-needs-bisectionCall for participation: This issue needs bisection: https://github.com/rust-lang/cargo-bisect-rustcI-ICEIssue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️P-highHigh priorityT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.regression-from-stable-to-stablePerformance or correctness regression from one stable version to another.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions