Skip to content
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

ICE when trying to use dyn Fn(...) -> UnsizedTy #58355

Closed
viftodi opened this issue Feb 10, 2019 · 16 comments · Fixed by #106494
Closed

ICE when trying to use dyn Fn(...) -> UnsizedTy #58355

viftodi opened this issue Feb 10, 2019 · 16 comments · Fixed by #106494
Labels
A-codegen Area: Code generation A-type-system Area: Type system C-bug Category: This is a bug. E-needs-test Call for participation: An issue has been fixed and does not reproduce, but no test has been added. glacier ICE tracked in rust-lang/glacier. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@viftodi
Copy link

viftodi commented Feb 10, 2019

Hello,

I am trying to implement this trait:

pub trait JsSerializable {
    fn size(&self) -> u32;
    fn ser(&self, cursor: &mut Cursor<Vec<u8>>) -> ();
}

impl JsSerializable for &'static Fn() -> (JsSerializable) 

I get a compiler panic

thread 'main' panicked at 'assertion failed: !layout.is_unsized()', src\librustc_codegen_ssa\mir\place.rs:45:9
stack backtrace:
   0: std::sys_common::alloc::realloc_fallback
   1: std::panicking::take_hook
   2: std::panicking::take_hook
   3: <rustc::ty::sty::Binder<rustc::ty::ProjectionPredicate<'tcx>> as rustc::ty::ToPredicate<'tcx>>::to_predicate
   4: std::panicking::rust_panic_with_hook
   5: <rustc_codegen_llvm::llvm_::archive_ro::Iter<'a> as core::ops::drop::Drop>::drop
   6: <rustc_codegen_llvm::llvm_::ffi::debuginfo::DIFlags as core::fmt::UpperHex>::fmt
   7: <rustc_codegen_llvm::llvm_::ffi::debuginfo::DIFlags as core::fmt::UpperHex>::fmt
   8: <rustc_codegen_llvm::back::lto::ThinLTOImports as core::fmt::Debug>::fmt
   9: <rustc_codegen_llvm::base::ValueIter<'ll> as core::iter::iterator::Iterator>::next
  10: <rustc_codegen_llvm::LlvmCodegenBackend as rustc_codegen_utils::codegen_backend::CodegenBackend>::join_codegen_and_link
  11: <rustc_codegen_llvm::base::ValueIter<'ll> as core::iter::iterator::Iterator>::next
  12: <rustc_codegen_llvm::back::lto::ThinLTOImports as core::fmt::Debug>::fmt
  13: <rustc_codegen_llvm::LlvmCodegenBackend as rustc_codegen_utils::codegen_backend::CodegenBackend>::codegen_crate
  14: <rustc_driver::pretty::UserIdentifiedItem as core::fmt::Debug>::fmt
  15: rustc_driver::driver::phase_4_codegen
  16: <rustc_driver::pretty::UserIdentifiedItem as core::fmt::Debug>::fmt
  17: <rustc_driver::pretty::UserIdentifiedItem as core::fmt::Debug>::fmt
  18: <rustc_driver::pretty::UserIdentifiedItem as core::fmt::Debug>::fmt
  19: <rustc_driver::pretty::UserIdentifiedItem as core::fmt::Debug>::fmt
  20: rustc_driver::driver::compile_input
  21: rustc_driver::run_compiler
  22: <rustc_driver::profile::trace::Query as core::fmt::Debug>::fmt
  23: rustc_driver::run_compiler
  24: <humantime::duration::Error as std::error::Error>::cause
  25: _rust_maybe_catch_panic
  26: rustc_driver::profile::dump
  27: rustc_driver::main
  28: <unknown>
  29: std::panicking::update_panic_count
  30: _rust_maybe_catch_panic
  31: std::rt::lang_start_internal
  32: <unknown>
  33: <unknown>
  34: BaseThreadInitThunk
  35: RtlUserThreadStart
query stack during panic:
end of query stack

error: internal compiler error: unexpected panic

I try to compile it for target=wasm32-unknown-unknown

note: rustc 1.32.0 (9fda7c2 2019-01-16) running on x86_64-pc-windows-msvc

note: compiler flags: -C debuginfo=2 -C incremental --crate-type lib

