From 0a80624dcfb8aab884c0bb478edaaa2a9e1c9a3b Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 27 Dec 2019 19:04:16 +0100 Subject: [PATCH 1/3] Fixup comments and clarify ICEs --- src/librustc_mir_build/hair/pattern/_match.rs | 39 ++++++++++++------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/src/librustc_mir_build/hair/pattern/_match.rs b/src/librustc_mir_build/hair/pattern/_match.rs index 03f668d562e78..8348322571fe0 100644 --- a/src/librustc_mir_build/hair/pattern/_match.rs +++ b/src/librustc_mir_build/hair/pattern/_match.rs @@ -291,30 +291,39 @@ impl<'tcx> LiteralExpander<'tcx> { } Scalar::Raw { .. } => { let layout = self.tcx.layout_of(self.param_env.and(rty)).unwrap(); - if layout.is_zst() { - // Deref of a reference to a ZST is a nop. - ConstValue::Scalar(Scalar::zst()) - } else { - // FIXME(oli-obk): this is reachable for `const FOO: &&&u32 = &&&42;` - bug!("cannot deref {:#?}, {} -> {}", val, crty, rty); - } + assert!(layout.is_zst()); + // Deref of a reference to a ZST is a nop. + ConstValue::Scalar(Scalar::zst()) } } } - // unsize array to slice if pattern is array but match value or other patterns are slice - (ConstValue::Scalar(Scalar::Ptr(p)), ty::Array(t, n), ty::Slice(u)) => { + // Unsize array to slice if pattern is array + // but match value or other patterns are slice. + (ConstValue::Scalar(s), ty::Array(t, n), ty::Slice(u)) => { assert_eq!(t, u); - ConstValue::Slice { - data: self.tcx.alloc_map.lock().unwrap_memory(p.alloc_id), - start: p.offset.bytes().try_into().unwrap(), - end: n.eval_usize(self.tcx, ty::ParamEnv::empty()).try_into().unwrap(), + let n = n.eval_usize(self.tcx, ty::ParamEnv::empty()).try_into().unwrap(); + match s { + Scalar::Ptr(p) => { + let start = p.offset.bytes().try_into().unwrap(); + ConstValue::Slice { + data: self.tcx.alloc_map.lock().unwrap_memory(p.alloc_id), + start, + end: n, + } + } + Scalar::Raw { .. } => { + assert_eq!(n, 0); + // FIXME(oli-obk): this is reachable for + // `const FOO: &[u8] = transmute::(1);` + bug!("cannot deref {:#?}, {} -> {}", val, crty, rty); + } } } - // fat pointers stay the same + // Wide pointers stay the same. (ConstValue::Slice { .. }, _, _) | (_, ty::Slice(_), ty::Slice(_)) | (_, ty::Str, ty::Str) => val, - // FIXME(oli-obk): this is reachable for `const FOO: &&&u32 = &&&42;` being used + // FIXME(oli-obk): this is reachable for `const FOO: &&&u32 = &&&42;` _ => bug!("cannot deref {:#?}, {} -> {}", val, crty, rty), } } From 2aa0bfd01275bcd008877893c1df207d75f98ec6 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Thu, 2 Apr 2020 15:35:43 +0200 Subject: [PATCH 2/3] Handle slice "deref" in pattern matching. --- src/librustc_mir_build/hair/pattern/_match.rs | 54 +++++++++++++------ src/test/ui/pattern/const-pat-unreachable.rs | 15 ++++++ .../ui/pattern/const-pat-unreachable.stderr | 20 +++++++ .../usefulness/slice-pattern-const-2.rs | 4 +- .../usefulness/slice-pattern-const-2.stderr | 20 +++++-- .../slice-patterns-exhaustiveness.rs | 1 - .../slice-patterns-exhaustiveness.stderr | 13 +---- 7 files changed, 92 insertions(+), 35 deletions(-) create mode 100644 src/test/ui/pattern/const-pat-unreachable.rs create mode 100644 src/test/ui/pattern/const-pat-unreachable.stderr diff --git a/src/librustc_mir_build/hair/pattern/_match.rs b/src/librustc_mir_build/hair/pattern/_match.rs index 8348322571fe0..c312498057dc5 100644 --- a/src/librustc_mir_build/hair/pattern/_match.rs +++ b/src/librustc_mir_build/hair/pattern/_match.rs @@ -2407,24 +2407,44 @@ fn specialize_one_pattern<'p, 'tcx>( _ => span_bug!(pat.span, "array pattern is {:?}", value,), } } - ty::Slice(t) => { - match value.val { - ty::ConstKind::Value(ConstValue::Slice { data, start, end }) => { - let offset = Size::from_bytes(start); - let n = (end - start) as u64; - (Cow::Borrowed(data), offset, n, t) - } - ty::ConstKind::Value(ConstValue::ByRef { .. }) => { - // FIXME(oli-obk): implement `deref` for `ConstValue` - return None; - } - _ => span_bug!( - pat.span, - "slice pattern constant must be scalar pair but is {:?}", - value, - ), + ty::Slice(t) => match value.val { + ty::ConstKind::Value(ConstValue::Slice { data, start, end }) => { + let offset = Size::from_bytes(start as u64); + let n = (end - start) as u64; + (Cow::Borrowed(data), offset, n, t) } - } + ty::ConstKind::Value(ConstValue::ByRef { alloc, offset }) => { + // The following code is essentially a `deref` operation for slice wide + // pointers. + // First, read a pointer. + let offset = Pointer::new(AllocId(0), offset); + let ptr = alloc + .read_ptr_sized(&cx.tcx, offset) + .unwrap() + .not_undef() + .unwrap() + .assert_ptr(); + // Then read a length. + let offset = + offset.offset(cx.tcx.data_layout.pointer_size, &cx.tcx).unwrap(); + let len = alloc + .read_ptr_sized(&cx.tcx, offset) + .unwrap() + .not_undef() + .unwrap() + .assert_bits(cx.tcx.data_layout.pointer_size) + .try_into() + .unwrap(); + // Now load the memory where the pointer points to. + let data = cx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id); + (Cow::Borrowed(data), ptr.offset, len, t) + } + _ => span_bug!( + pat.span, + "slice pattern constant must be scalar pair but is {:?}", + value, + ), + }, _ => span_bug!( pat.span, "unexpected const-val {:?} with ctor {:?}", diff --git a/src/test/ui/pattern/const-pat-unreachable.rs b/src/test/ui/pattern/const-pat-unreachable.rs new file mode 100644 index 0000000000000..abed78259a9e6 --- /dev/null +++ b/src/test/ui/pattern/const-pat-unreachable.rs @@ -0,0 +1,15 @@ +#![feature(const_transmute)] +#![deny(unreachable_patterns)] + +const FOO: &[u8] = unsafe { std::mem::transmute::(1) }; +const BAR: &[u8] = unsafe { std::mem::transmute::(3) }; + +fn main() { + let x: &[u8] = unimplemented!(); + match x { + b"" => {} + FOO => {} //~ ERROR unreachable pattern + BAR => {} //~ ERROR unreachable pattern + _ => {} + } +} diff --git a/src/test/ui/pattern/const-pat-unreachable.stderr b/src/test/ui/pattern/const-pat-unreachable.stderr new file mode 100644 index 0000000000000..6ae8b5e59b691 --- /dev/null +++ b/src/test/ui/pattern/const-pat-unreachable.stderr @@ -0,0 +1,20 @@ +error: unreachable pattern + --> $DIR/const-pat-unreachable.rs:11:9 + | +LL | FOO => {} + | ^^^ + | +note: the lint level is defined here + --> $DIR/const-pat-unreachable.rs:2:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/const-pat-unreachable.rs:12:9 + | +LL | BAR => {} + | ^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/pattern/usefulness/slice-pattern-const-2.rs b/src/test/ui/pattern/usefulness/slice-pattern-const-2.rs index a36c550f530a9..6cfef115d08dc 100644 --- a/src/test/ui/pattern/usefulness/slice-pattern-const-2.rs +++ b/src/test/ui/pattern/usefulness/slice-pattern-const-2.rs @@ -6,13 +6,13 @@ fn main() { match s { MAGIC_TEST => (), [0x00, 0x00, 0x00, 0x00] => (), - [4, 5, 6, 7] => (), // FIXME(oli-obk): this should warn, but currently does not + [4, 5, 6, 7] => (), //~ ERROR unreachable pattern _ => (), } match s { [0x00, 0x00, 0x00, 0x00] => (), MAGIC_TEST => (), - [4, 5, 6, 7] => (), // FIXME(oli-obk): this should warn, but currently does not + [4, 5, 6, 7] => (), //~ ERROR unreachable pattern _ => (), } match s { diff --git a/src/test/ui/pattern/usefulness/slice-pattern-const-2.stderr b/src/test/ui/pattern/usefulness/slice-pattern-const-2.stderr index cd0cb2e887691..29db94d375940 100644 --- a/src/test/ui/pattern/usefulness/slice-pattern-const-2.stderr +++ b/src/test/ui/pattern/usefulness/slice-pattern-const-2.stderr @@ -1,8 +1,8 @@ error: unreachable pattern - --> $DIR/slice-pattern-const-2.rs:28:9 + --> $DIR/slice-pattern-const-2.rs:9:9 | -LL | FOO => (), - | ^^^ +LL | [4, 5, 6, 7] => (), + | ^^^^^^^^^^^^ | note: the lint level is defined here --> $DIR/slice-pattern-const-2.rs:1:9 @@ -10,5 +10,17 @@ note: the lint level is defined here LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ -error: aborting due to previous error +error: unreachable pattern + --> $DIR/slice-pattern-const-2.rs:15:9 + | +LL | [4, 5, 6, 7] => (), + | ^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/slice-pattern-const-2.rs:28:9 + | +LL | FOO => (), + | ^^^ + +error: aborting due to 3 previous errors diff --git a/src/test/ui/pattern/usefulness/slice-patterns-exhaustiveness.rs b/src/test/ui/pattern/usefulness/slice-patterns-exhaustiveness.rs index 52d1320dad153..11d2b483923ca 100644 --- a/src/test/ui/pattern/usefulness/slice-patterns-exhaustiveness.rs +++ b/src/test/ui/pattern/usefulness/slice-patterns-exhaustiveness.rs @@ -87,7 +87,6 @@ fn main() { CONST => {} } match s { - //~^ ERROR `&[true]` not covered [] => {}, [false] => {}, CONST => {}, diff --git a/src/test/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr b/src/test/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr index 8b85eaeda0acf..425bfc7136d8f 100644 --- a/src/test/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr +++ b/src/test/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr @@ -124,17 +124,8 @@ LL | match s { = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `&[bool]` -error[E0004]: non-exhaustive patterns: `&[true]` not covered - --> $DIR/slice-patterns-exhaustiveness.rs:89:11 - | -LL | match s { - | ^ pattern `&[true]` not covered - | - = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `&[bool]` - error[E0004]: non-exhaustive patterns: `&[false]` not covered - --> $DIR/slice-patterns-exhaustiveness.rs:97:11 + --> $DIR/slice-patterns-exhaustiveness.rs:96:11 | LL | match s1 { | ^^ pattern `&[false]` not covered @@ -142,6 +133,6 @@ LL | match s1 { = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `&[bool; 1]` -error: aborting due to 16 previous errors +error: aborting due to 15 previous errors For more information about this error, try `rustc --explain E0004`. From 7c4984ffc63c3c1fd7a39b2a42d3f31d5034e32d Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Thu, 2 Apr 2020 17:22:35 +0200 Subject: [PATCH 3/3] Update src/librustc_mir_build/hair/pattern/_match.rs Co-Authored-By: varkor --- src/librustc_mir_build/hair/pattern/_match.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/librustc_mir_build/hair/pattern/_match.rs b/src/librustc_mir_build/hair/pattern/_match.rs index c312498057dc5..5713baf308544 100644 --- a/src/librustc_mir_build/hair/pattern/_match.rs +++ b/src/librustc_mir_build/hair/pattern/_match.rs @@ -297,8 +297,9 @@ impl<'tcx> LiteralExpander<'tcx> { } } } - // Unsize array to slice if pattern is array - // but match value or other patterns are slice. + // Unsize the array to a slice if we're matching on a slice, + // or other patterns are a slice (despite this pattern being + // an array). (ConstValue::Scalar(s), ty::Array(t, n), ty::Slice(u)) => { assert_eq!(t, u); let n = n.eval_usize(self.tcx, ty::ParamEnv::empty()).try_into().unwrap();