Skip to content

Commit

Permalink
Fix irrefutable matches on integer ranges
Browse files Browse the repository at this point in the history
  • Loading branch information
varkor committed Dec 11, 2018
1 parent 1137d29 commit 510a9ff
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 1 deletion.
34 changes: 33 additions & 1 deletion src/librustc_mir/build/matches/simplify.rs
Expand Up @@ -26,6 +26,10 @@ use build::{BlockAnd, BlockAndExtension, Builder};
use build::matches::{Ascription, Binding, MatchPair, Candidate};
use hair::*;
use rustc::mir::*;
use rustc::ty;
use rustc::ty::layout::{Integer, IntegerExt, Size};
use syntax::attr::{SignedInt, UnsignedInt};
use rustc::hir::RangeEnd;

use std::mem;

Expand Down Expand Up @@ -62,6 +66,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
match_pair: MatchPair<'pat, 'tcx>,
candidate: &mut Candidate<'pat, 'tcx>)
-> Result<(), MatchPair<'pat, 'tcx>> {
let tcx = self.hir.tcx();
match *match_pair.pattern.kind {
PatternKind::AscribeUserType { ref subpattern, ref user_ty, user_ty_span } => {
candidate.ascriptions.push(Ascription {
Expand Down Expand Up @@ -104,7 +109,34 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
Err(match_pair)
}

PatternKind::Range { .. } => {
PatternKind::Range { lo, hi, ty, end } => {
let range = match ty.sty {
ty::Char => {
Some(('\u{0000}' as u128, '\u{10FFFF}' as u128, Size::from_bits(32)))
}
ty::Int(ity) => {
// FIXME(49937): refactor these bit manipulations into interpret.
let size = Integer::from_attr(&tcx, SignedInt(ity)).size();
let min = 1u128 << (size.bits() - 1);
let max = (1u128 << (size.bits() - 1)) - 1;
Some((min, max, size))
}
ty::Uint(uty) => {
// FIXME(49937): refactor these bit manipulations into interpret.
let size = Integer::from_attr(&tcx, UnsignedInt(uty)).size();
let max = !0u128 >> (128 - size.bits());
Some((0, max, size))
}
_ => None,
};
if let Some((min, max, sz)) = range {
if let (Some(lo), Some(hi)) = (lo.val.try_to_bits(sz), hi.val.try_to_bits(sz)) {
if lo <= min && (hi > max || hi == max && end == RangeEnd::Included) {
// Irrefutable pattern match.
return Ok(());
}
}
}
Err(match_pair)
}

Expand Down
8 changes: 8 additions & 0 deletions src/test/ui/pattern/irrefutable-exhaustive-integer-binding.rs
@@ -0,0 +1,8 @@
// run-pass

fn main() {
let -2147483648..=2147483647 = 1;
let 0..=255 = 0u8;
let -128..=127 = 0i8;
let '\u{0000}'..='\u{10FFFF}' = 'v';
}

0 comments on commit 510a9ff

Please sign in to comment.