@jonas-schievink
Copy link
Contributor

Can you provide a self-contained example that reproduces the ICE?

@jonas-schievink jonas-schievink added I-ICE Issue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️ T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. C-bug Category: This is a bug. labels Feb 10, 2019
@viftodi
Copy link
Author

viftodi commented Feb 10, 2019

Hello,

This is the shortest example I could create:
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=69c305c9deff95a201e750cf280f6635

If you just build this you should get the error.
It looks like it works? when not in lib mode, not sure

@hellow554
Copy link
Contributor

Even shorter:

use std::cell::RefCell;

thread_local! {
    static TL: RefCell<Option<Box<dyn Fn() -> ToString>>> = RefCell::new(None);
}

pub fn crash(callback: &'static Fn() -> ToString) {
    TL.with(|cc| {
        *cc.borrow_mut() = Some(Box::new(callback));
    });
}

@hellow554
Copy link
Contributor

hellow554 commented Feb 11, 2019

Bug was introduced between 1.23 and 1.24 (766bd11...4d90ac3)
Between 2017-11-20 and 2017-11-21 (5041b3b...33374fa)

@hellow554
Copy link
Contributor

cc @eddyb based on your commits that day ^^

@eddyb
Copy link
Member

eddyb commented Feb 13, 2019

That example should not type-check, you're assigning a Box<&T> where a Box<T> is expected.

cc @rust-lang/compiler

@estebank
Copy link
Contributor

estebank commented Feb 13, 2019

Using the minimized repro, we have an stable ICE of some sort since 1.27, before then it was rejected due to dyn Trait syntax being unstable:

  • 1.27
thread 'main' panicked at 'attempt to divide by zero', librustc_trans/abi.rs:130:26
  • 1.28
thread 'main' panicked at 'unsupported integer: Reg { kind: Integer, size: Size { raw: 0 } }', librustc_target/abi/call/mod.rs:147:26
  • 1.30
thread 'main' panicked at 'assertion failed: !layout.is_unsized()', librustc_codegen_llvm/mir/place.rs:50:9
  • 1.32
thread 'main' panicked at 'assertion failed: !layout.is_unsized()', src/librustc_codegen_ssa/mir/place.rs:45:9

@eddyb
Copy link
Member

eddyb commented Feb 13, 2019

@estebank You can just remove the dyn keyword, it really shouldn't matter.

Btw, the minimized repro can be minimized further by removing the (rather heavy) thread_local!:

use std::cell::RefCell;

pub fn foo(callback: &'static Fn() -> ToString) {
    let x: RefCell<Option<Box<Fn() -> ToString>>> = RefCell::new(None);
    *x.borrow_mut() = Some(Box::new(callback));
}

And we can also get rid of RefCell:

pub fn foo(callback: &'static Fn() -> ToString) {
    let mut x: Option<Box<Fn() -> ToString>> = None;
    x = Some(Box::new(callback));
}

Fn() -> ToString is dyn Fn<(), Output = dyn ToString>, none of this can work.

So the real question is how does this ICE before emitting a type-checking error?

@eddyb
Copy link
Member

eddyb commented Feb 13, 2019

Okay, so there are two parts to this:

  • the Output associated type of FnOnce doesn't require Sized
  • &dyn Fn() implements the Fn() trait, so Box<&dyn Fn()> can be unsized to Box<Fn()>

So this has a reason to type-check, despite being very confusing.

We can make this simpler by using fn pointers:

pub fn foo(callback: fn() -> ToString) {
    let mut x: Option<Box<Fn() -> ToString>> = None;
    x = Some(Box::new(callback));
}

This way, we have fn() -> T: Fn() -> T, so Box<fn() -> T> can be unsized to Box<Fn() -> T>.

But it's impossible for the return type of a function, even with unsized rvalues, to be !Sized (i.e. we have no mechanism for supporting that), and here I think at the very least the vtable of fn() -> T: Fn() -> T has to have a Fn::call shim that would need to return a !Sized return type (T, i.e. ToString in the original repro), so we ICE.

If we don't want to enforce that return types are Sized in fn pointers or trait objects methods, this case will continue ICE-ing.

@eddyb
Copy link
Member

eddyb commented Feb 13, 2019

The original problem is clearer if we add the dyn keyword:

pub trait JsSerializable {
    fn size(&self) -> u32;
    fn ser(&self, cursor: &mut Cursor<Vec>);
}

impl JsSerializable for &'static dyn Fn() -> dyn JsSerializable {...}

@viftodi You can fix your code by putting a Box<...> around the return type of this Fn(), or figure out some other way to do it.

If you want to make sure you find such problems, try to write function that is has implements the right traits, e.g. fn foo() -> dyn JsSerializable {...}.
That will error because the return type of a function with a body must be Sized.

@estebank
Copy link
Contributor

If we don't want to enforce that return types are Sized in fn pointers or trait objects methods, this case will continue ICE-ing.

What alternative do we have?

@viftodi
Copy link
Author

viftodi commented Feb 14, 2019

@viftodi You can fix your code by putting a Box<...> around the return type of this Fn(), or figure out some other way to do it.

Thank you @eddyb , I will look into an alternative

@Centril Centril added A-codegen Area: Code generation A-type-system Area: Type system labels Mar 10, 2020
@Centril
Copy link
Contributor

Centril commented Mar 10, 2020

Reproduces (#58355 (comment)) as of 2020-03-10.

@rust-lang-glacier-bot rust-lang-glacier-bot added the glacier ICE tracked in rust-lang/glacier. label Mar 18, 2020
@matthiaskrgr
Copy link
Member

@rustbot modify labels: +regression-from-stable-to-stable

Still reproduces with stable/beta/nightly

stable-x86_64-unknown-linux-gnu - 1.48.0 (7eac88abb 2020-11-16)
beta-x86_64-unknown-linux-gnu - 1.49.0-beta.4 (877c7cbe1 2020-12-10)
nightly-x86_64-unknown-linux-gnu - 1.50.0-nightly (1f5bc176b 2020-12-19)

@rustbot rustbot added regression-from-stable-to-stable Performance or correctness regression from one stable version to another. I-prioritize Issue: Indicates that prioritization has been requested for this issue. labels Dec 20, 2020
@LeSeulArtichaut LeSeulArtichaut added P-medium Medium priority and removed I-prioritize Issue: Indicates that prioritization has been requested for this issue. labels Dec 20, 2020
@LeSeulArtichaut
Copy link
Contributor

@lcnr lcnr changed the title Compiler panic when implementing recursive trait for dyn Fn ? ICE when trying to use dyn Fn(...) -> UnsizedTy Dec 20, 2020
@JohnTitor
Copy link
Member

The latest nightly fixes the ICE, marking as E-needs-test.

@JohnTitor JohnTitor added the E-needs-test Call for participation: An issue has been fixed and does not reproduce, but no test has been added. label Sep 22, 2022
@estebank estebank removed the I-ICE Issue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️ label Sep 22, 2022
@estebank estebank removed P-medium Medium priority regression-from-stable-to-stable Performance or correctness regression from one stable version to another. labels Sep 22, 2022
JohnTitor added a commit to JohnTitor/rust that referenced this issue Jan 5, 2023
Signed-off-by: Yuki Okushi <jtitor@2k36.org>
bors added a commit to rust-lang-ci/rust that referenced this issue Jan 6, 2023
Rollup of 5 pull requests

Successful merges:

 - rust-lang#106400 (Point at expressions where inference refines an unexpected type)
 - rust-lang#106491 (Fix error-index redirect to work with the back button.)
 - rust-lang#106494 (Add regression test for rust-lang#58355)
 - rust-lang#106499 (fix [type error] for error E0029 and E0277)
 - rust-lang#106502 (rustdoc: remove legacy user-select CSS)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
@bors bors closed this as completed in 4b094c5 Jan 6, 2023
@fmease fmease added A-type-system Area: Type system and removed A-type-system Area: Type system labels Dec 21, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-codegen Area: Code generation A-type-system Area: Type system C-bug Category: This is a bug. E-needs-test Call for participation: An issue has been fixed and does not reproduce, but no test has been added. glacier ICE tracked in rust-lang/glacier. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging a pull request may close this issue.