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

Pattern-matching array values in struct fields causes compiler panic #57472

Closed
ghost opened this issue Jan 9, 2019 · 5 comments
Closed

Pattern-matching array values in struct fields causes compiler panic #57472

ghost opened this issue Jan 9, 2019 · 5 comments
Labels
A-slice-patterns Area: Slice patterns, https://github.com/rust-lang/rust/issues/23121 I-ICE Issue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️

Comments

@ghost
Copy link

ghost commented Jan 9, 2019

I am writing some code which parses on-disk structures which vary their type based on magic numbers scattered through the structure. I have chosen to model this as a union of structs, and the magic number fields as byte arrays because they have neither power-of-two alignment or size, and then pattern-match on magic numbers to determine the type. This turns out to be sufficiently pathological to cause compiler panics.

Here is a minimal case that triggers the panic:

pub struct Punned {
    foo: [u8; 1],
    bar: [u8; 1],
}
pub fn test(punned: Punned) {
    match punned {
        Punned { foo: [_], .. } => println!("foo"),
        Punned { bar: [_], .. } => println!("bar"),
    }
}

Playing around with the different things being matched on — my real code matches on constants — suggest that this is a bug in the exhaustiveness checking.

Output of rustc --version --verbose:

rustc 1.33.0-nightly (d22fa2d87 2019-01-08)
binary: rustc
commit-hash: d22fa2d87d03d19fdb1359faab9ec5e74eff26b3
commit-date: 2019-01-08
host: x86_64-apple-darwin
release: 1.33.0-nightly
LLVM version: 8.0

Output of RUST_BACKTRACE=1 rustc crash.rs:

thread 'rustc' panicked at 'expected `LazyConst` to contain a usize', src/libcore/option.rs:1040:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
stack backtrace:
   0: std::sys::unix::backtrace::tracing::imp::unwind_backtrace
   1: std::sys_common::backtrace::_print
   2: std::panicking::default_hook::{{closure}}
   3: std::panicking::default_hook
   4: rustc::util::common::panic_hook
   5: std::panicking::rust_panic_with_hook
   6: std::panicking::continue_panic_fmt
   7: rust_begin_unwind
   8: core::panicking::panic_fmt
   9: core::option::expect_failed
  10: rustc_mir::hair::pattern::_match::pat_constructors
  11: rustc_mir::hair::pattern::_match::is_useful
  12: rustc_mir::hair::pattern::_match::is_useful
  13: rustc_mir::hair::pattern::_match::is_useful_specialized
  14: <core::iter::Map<I, F> as core::iter::iterator::Iterator>::try_fold
  15: rustc_mir::hair::pattern::_match::is_useful
  16: rustc_mir::hair::pattern::_match::is_useful_specialized
  17: <core::iter::Map<I, F> as core::iter::iterator::Iterator>::try_fold
  18: rustc_mir::hair::pattern::_match::is_useful
  19: rustc_mir::hair::pattern::check_match::check_arms
  20: rustc_mir::hair::pattern::_match::MatchCheckCtxt::create_and_enter
  21: <rustc_mir::hair::pattern::check_match::MatchVisitor<'a, 'tcx> as rustc::hir::intravisit::Visitor<'tcx>>::visit_expr
  22: <rustc_mir::hair::pattern::check_match::MatchVisitor<'a, 'tcx> as rustc::hir::intravisit::Visitor<'tcx>>::visit_expr
  23: <rustc_mir::hair::pattern::check_match::MatchVisitor<'a, 'tcx> as rustc::hir::intravisit::Visitor<'tcx>>::visit_body
  24: rustc::session::Session::track_errors
  25: rustc_mir::hair::pattern::check_match::check_match
  26: rustc::ty::query::__query_compute::check_match
  27: rustc::ty::query::<impl rustc::ty::query::config::QueryAccessors<'tcx> for rustc::ty::query::queries::check_match<'tcx>>::compute
  28: rustc::dep_graph::graph::DepGraph::with_task_impl
  29: rustc::ty::query::plumbing::<impl rustc::ty::context::TyCtxt<'a, 'gcx, 'tcx>>::try_get_with
  30: <rustc_mir::hair::pattern::check_match::OuterVisitor<'a, 'tcx> as rustc::hir::intravisit::Visitor<'tcx>>::visit_body
  31: rustc::hir::intravisit::walk_item
  32: rustc::hir::Crate::visit_all_item_likes
  33: rustc_mir::hair::pattern::check_match::check_crate
  34: rustc::util::common::time
  35: <std::thread::local::LocalKey<T>>::with
  36: rustc_driver::driver::compile_input
  37: rustc_driver::run_compiler_with_pool
  38: <scoped_tls::ScopedKey<T>>::set
  39: rustc_driver::run_compiler
  40: <scoped_tls::ScopedKey<T>>::set
query stack during panic:
#0 [check_match] processing `test`
end of query stack

error: internal compiler error: unexpected panic

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

note: rustc 1.33.0-nightly (d22fa2d87 2019-01-08) running on x86_64-apple-darwin
@Centril Centril added I-ICE Issue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️ A-slice-patterns Area: Slice patterns, https://github.com/rust-lang/rust/issues/23121 labels Jan 9, 2019
@dlrobertson
Copy link
Contributor

dlrobertson commented Jan 12, 2019

I actually think I know what is going on here. If you add bar: _ to the first arm the compiler doesn't ICE. I think it is because we first attempt to get the type of the pattern from the previously seen arms here, but the 1st arm did not include all of the fields used in the second arm.

I'm not entirely sure what the best way to fix this is, but I'll post a PR once I get something working.

@ghost
Copy link
Author

ghost commented Jan 12, 2019

Thumbs-up for an interesting workaround, however it does not work for union patterns as they can only be matched on one field. I'm unclear on why that limitation even exists.

@dlrobertson
Copy link
Contributor

For union patterns you're only accessing one field, so you're not using ... This ICE is only triggered when you use the .. pattern on a struct in a match . If you can repro this ICE with a union or enum, let me know and I'll add it to the test in my PR. I've already added the example you included in the issue to it.

@ghost
Copy link
Author

ghost commented Jan 13, 2019

I also get a UCE if I make the obvious tweaks to use a union instead:

pub union Punned {
    foo: [u8; 1],
    bar: [u8; 1],
}
pub fn test(punned: Punned) {
    match punned {
        Punned { foo: [_] } => println!("foo"),
        Punned { bar: [_] } => println!("bar"),
    }
}

It doesn't matter whether or not the match is in an unsafe block; the compiler presumably crashes before it gets as far as checking for that.

@dlrobertson
Copy link
Contributor

dlrobertson commented Jan 13, 2019

Ah! you're right! I think I was using my updated compiler when I tested that. I added the example with the union to the test in the PR.

Centril added a commit to Centril/rust that referenced this issue Jan 13, 2019
librustc_mir: Fix ICE with slice patterns

If a match arm does not include all fields in a structure and a later
pattern includes a field that is an array, we will attempt to use the
array type from the prior arm. When calculating the field type, treat
a array of an unknown size as a `TyErr`.

Fixes: rust-lang#57472
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-slice-patterns Area: Slice patterns, https://github.com/rust-lang/rust/issues/23121 I-ICE Issue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️
Projects
None yet
Development

No branches or pull requests

2 participants