From d6c19191b05c11c6a3f5cbf25178ec749f5a3414 Mon Sep 17 00:00:00 2001 From: Dan Robertson Date: Sun, 13 Jan 2019 14:23:32 +0000 Subject: [PATCH] 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. --- src/librustc_mir/hair/pattern/_match.rs | 9 ++++++- src/test/ui/issues/issue-57472.rs | 35 +++++++++++++++++++++++++ src/test/ui/issues/issue-57472.stderr | 20 ++++++++++++++ 3 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/issues/issue-57472.rs create mode 100644 src/test/ui/issues/issue-57472.stderr diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs index b25d47b390175..188a112044298 100644 --- a/src/librustc_mir/hair/pattern/_match.rs +++ b/src/librustc_mir/hair/pattern/_match.rs @@ -1372,7 +1372,14 @@ fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>, let is_visible = adt.is_enum() || field.vis.is_accessible_from(cx.module, cx.tcx); if is_visible { - field.ty(cx.tcx, substs) + let ty = field.ty(cx.tcx, substs); + match ty.sty { + // If the field type returned is an array of an unknown + // size return an TyErr. + ty::Array(_, len) if len.assert_usize(cx.tcx).is_none() => + cx.tcx.types.err, + _ => ty, + } } else { // Treat all non-visible fields as TyErr. They // can't appear in any other pattern from diff --git a/src/test/ui/issues/issue-57472.rs b/src/test/ui/issues/issue-57472.rs new file mode 100644 index 0000000000000..1131006374c64 --- /dev/null +++ b/src/test/ui/issues/issue-57472.rs @@ -0,0 +1,35 @@ +#![crate_type="lib"] +#![deny(unreachable_patterns)] + +mod test_struct { + // Test the exact copy of the minimal example + // posted in the issue. + pub struct Punned { + foo: [u8; 1], + bar: [u8; 1], + } + + pub fn test(punned: Punned) { + match punned { + Punned { foo: [_], .. } => println!("foo"), + Punned { bar: [_], .. } => println!("bar"), + //~^ ERROR unreachable pattern [unreachable_patterns] + } + } +} + +mod test_union { + // Test the same thing using a union. + pub union Punned { + foo: [u8; 1], + bar: [u8; 1], + } + + pub fn test(punned: Punned) { + match punned { + Punned { foo: [_] } => println!("foo"), + Punned { bar: [_] } => println!("bar"), + //~^ ERROR unreachable pattern [unreachable_patterns] + } + } +} diff --git a/src/test/ui/issues/issue-57472.stderr b/src/test/ui/issues/issue-57472.stderr new file mode 100644 index 0000000000000..b6dd7e2494186 --- /dev/null +++ b/src/test/ui/issues/issue-57472.stderr @@ -0,0 +1,20 @@ +error: unreachable pattern + --> $DIR/issue-57472.rs:15:13 + | +LL | Punned { bar: [_], .. } => println!("bar"), + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/issue-57472.rs:2:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/issue-57472.rs:31:13 + | +LL | Punned { bar: [_] } => println!("bar"), + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors +