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

Rust 1.18: internal compiler error: unresolved type in dtorck #42552

Closed
phimuemue opened this issue Jun 8, 2017 · 10 comments
Closed

Rust 1.18: internal compiler error: unresolved type in dtorck #42552

phimuemue opened this issue Jun 8, 2017 · 10 comments
Assignees
Labels
I-ICE Issue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️ P-high High priority regression-from-stable-to-stable Performance or correctness regression from one stable version to another. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@phimuemue
Copy link
Contributor

rust-1.18-bug.zip

Cargo.toml:

[package]
name = "rust-1-18-bug"
version = "0.1.0"
authors = ["philipp <philipp>"]

[dependencies]
itertools="0"

main.rs:

extern crate itertools;
use itertools::Itertools;

fn main() {
    [0].iter()
        .map(|n| (n, 0))
        .group_by(|_| 0)
        .into_iter()
        .map(|(_, grp)| 
            grp.into_iter()
                .group_by(|_| 0)
                .into_iter()
                .map(|(_, grpinner)| grpinner.into_iter())
        );
}

cargo build results in:

error: internal compiler error: unresolved type in dtorck
  --> src/main.rs:13:38
   |
13 |                 .map(|(_, grpinner)| grpinner.into_iter())
   |                                      ^^^^^^^^^^^^^^^^^^^^

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

note: we would appreciate a bug report: https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md#bug-reports

thread 'rustc' panicked at 'Box<Any>', /checkout/src/librustc_errors/lib.rs:375
note: Run with `RUST_BACKTRACE=1` for a backtrace.

rustc --version --verbose yields (I'm running Ubuntu 16.04):

rustc 1.18.0 (03fc9d622 2017-06-06)
binary: rustc
commit-hash: 03fc9d622e0ea26a3d37f5ab030737fcca6928b9
commit-date: 2017-06-06
host: x86_64-unknown-linux-gnu
release: 1.18.0
LLVM version: 3.9

Backtrace:

thread 'rustc' panicked at 'Box<Any>', /checkout/src/librustc_errors/lib.rs:375
stack backtrace:
   0: std::sys::imp::backtrace::tracing::imp::unwind_backtrace
             at /checkout/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs:49
   1: std::sys_common::backtrace::_print
             at /checkout/src/libstd/sys_common/backtrace.rs:71
   2: std::panicking::default_hook::{{closure}}
             at /checkout/src/libstd/sys_common/backtrace.rs:60
             at /checkout/src/libstd/panicking.rs:355
   3: std::panicking::default_hook
             at /checkout/src/libstd/panicking.rs:365
   4: std::panicking::rust_panic_with_hook
             at /checkout/src/libstd/panicking.rs:549
   5: std::panicking::begin_panic
   6: rustc_errors::Handler::abort_if_errors
   7: rustc_passes::consts::check_crate
   8: rustc_driver::driver::phase_3_run_analysis_passes::{{closure}}
   9: rustc::ty::context::TyCtxt::create_and_enter
  10: rustc_driver::driver::phase_3_run_analysis_passes
  11: rustc_driver::driver::compile_input
  12: rustc_driver::run_compiler
  13: std::panicking::try::do_call
  14: __rust_maybe_catch_panic
             at /checkout/src/libpanic_unwind/lib.rs:98
  15: <F as alloc::boxed::FnBox<A>>::call_box
  16: std::sys::imp::thread::Thread::new::thread_start
             at /checkout/src/liballoc/boxed.rs:650
             at /checkout/src/libstd/sys_common/thread.rs:21
             at /checkout/src/libstd/sys/unix/thread.rs:84
  17: start_thread
  18: clone
@frewsxcv
Copy link
Member

frewsxcv commented Jun 8, 2017

for reference, this was an error in 1.17.0, but didn't hit an ICE:

error: borrowed value does not live long enough
  --> src/main.rs:13:58
   |
10 |               grp.into_iter()
   |  _____________- starting here...
11 | |                 .group_by(|_| 0)
   | |________________________________- ...ending here: temporary value created here
12 |                 .into_iter()
13 |                   .map(|(_, grpinner)| grpinner.into_iter())
   |                                                            ^ temporary value dropped here while still borrowed
14 |           );
   |           - temporary value needs to live until here

error: aborting due to previous error

error: Could not compile `hi`.

To learn more, run the command again with --verbose.

@frewsxcv frewsxcv added the I-ICE Issue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️ label Jun 8, 2017
@phimuemue
Copy link
Contributor Author

phimuemue commented Jun 8, 2017

