Skip to content

ICE with move FnOnce unboxed closure #18652

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
cristicbz opened this issue Nov 5, 2014 · 2 comments · Fixed by #18730
Closed

ICE with move FnOnce unboxed closure #18652

cristicbz opened this issue Nov 5, 2014 · 2 comments · Fixed by #18730
Labels
A-closures Area: Closures (`|…| { … }`)

Comments

@cristicbz
Copy link
Contributor

#![feature(unboxed_closures)]

struct Foo;
impl Foo {
    fn bar(&self, _x: uint) {}
}

fn main() {
    let foo = Foo;
    let y = 0u;
    move |:| {
        foo.bar(y);
    };
}

Gives:

error: internal compiler error: unexpected panic
note: the compiler unexpectedly panicked. this is a bug.
note: we would appreciate a bug report: http://doc.rust-lang.org/complement-bugreport.html
note: run with `RUST_BACKTRACE=1` for a backtrace
task 'rustc' panicked at 'assertion failed: freevars.len() <= 1', /build/rust-git/src/rust/src/librustc/middle/trans/closure.rs:325

Rust playpen

Foo.bar can take &self or &mut self instead and the ICE still happens. The following things stop the ICE from happening:

  • Moving foo or y inside the closure.
  • Removing foo (capturing only y).
  • Removing y (capturing only foo)
  • Making the closure non-move, |&:| or |& mut:|.

Only have access to the playpen right now, so I can't get a backtrace, sorry.

@huonw huonw added the A-closures Area: Closures (`|…| { … }`) label Nov 5, 2014
@cristicbz cristicbz mentioned this issue Nov 5, 2014
47 tasks
@abonander
Copy link
Contributor

$ rustc issue_18652.rs 
error: internal compiler error: unexpected panic
note: the compiler unexpectedly panicked. this is a bug.
note: we would appreciate a bug report: http://doc.rust-lang.org/complement-bugreport.html
note: run with `RUST_BACKTRACE=1` for a backtrace
task 'rustc' panicked at 'assertion failed: freevars.len() <= 1', /home/rustbuild/src/rust-buildbot/slave/nightly-linux/build/src/librustc/middle/trans/closure.rs:325

stack backtrace:
   1:     0x7f9ccb3cd8e0 - rt::backtrace::imp::write::h90851ece7c054d3bTVp
   2:     0x7f9ccb3d0960 - failure::on_fail::hc015761685342dd1vhq
   3:     0x7f9ccbb7fa20 - unwind::begin_unwind_inner::hf5743de3e545b8bbZSd
   4:     0x7f9ccbf59820 - unwind::begin_unwind::h12836636821598676233
   5:     0x7f9ccc3bec60 - middle::trans::closure::trans_unboxed_closure::closure.127438
   6:     0x7f9ccc3907f0 - middle::trans::base::trans_closure::h0ee0e830d5f57196BNh
   7:     0x7f9ccc33e380 - middle::trans::closure::trans_unboxed_closure::h10dd08b60eae5c99h9l
   8:     0x7f9ccc329860 - middle::trans::expr::trans_rvalue_dps_unadjusted::hbba4faa267b036ffeM6
   9:     0x7f9ccc2ef050 - middle::trans::expr::trans_into::haccb966391cea9aedn5
  10:     0x7f9ccc2ee4b0 - middle::trans::controlflow::trans_stmt_semi::h4d0d2d7f5be74d97ZC1
  11:     0x7f9ccc2eda60 - middle::trans::controlflow::trans_stmt::h6a80ddbefaced6ffMy1
  12:     0x7f9ccc2ef470 - middle::trans::controlflow::trans_block::h76660195897ae193SD1
  13:     0x7f9ccc3907f0 - middle::trans::base::trans_closure::h0ee0e830d5f57196BNh
  14:     0x7f9ccc2e2530 - middle::trans::base::trans_fn::h9de5c2dcb3f96df5wZh
  15:     0x7f9ccc2dfc20 - middle::trans::base::trans_item::h5f88c04c36ef66aaKii
  16:     0x7f9ccc39b160 - middle::trans::base::trans_crate::heef2f92cab82a2c9Lgj
  17:     0x7f9ccc818b30 - driver::driver::phase_4_translate_to_llvm::h424d161d8e05b6883UB
  18:     0x7f9ccc80f320 - driver::driver::compile_input::h0cb1ebcd11f34cd6XrB
  19:     0x7f9ccc893a60 - driver::run_compiler::h92ab17fc93f0a323giF
  20:     0x7f9ccc893950 - driver::run::closure.146866
  21:     0x7f9ccbf915f0 - task::TaskBuilder<S>::try_future::closure.104323
  22:     0x7f9ccbf913e0 - task::TaskBuilder<S>::spawn_internal::closure.104294
  23:     0x7f9ccd121b90 - task::NativeSpawner.Spawner::spawn::closure.8440
  24:     0x7f9ccbbd5510 - rust_try_inner
  25:     0x7f9ccbbd5500 - rust_try
  26:     0x7f9ccbb7d370 - unwind::try::h9b7bcf92a04d9d42jHd
  27:     0x7f9ccbb7d200 - task::Task::run::h74a092677bc826a59Mc
  28:     0x7f9ccd1218d0 - task::NativeSpawner.Spawner::spawn::closure.8378
  29:     0x7f9ccbb7ea10 - thread::thread_start::h7ebb3af704f6e202o8c
  30:     0x7f9ccae9e0c0 - start_thread
  31:     0x7f9ccb848f89 - __clone
  32:                0x0 - <unknown>

@bkoropoff
Copy link
Contributor

We take the branch in question as an optimization when the closure is less than or equal to the size of an int:

            llsize_of_alloc(ccx, llty) <= llsize_of_alloc(ccx, ccx.int_type())

The assert seems to assume that this can only happen if the closure has 1 or 0 free variables, but it's trivial to have several smaller variables packed into the space of an int. The following also ICEs in the same way:

#![feature(unboxed_closures)]

fn main() {
    let x = 0u16;
    let y = 0u16;
    move |:| x + y;
}

In the original example, Foo is zero-sized so the overall closure fits in an int.

bkoropoff added a commit to bkoropoff/rust that referenced this issue Nov 7, 2014
As an optimization, once unboxed closures receive their environment by
value if it fits within the size of an `int`.  An assert in this code
path assumed that this would only occur if the environment had no more
than a single free variable in it, but multiple smaller free variables
can easily be packed into the space of an `int`, particularly if any
of them are 0-sized.  The assert can simply be removed.

Closes rust-lang#18652
bkoropoff added a commit to bkoropoff/rust that referenced this issue Nov 7, 2014
bors added a commit that referenced this issue Nov 8, 2014
`FnOnce` environments that fit within an `int` are passed to the closure by value.  For some reason there was an assert that this would only happen if there were 1 or 0 free variables, but it can also happen if there are multiple variables that happen to fit.

Closes #18652
lnicola pushed a commit to lnicola/rust that referenced this issue Dec 16, 2024
feat: Add an assist to extract an expression into a constant
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-closures Area: Closures (`|…| { … }`)
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants