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: OutputTypeParameterMismatch error under -Clink-dead-code #86703

Closed
Manishearth opened this issue Jun 28, 2021 · 26 comments
Closed

ICE: OutputTypeParameterMismatch error under -Clink-dead-code #86703

Manishearth opened this issue Jun 28, 2021 · 26 comments
Labels
C-bug Category: This is a bug. glacier ICE tracked in rust-lang/glacier. 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.

Comments

@Manishearth
Copy link
Member

Manishearth commented Jun 28, 2021

Code

Must be compiled with -C link-dead-code

Minimized test
use std::rc::Rc;
use std::borrow::{Cow, ToOwned};
use std::{mem, ptr};


pub unsafe trait Yokeable<'a>: 'static {
    type Output: 'a;
}

pub struct Yoke<Y: for<'a> Yokeable<'a>, C> {
    // must be the first field for drop order
    // this will have a 'static lifetime parameter, that parameter is a lie
    yokeable: Y,
    cart: C,
}


impl<Y: for<'a> Yokeable<'a>> Yoke<Y, Rc<[u8]>> {
    pub fn project<'this, P>(
        &'this self,
        f: for<'a> fn(&'this <Y as Yokeable<'a>>::Output, &'a ()) -> <P as Yokeable<'a>>::Output,
    ) -> Yoke<P, Rc<[u8]>>
    where
        P: for<'a> Yokeable<'a>,
    {
        unimplemented!()
    }
}

pub fn slice(y: Yoke<&'static str, Rc<[u8]>>) -> Yoke<&'static [u8], Rc<[u8]>> {
    y.project(move |yk, _| yk.as_bytes())
}


unsafe impl<'a, T: 'static + ToOwned + ?Sized> Yokeable<'a> for Cow<'static, T>
where
    <T as ToOwned>::Owned: Sized,
{
    type Output = Cow<'a, T>;

}

unsafe impl<'a, T: 'static + ?Sized> Yokeable<'a> for &'static T {
    type Output = &'a T;
}
Nonminimized original failure

For the nonminimized example, the tests under https://github.com/Manishearth/icu4x/blob/yoke-ice/utils/yoke/src/yoke.rs#L474-L551 fail when run under -Clink-dead-code

Steps:

Adding code that makes use of the functions defined in these tests does not change anything, e.g. the function in the first test is not being called, but if you add code that calls it like below, the ICE still happens. I'm not sure as to what role -Clink-dead-code has here.

let rc: Rc<[u8]> = Rc::from("hello".as_bytes());
let yoke: Yoke<&'static str, Rc<[u8]>> = Yoke::attach_to_cart_badly(rc, |rc| std::str::from_utf8(&rc).unwrap());

Meta

rustc --version --verbose:

rustc 1.55.0-nightly (e8cb1a4a5 2021-06-27)
binary: rustc
commit-hash: e8cb1a4a567ce88e459ffd431207eff2e0f0ffa5
commit-date: 2021-06-27
host: x86_64-unknown-linux-gnu
release: 1.55.0-nightly
LLVM version: 12.0.1

Error output

---- src/yoke.rs - yoke::Yoke<Y, C>::project (line 500) stdout ----
error: internal compiler error: compiler/rustc_trait_selection/src/traits/codegen.rs:78:17: Encountered error `OutputTypeParameterMismatch(Binder(<[closure@src/yoke.rs:16:17: 16:38] as std::ops::FnMut<(&<main::_doctest_main_src_yoke_rs_500_0::Bar as yoke::Yokeable<'_>>::Output, &())>>, [Region(BrAnon(0))]), Binder(<[closure@src/yoke.rs:16:17: 16:38] as std::ops::FnMut<(&main::_doctest_main_src_yoke_rs_500_0::Bar, &())>>, []), Sorts(ExpectedFound { expected: main::_doctest_main_src_yoke_rs_500_0::Bar, found: <main::_doctest_main_src_yoke_rs_500_0::Bar as yoke::Yokeable<'_>>::Output }))` selecting `Binder(<[closure@src/yoke.rs:16:17: 16:38] as std::ops::FnMut<(&main::_doctest_main_src_yoke_rs_500_0::Bar, &())>>, [])` during codegen

thread 'rustc' panicked at 'Box<dyn Any>', compiler/rustc_errors/src/lib.rs:1007:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

note: 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: rustc 1.55.0-nightly (e8cb1a4a5 2021-06-27) running on x86_64-unknown-linux-gnu

note: compiler flags: -C codegen-units=1 -C embed-bitcode=no -C link-dead-code --crate-type bin

query stack during panic:
#0 [codegen_fulfill_obligation] checking if `std::ops::FnMut` fulfills its obligations
#1 [resolve_instance] resolving instance `<[closure@src/yoke.rs:16:17: 16:38] as std::ops::FnMut<(&main::_doctest_main_src_yoke_rs_500_0::Bar, &())>>::call_mut`
end of query stack
error: aborting due to previous error


Backtrace

stack backtrace:
   0: std::panicking::begin_panic
   1: std::panic::panic_any
   2: rustc_errors::HandlerInner::bug
   3: rustc_errors::Handler::bug
   4: rustc_middle::ty::context::tls::with_opt
   5: rustc_middle::util::bug::opt_span_bug_fmt
   6: rustc_middle::util::bug::bug_fmt
   7: rustc_infer::infer::InferCtxtBuilder::enter
   8: rustc_trait_selection::traits::codegen::codegen_fulfill_obligation
   9: rustc_query_system::query::plumbing::get_query_impl
  10: <rustc_query_impl::Queries as rustc_middle::ty::query::QueryEngine>::codegen_fulfill_obligation
  11: rustc_ty_utils::instance::inner_resolve_instance
  12: rustc_ty_utils::instance::resolve_instance
  13: rustc_query_system::query::plumbing::get_query_impl
  14: <rustc_query_impl::Queries as rustc_middle::ty::query::QueryEngine>::resolve_instance
  15: rustc_middle::ty::instance::Instance::resolve_opt_const_arg
  16: rustc_middle::ty::instance::Instance::resolve
  17: <rustc_mir::monomorphize::collector::MirNeighborCollector as rustc_middle::mir::visit::Visitor>::visit_terminator
  18: rustc_mir::monomorphize::collector::collect_neighbours
  19: rustc_mir::monomorphize::collector::collect_items_rec
  20: rustc_mir::monomorphize::collector::collect_items_rec
  21: rustc_session::utils::<impl rustc_session::session::Session>::time
  22: rustc_mir::monomorphize::collector::collect_crate_mono_items
  23: rustc_mir::monomorphize::partitioning::collect_and_partition_mono_items
  24: rustc_query_system::query::plumbing::get_query_impl
  25: <rustc_query_impl::Queries as rustc_middle::ty::query::QueryEngine>::collect_and_partition_mono_items
  26: <rustc_codegen_llvm::LlvmCodegenBackend as rustc_codegen_ssa::traits::backend::CodegenBackend>::codegen_crate
  27: rustc_interface::passes::QueryContext::enter
  28: rustc_interface::queries::Queries::ongoing_codegen
  29: rustc_interface::queries::<impl rustc_interface::interface::Compiler>::enter
  30: rustc_span::with_source_map
  31: rustc_interface::interface::create_compiler_and_run
  32: scoped_tls::ScopedKey<T>::set

@Manishearth Manishearth 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 Jun 28, 2021
@Manishearth Manishearth changed the title OutputTypeParameterMismatch error under -Clink-dead-code ICE: OutputTypeParameterMismatch error under -Clink-dead-code Jun 28, 2021
@Manishearth
Copy link
Member Author

This may be related to #86702

@Manishearth
Copy link
Member Author

Manishearth commented Jun 28, 2021

The weird thing is that even if I make sure all of the functions are used, I still do not get the error without -C link-dead-code, and still get the error with -C link-dead-code

I cannot get this ICE to occur without -C link-dead-code

@Manishearth
Copy link
Member Author

Jonas says this might be #62529

@Manishearth
Copy link
Member Author

The ICE here is fixed by #85499, however it gets replaced with the following (incorrect) error:

error: implementation of `Yokeable` is not general enough
  --> foo.rs:31:7
   |
31 |     y.project(move |yk, _| yk.as_bytes())
   |       ^^^^^^^ implementation of `Yokeable` is not general enough
   |
   = note: `&[u8]` must implement `Yokeable<'0>`, for any lifetime `'0`...
   = note: ...but `Yokeable<'_>` is actually implemented for the type `&'static [u8]`

@hellow554
Copy link
Contributor

hellow554 commented Jun 29, 2021

Reduced to this:

trait Yokeable<'a> {
    type Output: 'a;
}