I constructed this example from a more complex one which I am not able to post here (too many requirements). The original piece of code compiled fine under 1.17, but hits an ICE in 1.18.

Can I somehow downgrade to 1.17 on my machine to construct an example that compiles cleanly under 1.17 but fails in 1.18?

@frewsxcv
Copy link
Member

frewsxcv commented Jun 8, 2017

@phimuemue if you're using rustup, rustup default 1.17.0 will set your compiler to 1.17.0

@Mark-Simulacrum Mark-Simulacrum added the regression-from-stable-to-stable Performance or correctness regression from one stable version to another. label Jun 8, 2017
@Mark-Simulacrum
Copy link
Member

I've bisected this to 141e8a6 -- #41716 (cc @nikomatsakis ) but I think P-medium since, while a regression, the code didn't compile anyway.

@Mark-Simulacrum Mark-Simulacrum added the P-medium Medium priority label Jun 8, 2017
@phimuemue
Copy link
Contributor Author

The following code compiles fine under 1.17, but yields the aforementioned ICE under 1.18:

extern crate itertools;
use itertools::Itertools;

fn main() {
    [0].iter()
        .map(|n| (n, 0))
        .group_by(|_| 0)
        .into_iter()
        .map(|(_, grp)| 
            grp.into_iter()
                .map(|_| 0)
                .group_by(|_| 0)
                .into_iter()
                .map(|(_, grpinner)| grpinner.into_iter().max())
                .max()
        )
        .max()
        .unwrap();
}

@Mark-Simulacrum
Copy link
Member

Okay, in that case P-high, I think.

@Mark-Simulacrum Mark-Simulacrum added P-high High priority and removed P-medium Medium priority labels Jun 8, 2017
@kennytm
Copy link
Member

kennytm commented Jun 9, 2017

Reduced from @phimuemue's second example. Compiles fine on 1.17, ICE on 1.18 with "unresolved type in dtorck".

fn into_iter<I: Iterator>(a: &I) -> Groups<I> {
    Groups { _a: a }
}

pub struct Groups<'a, I: 'a> {
    _a: &'a I,
}

impl<'a, I: Iterator> Iterator for Groups<'a, I> {
    type Item = Group<'a, I>;
    fn next(&mut self) -> Option<Self::Item> {
        None
    }
}

pub struct Group<'a, I: Iterator + 'a>
    where I::Item: 'a       // <-- needed to trigger ICE!
{
    _phantom: &'a (),
    _ice_trigger: I::Item,  // <-- needed to trigger ICE!
}


fn main() {
    let _ = into_iter(&[0].iter().map(|_| 0)).map(|grp| {
        let _g = grp;
    });
}

@kennytm
Copy link
Member

kennytm commented Jun 9, 2017

Referring to my example, ICE happens due to sty.ty == TyInfer(..) in dtorck_constraint_for_ty.

