Skip to content

Commit

Permalink
Auto merge of #66603 - Nadrieril:fix-65413, r=varkor
Browse files Browse the repository at this point in the history
Fix #65413

#65413 was due to an oversight in `pat_constructor` that didn't check if a particular const value was maybe a slice/array const.
  • Loading branch information
bors committed Nov 28, 2019
2 parents 4752c05 + 3f91712 commit f453d11
Show file tree
Hide file tree
Showing 8 changed files with 111 additions and 43 deletions.
66 changes: 30 additions & 36 deletions src/librustc_mir/hair/pattern/_match.rs
Expand Up @@ -347,6 +347,7 @@ impl PatternFolder<'tcx> for LiteralExpander<'tcx> {
) => bug!("cannot deref {:#?}, {} -> {}", val, crty, rty),

(_, &PatKind::Binding { subpattern: Some(ref s), .. }) => s.fold_with(self),
(_, &PatKind::AscribeUserType { subpattern: ref s, .. }) => s.fold_with(self),
_ => pat.super_fold_with(self),
}
}
Expand Down Expand Up @@ -747,7 +748,7 @@ impl<'tcx> Constructor<'tcx> {
.iter()
.filter_map(|c: &Constructor<'_>| match c {
Slice(slice) => Some(*slice),
// FIXME(#65413): We ignore `ConstantValue`s here.
// FIXME(oli-obk): implement `deref` for `ConstValue`
ConstantValue(..) => None,
_ => bug!("bad slice pattern constructor {:?}", c),
})
Expand Down Expand Up @@ -1759,9 +1760,7 @@ fn pat_constructor<'tcx>(
pat: &Pat<'tcx>,
) -> Option<Constructor<'tcx>> {
match *pat.kind {
PatKind::AscribeUserType { ref subpattern, .. } => {
pat_constructor(tcx, param_env, subpattern)
}
PatKind::AscribeUserType { .. } => bug!(), // Handled by `expand_pattern`
PatKind::Binding { .. } | PatKind::Wild => None,
PatKind::Leaf { .. } | PatKind::Deref { .. } => Some(Single),
PatKind::Variant { adt_def, variant_index, .. } => {
Expand All @@ -1771,7 +1770,19 @@ fn pat_constructor<'tcx>(
if let Some(int_range) = IntRange::from_const(tcx, param_env, value, pat.span) {
Some(IntRange(int_range))
} else {
Some(ConstantValue(value))
match (value.val, &value.ty.kind) {
(_, ty::Array(_, n)) => {
let len = n.eval_usize(tcx, param_env);
Some(Slice(Slice { array_len: Some(len), kind: FixedLen(len) }))
}
(ty::ConstKind::Value(ConstValue::Slice { start, end, .. }), ty::Slice(_)) => {
let len = (end - start) as u64;
Some(Slice(Slice { array_len: None, kind: FixedLen(len) }))
}
// FIXME(oli-obk): implement `deref` for `ConstValue`
// (ty::ConstKind::Value(ConstValue::ByRef { .. }), ty::Slice(_)) => { ... }
_ => Some(ConstantValue(value)),
}
}
}
PatKind::Range(PatRange { lo, hi, end }) => {
Expand Down Expand Up @@ -2085,32 +2096,19 @@ fn split_grouped_constructors<'p, 'tcx>(
let mut max_suffix_len = self_suffix;
let mut max_fixed_len = 0;

for row in matrix.heads() {
match *row.kind {
PatKind::Constant { value } => {
// extract the length of an array/slice from a constant
match (value.val, &value.ty.kind) {
(_, ty::Array(_, n)) => {
max_fixed_len =
cmp::max(max_fixed_len, n.eval_usize(tcx, param_env))
}
(
ty::ConstKind::Value(ConstValue::Slice { start, end, .. }),
ty::Slice(_),
) => max_fixed_len = cmp::max(max_fixed_len, (end - start) as u64),
_ => {}
let head_ctors =
matrix.heads().filter_map(|pat| pat_constructor(tcx, param_env, pat));
for ctor in head_ctors {
match ctor {
Slice(slice) => match slice.pattern_kind() {
FixedLen(len) => {
max_fixed_len = cmp::max(max_fixed_len, len);
}
}
PatKind::Slice { ref prefix, slice: None, ref suffix }
| PatKind::Array { ref prefix, slice: None, ref suffix } => {
let fixed_len = prefix.len() as u64 + suffix.len() as u64;
max_fixed_len = cmp::max(max_fixed_len, fixed_len);
}
PatKind::Slice { ref prefix, slice: Some(_), ref suffix }
| PatKind::Array { ref prefix, slice: Some(_), ref suffix } => {
max_prefix_len = cmp::max(max_prefix_len, prefix.len() as u64);
max_suffix_len = cmp::max(max_suffix_len, suffix.len() as u64);
}
VarLen(prefix, suffix) => {
max_prefix_len = cmp::max(max_prefix_len, prefix);
max_suffix_len = cmp::max(max_suffix_len, suffix);
}
},
_ => {}
}
}
Expand Down Expand Up @@ -2250,21 +2248,17 @@ fn patterns_for_variant<'p, 'a: 'p, 'tcx>(
/// fields filled with wild patterns.
fn specialize_one_pattern<'p, 'a: 'p, 'q: 'p, 'tcx>(
cx: &mut MatchCheckCtxt<'a, 'tcx>,
mut pat: &'q Pat<'tcx>,
pat: &'q Pat<'tcx>,
constructor: &Constructor<'tcx>,
ctor_wild_subpatterns: &[&'p Pat<'tcx>],
) -> Option<PatStack<'p, 'tcx>> {
while let PatKind::AscribeUserType { ref subpattern, .. } = *pat.kind {
pat = subpattern;
}

if let NonExhaustive = constructor {
// Only a wildcard pattern can match the special extra constructor
return if pat.is_wildcard() { Some(PatStack::default()) } else { None };
}

let result = match *pat.kind {
PatKind::AscribeUserType { .. } => bug!(), // Handled above
PatKind::AscribeUserType { .. } => bug!(), // Handled by `expand_pattern`

PatKind::Binding { .. } | PatKind::Wild => {
Some(PatStack::from_slice(ctor_wild_subpatterns))
Expand Down
@@ -0,0 +1,15 @@
// check-pass
#![feature(slice_patterns)]
#![deny(unreachable_patterns)]

const C0: &'static [u8] = b"\x00";

fn main() {
let x: &[u8] = &[0];
match x {
&[] => {}
&[1..=255] => {}
C0 => {}
&[_, _, ..] => {}
}
}
@@ -1,16 +1,16 @@
error[E0004]: non-exhaustive patterns: `&[..]` not covered
error[E0004]: non-exhaustive patterns: `&[0u8..=64u8, _, _, _]` and `&[66u8..=std::u8::MAX, _, _, _]` not covered
--> $DIR/match-byte-array-patterns-2.rs:4:11
|
LL | match buf {
| ^^^ pattern `&[..]` not covered
| ^^^ patterns `&[0u8..=64u8, _, _, _]` and `&[66u8..=std::u8::MAX, _, _, _]` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms

error[E0004]: non-exhaustive patterns: `&[..]` not covered
error[E0004]: non-exhaustive patterns: `&[]`, `&[_]`, `&[_, _]` and 2 more not covered
--> $DIR/match-byte-array-patterns-2.rs:10:11
|
LL | match buf {
| ^^^ pattern `&[..]` not covered
| ^^^ patterns `&[]`, `&[_]`, `&[_, _]` and 2 more not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms

Expand Down
7 changes: 7 additions & 0 deletions src/test/ui/pattern/usefulness/slice-pattern-const.rs
Expand Up @@ -44,4 +44,11 @@ fn main() {
b"" => (), //~ ERROR unreachable pattern
_ => (), //~ ERROR unreachable pattern
}

const CONST1: &[bool; 1] = &[true];
match &[false] {
CONST1 => {}
[true] => {} //~ ERROR unreachable pattern
[false] => {}
}
}
8 changes: 7 additions & 1 deletion src/test/ui/pattern/usefulness/slice-pattern-const.stderr
Expand Up @@ -52,5 +52,11 @@ error: unreachable pattern
LL | _ => (),
| ^

error: aborting due to 8 previous errors
error: unreachable pattern
--> $DIR/slice-pattern-const.rs:51:9
|
LL | [true] => {}
| ^^^^^^

error: aborting due to 9 previous errors

22 changes: 22 additions & 0 deletions src/test/ui/pattern/usefulness/slice-patterns-exhaustiveness.rs
Expand Up @@ -82,4 +82,26 @@ fn main() {
[_, _] => {}
[false, .., false] => {}
}

const CONST: &[bool] = &[true];
match s {
//~^ ERROR `&[..]` not covered
CONST => {}
}
match s {
//~^ ERROR `&[true]` not covered
[] => {},
[false] => {},
CONST => {},
[_, _, ..] => {}
}
const CONST1: &[bool; 1] = &[true];
match s1 {
//~^ ERROR `&[false]` not covered
CONST1 => {}
}
match s1 {
CONST1 => {}
[false] => {}
}
}
Expand Up @@ -102,6 +102,30 @@ LL | match s {
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms

error: aborting due to 13 previous errors
error[E0004]: non-exhaustive patterns: `&[..]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:87:11
|
LL | match s {
| ^ pattern `&[..]` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms

error[E0004]: non-exhaustive patterns: `&[true]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:91: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

error[E0004]: non-exhaustive patterns: `&[false]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:99:11
|
LL | match s1 {
| ^^ pattern `&[false]` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms

error: aborting due to 16 previous errors

For more information about this error, try `rustc --explain E0004`.
Expand Up @@ -2,7 +2,7 @@
#![deny(unreachable_patterns)]

fn main() {
let s: &[bool] = &[true; 0];
let s: &[bool] = &[];

match s {
[true, ..] => {}
Expand Down

0 comments on commit f453d11

Please sign in to comment.