fn project(_: for<'a> fn(<() as Yokeable<'a>>::Output)) {}

impl<'a> Yokeable<'a> for () {
    type Output = ();
}

fn main() {
    project(|_| {});
}

looks related at least

@lqd
Copy link
Member

lqd commented Jun 29, 2021

The subtlety with reducing this is that it quickly falls into an actual duplicate of #62529, losing what made it slightly different under #85499. That PR will successfully compile this reduction, but not the OP.

@hellow554
Copy link
Contributor

@lqd you're right. Here's what needs to be done, to be able to trigger the ICE with -C link-dead-code again:

fn crash() {
    project(|_| {});
}

fn main() {}

which seems plausible, because that's what link-dead-code is supposed to do, right?
Is that enough or am I missing something?

@lqd
Copy link
Member

lqd commented Jun 29, 2021

I guess it depends on your reduction goals :)

If you want the minimal ICE regardless of the intent of the OP, that's valuable for tests and debugging.

Equally valuable, we could reduce to try to understand why the OP doesn't compile, even without the ICE: there could be

This would likely require reducing using the CI artifacts of that PR.

@jackh726
Copy link
Member

jackh726 commented Jul 1, 2021

Here is a smaller reproduction of this that passes on current master but fails in #85499. It's no_core and doesn't need -C link-dead-code

// build-pass

#![feature(no_core)]

pub trait Yokeable<'a> {
    type Output: 'a;
}

pub struct Yoke<Y: for<'a> Yokeable<'a>> {
    _yokeable: Y,
}

impl<Y: for<'a> Yokeable<'a>> Yoke<Y> {
    pub fn project<'this, P>(
        &'this self,
        _f: for<'a> fn(&'this <Y as Yokeable<'a>>::Output, &'a ()) -> <P as Yokeable<'a>>::Output,
    ) -> Yoke<P>
    where
        P: for<'a> Yokeable<'a>,
    {
        unimplemented!()
    }
}

pub fn slice(y: Yoke<&'static ()>) -> Yoke<&'static ()> {
    y.project(move |yk, _| *yk)
}

impl<'a, T> Yokeable<'a> for &'static T {
    type Output = &'a T;
}

fn main() {}

@Manishearth
Copy link
Member Author

Manishearth commented Jul 1, 2021

I find the -Clink-dead-code to be an interesting part of the bug as well fwiw since i don't think we have bugs like that anywhere else in this class of ICEs.

fanninpm added a commit to fanninpm/glacier that referenced this issue Jul 4, 2021
@rust-lang-glacier-bot rust-lang-glacier-bot added the glacier ICE tracked in rust-lang/glacier. label Jul 6, 2021
@Manishearth
Copy link
Member Author

Manishearth commented Jul 23, 2021

With the latest #85499 I get the following bug on the nonminimized case.