Logs of relevant function before the crash (I've upgraded all relevant debug! logs to warn! for convenience because RUST_LOG=debug has no effect in my setting)

WARN:rustc_typeck::check::regionck: regionck::visit_pat(pat=pat(87: _g))
WARN:rustc::ty::util: dtorck_constraint_for_ty(1.rs:26:13: 26:15, Group<'_, std::iter::Map<std::slice::Iter<'_, i32>, [closure@1.rs:25:39: 25:44]>>, 0, Group<'_, std::iter::Map<std::slice::Iter<'_, i32>, [closure@1.rs:25:39: 25:44]>>)
WARN:rustc::ty::util: dtorck_constraint_for_ty(Group<'_, std::iter::Map<std::slice::Iter<'_, i32>, [closure@1.rs:25:39: 25:44]>>) = Ok(DtorckConstraint { outlives: [], dtorck_types: [<std::iter::Map<std::slice::Iter<'_, i32>, [closure@1.rs:25:39: 25:44]> as std::iter::Iterator>::Item] })
WARN:rustc::ty::util: dtorck_constraint_for_ty(1.rs:26:13: 26:15, Group<'_, std::iter::Map<std::slice::Iter<'_, i32>, [closure@1.rs:25:39: 25:44]>>, 1, _)
WARN:rustc::ty::util: ty.sty = TyInfer(_#45t)
Real stack trace
stack backtrace:
   7: rustc::ty::util::<impl rustc::ty::context::TyCtxt<'a, 'gcx, 'tcx>>::dtorck_constraint_for_ty
   8: rustc_typeck::check::dropck::check_safety_of_destructor_if_necessary
   9: rustc_typeck::check::regionck::RegionCtxt::constrain_bindings_in_pat::{{closure}}
  10: rustc::hir::pat_util::<impl rustc::hir::Pat>::each_binding::{{closure}}
  11: rustc::hir::Pat::walk_
  12: rustc::hir::Pat::walk
  13: rustc::hir::pat_util::<impl rustc::hir::Pat>::each_binding
  14: rustc_typeck::check::regionck::RegionCtxt::constrain_bindings_in_pat
  15: <rustc_typeck::check::regionck::RegionCtxt<'a, 'gcx, 'tcx> as rustc::hir::intravisit::Visitor<'gcx>>::visit_local
  16: rustc::hir::intravisit::walk_block
  17: rustc::hir::intravisit::walk_expr
  18: <rustc_typeck::check::regionck::RegionCtxt<'a, 'gcx, 'tcx> as rustc::hir::intravisit::Visitor<'gcx>>::visit_expr
  19: rustc_typeck::check::regionck::RegionCtxt::visit_fn_body
  20: <rustc_typeck::check::regionck::RegionCtxt<'a, 'gcx, 'tcx> as rustc::hir::intravisit::Visitor<'gcx>>::visit_fn
  21: rustc::hir::intravisit::walk_expr
  22: rustc_typeck::check::regionck::RegionCtxt::check_expr_fn_block
  23: <rustc_typeck::check::regionck::RegionCtxt<'a, 'gcx, 'tcx> as rustc::hir::intravisit::Visitor<'gcx>>::visit_expr
  24: rustc::hir::intravisit::walk_expr
  25: <rustc_typeck::check::regionck::RegionCtxt<'a, 'gcx, 'tcx> as rustc::hir::intravisit::Visitor<'gcx>>::visit_expr
  26: rustc::hir::intravisit::walk_local
  27: rustc::hir::intravisit::walk_block
  28: rustc::hir::intravisit::walk_expr
  29: <rustc_typeck::check::regionck::RegionCtxt<'a, 'gcx, 'tcx> as rustc::hir::intravisit::Visitor<'gcx>>::visit_expr
  30: rustc_typeck::check::regionck::RegionCtxt::visit_fn_body
  31: rustc_typeck::check::regionck::<impl rustc_typeck::check::FnCtxt<'a, 'gcx, 'tcx>>::regionck_fn
  32: rustc_typeck::check::typeck_tables_of::{{closure}}
  33: rustc_typeck::check::InheritedBuilder::enter::{{closure}}
  34: rustc::infer::InferCtxtBuilder::enter::{{closure}}
  35: rustc::ty::context::tls::enter::{{closure}}
  36: <std::thread::local::LocalKey<T>>::with
  37: rustc::ty::context::tls::enter
  38: rustc::ty::context::GlobalCtxt::enter_local
  39: rustc::infer::InferCtxtBuilder::enter
  40: rustc_typeck::check::InheritedBuilder::enter
  41: rustc_typeck::check::typeck_tables_of
  42: rustc::ty::maps::<impl rustc::ty::maps::queries::typeck_tables_of<'tcx>>::try_get_with::{{closure}}
  43: rustc::ty::maps::<impl rustc::ty::context::TyCtxt<'a, 'gcx, 'tcx>>::cycle_check
  44: rustc::ty::maps::<impl rustc::ty::maps::queries::typeck_tables_of<'tcx>>::try_get_with
  45: rustc::ty::maps::<impl rustc::ty::maps::queries::typeck_tables_of<'tcx>>::try_get
  46: rustc::ty::maps::TyCtxtAt::typeck_tables_of
  47: rustc::ty::maps::<impl rustc::ty::context::TyCtxt<'a, 'tcx, 'lcx>>::typeck_tables_of
  48: rustc_typeck::check::typeck_item_bodies::{{closure}}
  49: rustc::session::Session::track_errors
  50: rustc_typeck::check::typeck_item_bodies
  51: rustc::ty::maps::<impl rustc::ty::maps::queries::typeck_item_bodies<'tcx>>::try_get_with::{{closure}}
  52: rustc::ty::maps::<impl rustc::ty::context::TyCtxt<'a, 'gcx, 'tcx>>::cycle_check
  53: rustc::ty::maps::<impl rustc::ty::maps::queries::typeck_item_bodies<'tcx>>::try_get_with
  54: rustc::ty::maps::<impl rustc::ty::maps::queries::typeck_item_bodies<'tcx>>::try_get
  55: rustc::ty::maps::TyCtxtAt::typeck_item_bodies
  56: rustc::ty::maps::<impl rustc::ty::context::TyCtxt<'a, 'tcx, 'lcx>>::typeck_item_bodies
  57: rustc_typeck::check::check_item_bodies
  58: rustc_typeck::check_crate::{{closure}}
  59: rustc::util::common::time
  60: rustc_typeck::check_crate
  61: rustc_driver::driver::phase_3_run_analysis_passes::{{closure}}
  62: rustc::ty::context::tls::enter::{{closure}}
  63: <std::thread::local::LocalKey<T>>::with
  64: rustc::ty::context::tls::enter
  65: rustc::ty::context::tls::enter_global::{{closure}}
  66: <std::thread::local::LocalKey<T>>::with
  67: rustc::ty::context::tls::enter_global
  68: rustc::ty::context::TyCtxt::create_and_enter
  69: rustc_driver::driver::phase_3_run_analysis_passes
  70: rustc_driver::driver::compile_input
  71: rustc_driver::run_compiler
  72: rustc_driver::main::{{closure}}
  73: rustc_driver::run::{{closure}}
  74: rustc_driver::monitor::{{closure}}
  75: __rust_try
  76: std::panicking::try
  77: std::panicking::try
  78: std::panic::catch_unwind
  79: std::thread::Builder::spawn::{{closure}}
  80: <F as alloc::boxed::FnBox<A>>::call_box
  81: std::sys_common::thread::start_thread
  82: std::sys::imp::thread::Thread::new::thread_start
  83: _pthread_body
  84: _pthread_start

ICE does not happen if the [0] is replaced by [0i32], where the log becomes:

WARN:rustc_typeck::check::regionck: regionck::visit_pat(pat=pat(87: _g))
WARN:rustc::ty::util: dtorck_constraint_for_ty(1.rs:26:13: 26:15, Group<'_, std::iter::Map<std::slice::Iter<'_, i32>, [closure@1.rs:25:42: 25:47]>>, 0, Group<'_, std::iter::Map<std::slice::Iter<'_, i32>, [closure@1.rs:25:42: 25:47]>>)
WARN:rustc::ty::util: dtorck_constraint_for_ty(Group<'_, std::iter::Map<std::slice::Iter<'_, i32>, [closure@1.rs:25:42: 25:47]>>) = Ok(DtorckConstraint { outlives: [], dtorck_types: [<std::iter::Map<std::slice::Iter<'_, i32>, [closure@1.rs:25:42: 25:47]> as std::iter::Iterator>::Item] })
WARN:rustc::ty::util: dtorck_constraint_for_ty(1.rs:26:13: 26:15, Group<'_, std::iter::Map<std::slice::Iter<'_, i32>, [closure@1.rs:25:42: 25:47]>>, 1, i32)
WARN:rustc::ty::util: dtorck_constraint_for_ty(i32) = Ok(DtorckConstraint { outlives: [], dtorck_types: [] })

(removing the I::Item: 'a constraint also has the same effect (the TyInfer becomes i32)).


Similarly @phimuemue's second example does not ICE after replacing all 0 by 0i32. Basically this means it can be worked around by being more explicit when using number literals.

@TimNN TimNN added the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label Jun 9, 2017
@nikomatsakis
Copy link
Contributor

Will investigate.

@nikomatsakis
Copy link
Contributor

OK, I've tracked down this bug, more-or-less, but I'm not sure how best to fix it just now.

What seems to be happening:

  • When we process the I::Item: 'a bound in the where-clauses, we wind up creating a projection cache entry. This caches a result of _#45t, and passes back a pending obligation that should resolve _#45t.
  • Unfortunately, we are invoking this normalization from the wf::implied_bounds routine (which in turn invokes obligations, where the actual normalizations arise). implied_bounds just discards the results from obligations, rather than registering this predicate to be solved later. Hence the constraint gets lost and _#45t goes unfulfilled.
  • Later we die.

Definitely the behavior of wf::implied_bounds (or perhaps obligations?) feels wrong. I'm not 100% sure why this is happening now and not before -- I suspect it is because in #41716 I improved some of the code in the inference engine to re-use variables more often, which is then leading to more cache hits -- i.e., this cache hit was always problematic, but we never reused its result before. This is probably also why having a field of just I and not I::Item avoids the ICE -- that would be covariant, and would likely also avoid the cache hit.

@bors bors closed this as completed in 9fec409 Jun 17, 2017
brson pushed a commit to brson/rust that referenced this issue Jun 22, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
I-ICE Issue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️ P-high High priority regression-from-stable-to-stable Performance or correctness regression from one stable version to another. 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

6 participants