error: internal compiler error: broken MIR in DefId(0:13 ~ rust_out[6150]::main::_doctest_main_src_yoke_rs_488_0::slice::{closure#0}) (bb0[0]): equate_normalized_input_or_output: `&[closure@src/yoke.rs:8:14: 8:40]==&[closure@src/yoke.rs:8:14: 8:40]` failed with `NoSolution`
 --> src/yoke.rs:493:14
  |
8 |    y.project(move |yk, _| yk.as_bytes())
  |              ^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: delayed at compiler/rustc_mir/src/borrow_check/type_check/mod.rs:253:27

thread 'rustc' panicked at 'no errors encountered even though `delay_span_bug` issued', compiler/rustc_errors/src/lib.rs:1050:13
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

@jackh726
Copy link
Member

@Manishearth can you run with -Z verbose?

@Manishearth
Copy link
Member Author

error: internal compiler error: broken MIR in DefId(0:27 ~ rust_out[6150]::main::_doctest_main_src_yoke_rs_500_0::project_string_1::{closure#0}) (bb0[0]): equate_normalized_input_or_output: `&'_#3r [main::_doctest_main_src_yoke_rs_500_0::project_string_1::{closure#0} closure_kind_ty=i8 closure_sig_as_fn_ptr_ty=for<'r> extern "rust-call" fn((&'_#1r main::_doctest_main_src_yoke_rs_500_0::Bar<ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('r) })>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('r) }) ())) -> &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('r) }) str upvar_tys=()]==&'_#11r [main::_doctest_main_src_yoke_rs_500_0::project_string_1::{closure#0} closure_kind_ty=i8 closure_sig_as_fn_ptr_ty=for<'r> extern "rust-call" fn((&'_#12r main::_doctest_main_src_yoke_rs_500_0::Bar<ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('r) })>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('r) }) ())) -> <&'_#13r str as yoke::Yokeable<ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('r) })>>::Output upvar_tys=()]` failed with `NoSolution`

@jackh726
Copy link
Member

Okay, so looks like my minimization in #86703 (comment) doesn't fully capture the issue (though that did fail and now doesn't).

Looking at the -Z verbose error output, it looks really similar. But I'm wondering if maybe the region variables aren't resolving the ReErased as they were.

@Manishearth do you think you can on getting a more minimized repro using #85499? Just getting it done to one file is enough for me to work with.

That being said, I'm tempted to let this slip through the PR if I can't figure out a quick and easy solution, given that this didn't come up in the crater run and this exact issue is "gated" behind an ICE right now anyways.

@lqd
Copy link
Member

lqd commented Jul 23, 2021

IIUC the minimized test in the OP ICEs similarly

@Manishearth
Copy link
Member Author

Manishearth commented Jul 23, 2021

@jackh726 The minimized tescase in my post, if you add a fn main() to it, errors with this:

error: internal compiler error: broken MIR in DefId(0:38 ~ bar[290d]::slice::{closure#0}) (bb0[0]): equate_normalized_input_or_output: `&'_#3r [slice::{closure#0} closure_kind_ty=i8 closure_sig_as_fn_ptr_ty=for<'r> extern "rust-call" fn((&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('r) }) str, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('r) }) ())) -> &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('r) }) [u8] upvar_tys=()]==&'_#11r [slice::{closure#0} closure_kind_ty=i8 closure_sig_as_fn_ptr_ty=for<'r> extern "rust-call" fn((&'_#12r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('r) }) str, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('r) }) ())) -> <&'_#13r [u8] as Yokeable<ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('r) })>>::Output upvar_tys=()]` failed with `NoSolution`
  --> bar.rs:31:15
   |
31 |     y.project(move |yk, _| yk.as_bytes())
   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: delayed at compiler/rustc_mir/src/borrow_check/type_check/mod.rs:253:27

-Clink-dead-code does not affect the error.

That being said, I'm tempted to let this slip through the PR if I can't figure out a quick and easy solution, given that this didn't come up in the crater run and this exact issue is "gated" behind an ICE right now anyways.

To be clear, this code is in a published crate, I've preemptively disabled the test because we run coverage tests and they fail under -Clink-dead-code

@jackh726
Copy link
Member

Okay, I'll look into it.

no_core version of the repro
// build-pass
// compile-flags: -Z verbose

#![feature(no_core)]
#[no_core]

pub trait Borrow<Borrowed: ?Sized> {
    fn borrow(&self) -> &Borrowed;
}

pub trait ToOwned {
    type Owned: Borrow<Self>;
    fn to_owned(&self) -> Self::Owned;
}

pub enum Cow<'a, B: ?Sized + 'a>
where
    B: ToOwned,
{
    Borrowed(&'a B),
    Owned(<B as ToOwned>::Owned),
}

pub struct Rc<T: ?Sized> {
    _t: Box<T>,
}

pub unsafe trait Yokeable<'a>: 'static {
    type Output: 'a;
}

pub struct Yoke<Y: for<'a> Yokeable<'a>, C> {
    // must be the first field for drop order
    // this will have a 'static lifetime parameter, that parameter is a lie
    yokeable: Y,
    cart: C,
}


impl<Y: for<'a> Yokeable<'a>> Yoke<Y, Rc<[u8]>> {
    pub fn project<'this, P>(
        &'this self,
        f: for<'a> fn(&'this <Y as Yokeable<'a>>::Output, &'a ()) -> <P as Yokeable<'a>>::Output,
    ) -> Yoke<P, Rc<[u8]>>
    where
        P: for<'a> Yokeable<'a>,
    {
        unimplemented!()
    }
}

pub fn slice(y: Yoke<&'static str, Rc<[u8]>>) -> Yoke<&'static [u8], Rc<[u8]>> {
    y.project(move |yk, _| yk.as_bytes())
}


unsafe impl<'a, T: 'static + ToOwned + ?Sized> Yokeable<'a> for Cow<'static, T>
where
    <T as ToOwned>::Owned: Sized,
{
    type Output = Cow<'a, T>;

}

unsafe impl<'a, T: 'static + ?Sized> Yokeable<'a> for &'static T {
    type Output = &'a T;
}

fn main() {}

@Manishearth
Copy link
Member Author

(@jackh726 Out of curiosity, is there a reason you like no_core for the repros? Easier to debug?)

@jackh726
Copy link
Member

For me, yes, easier to debug. Making a test no_core means I can conceivably just RUSTC_LOG=debug, or at least be much more liberal with logging.

@lqd
Copy link
Member

lqd commented Jul 23, 2021

minimized a bit more the one in the OP (not the no_core repro)

pub unsafe trait Yokeable<'a> {
    type Output: 'a;
}
pub struct Yoke<Y: for<'a> Yokeable<'a>> {
    _marker: std::marker::PhantomData<Y>,
}
impl<Y: for<'a> Yokeable<'a>> Yoke<Y> {
    pub fn project<P>(
        &self,
        _f: for<'a> fn(&<Y as Yokeable<'a>>::Output, &'a ()) -> <P as Yokeable<'a>>::Output,
    ) -> Yoke<P>
    where
        P: for<'a> Yokeable<'a>,
    {
        unimplemented!()
    }
}
pub fn slice(y: Yoke<&'static str>) -> Yoke<&'static [u8]> {
    y.project(move |yk, _| yk.as_bytes())
}
unsafe impl<'a, T: 'static + ?Sized> Yokeable<'a> for &'static T {
    type Output = &'a T;
}
fn main() {
}

@jackh726
Copy link
Member

@Manishearth just pushed a fix. Can you confirm?

@Manishearth
Copy link
Member Author

@jackh726 will take me a while since that commit hasn't been trybuilt. But it looks like you checked in the reduced testcase, so that's good!

@Manishearth
Copy link
Member Author

It works, thanks!

@jackh726
Copy link
Member

The original issue here is fixed by #85499, but there might be a separate problem that was exposed here.

Can someone (@Manishearth?) check if that minimization fails? If so, might make sense to open a separate issue. If not, this can be closed (probably with a PR for that minimization as a test case)

@Manishearth
Copy link
Member Author

I'll have a look! I recall commenting on the normalize PR with this issue as well, and I think one of your try builds was successful in fixing this, but I should check again. Will do tomorrow.

@jackh726
Copy link
Member

jackh726 commented Aug 26, 2021

Well, a non -Clink-dead-code variant is fixed by #85499 (there's a test). But if the comment above is correct, there might be a -Clink-dead-code issue hiding (I don't see any normalization under binders in that repro, so I assume it's not the same error)

Edit: I just realised that the comment I linked isn't a full repro, but relies on the other code that does have normalization under binders. In that case, I think this is directly covered by the test in #85499. Going to close this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-bug Category: This is a bug. glacier ICE tracked in rust-lang/glacier. 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.
Projects
None yet
Development

No branches or pull requests

5 participants