diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs index 6f8b1f8e799..ff7b4f9e0fd 100644 --- a/src/librustc_mir/hair/pattern/_match.rs +++ b/src/librustc_mir/hair/pattern/_match.rs @@ -985,15 +985,17 @@ fn slice_pat_covered_by_constructor(tcx: TyCtxt, _span: Span, Ok(true) } -fn constructor_covered_by_range(ctor: &Constructor, - from: &ConstVal, to: &ConstVal, - end: RangeEnd, - ty: Ty) - -> Result { +fn constructor_covered_by_range<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + ctor: &Constructor, + from: &ConstVal, to: &ConstVal, + end: RangeEnd, + ty: Ty<'tcx>, +) -> Result { trace!("constructor_covered_by_range {:#?}, {:#?}, {:#?}, {}", ctor, from, to, ty); - let cmp_from = |c_from| compare_const_vals(c_from, from, ty) + let cmp_from = |c_from| compare_const_vals(tcx, c_from, from, ty) .map(|res| res != Ordering::Less); - let cmp_to = |c_to| compare_const_vals(c_to, to, ty); + let cmp_to = |c_to| compare_const_vals(tcx, c_to, to, ty); macro_rules! some_or_ok { ($e:expr) => { match $e { @@ -1105,6 +1107,7 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>( }, _ => { match constructor_covered_by_range( + cx.tcx, constructor, &value.val, &value.val, RangeEnd::Included, value.ty, ) { @@ -1118,6 +1121,7 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>( PatternKind::Range { lo, hi, ref end } => { match constructor_covered_by_range( + cx.tcx, constructor, &lo.val, &hi.val, end.clone(), lo.ty, ) { Ok(true) => Some(vec![]), diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index 8d2b73d6ba0..9f17af8b16f 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -16,7 +16,7 @@ mod check_match; pub use self::check_match::check_crate; pub(crate) use self::check_match::check_match; -use interpret::{const_val_field, const_discr}; +use interpret::{const_val_field, const_discr, self}; use rustc::middle::const_val::ConstVal; use rustc::mir::{Field, BorrowKind, Mutability}; @@ -372,7 +372,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { (PatternKind::Constant { value: lo }, PatternKind::Constant { value: hi }) => { use std::cmp::Ordering; - match (end, compare_const_vals(&lo.val, &hi.val, ty).unwrap()) { + match (end, compare_const_vals(self.tcx, &lo.val, &hi.val, ty).unwrap()) { (RangeEnd::Excluded, Ordering::Less) => PatternKind::Range { lo, hi, end }, (RangeEnd::Excluded, _) => { @@ -1076,7 +1076,12 @@ impl<'tcx> PatternFoldable<'tcx> for PatternKind<'tcx> { } } -pub fn compare_const_vals(a: &ConstVal, b: &ConstVal, ty: Ty) -> Option { +pub fn compare_const_vals<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + a: &ConstVal, + b: &ConstVal, + ty: Ty<'tcx>, +) -> Option { use rustc_const_math::ConstFloat; trace!("compare_const_vals: {:?}, {:?}", a, b); use rustc::mir::interpret::{Value, PrimVal}; @@ -1096,7 +1101,11 @@ pub fn compare_const_vals(a: &ConstVal, b: &ConstVal, ty: Ty) -> Option Some((a as i128).cmp(&(b as i128))), + ty::TyInt(_) => { + let a = interpret::sign_extend(tcx, a, ty).expect("layout error for TyInt"); + let b = interpret::sign_extend(tcx, b, ty).expect("layout error for TyInt"); + Some((a as i128).cmp(&(b as i128))) + }, _ => Some(a.cmp(&b)), } }, diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 03785f9623b..c5ff14e6069 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -1679,21 +1679,11 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M } pub fn sign_extend(&self, value: u128, ty: Ty<'tcx>) -> EvalResult<'tcx, u128> { - let layout = self.layout_of(ty)?; - let size = layout.size.bits(); - assert!(layout.abi.is_signed()); - // sign extend - let amt = 128 - size; - // shift the unsigned value to the left - // and back to the right as signed (essentially fills with FF on the left) - Ok((((value << amt) as i128) >> amt) as u128) + super::sign_extend(self.tcx.tcx, value, ty) } pub fn truncate(&self, value: u128, ty: Ty<'tcx>) -> EvalResult<'tcx, u128> { - let size = self.layout_of(ty)?.size.bits(); - let amt = 128 - size; - // truncate (shift left to drop out leftover values, shift right to fill with zeroes) - Ok((value << amt) >> amt) + super::truncate(self.tcx.tcx, value, ty) } } diff --git a/src/librustc_mir/interpret/mod.rs b/src/librustc_mir/interpret/mod.rs index ae6337d82c3..147db3bdc0e 100644 --- a/src/librustc_mir/interpret/mod.rs +++ b/src/librustc_mir/interpret/mod.rs @@ -31,3 +31,27 @@ pub use self::const_eval::{ pub use self::machine::Machine; pub use self::memory::{write_target_uint, write_target_int, read_target_uint}; + +use rustc::mir::interpret::{EvalResult, EvalErrorKind}; +use rustc::ty::{Ty, TyCtxt, ParamEnv}; + +pub fn sign_extend<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, value: u128, ty: Ty<'tcx>) -> EvalResult<'tcx, u128> { + let param_env = ParamEnv::empty(); + let layout = tcx.layout_of(param_env.and(ty)).map_err(|layout| EvalErrorKind::Layout(layout))?; + let size = layout.size.bits(); + assert!(layout.abi.is_signed()); + // sign extend + let amt = 128 - size; + // shift the unsigned value to the left + // and back to the right as signed (essentially fills with FF on the left) + Ok((((value << amt) as i128) >> amt) as u128) +} + +pub fn truncate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, value: u128, ty: Ty<'tcx>) -> EvalResult<'tcx, u128> { + let param_env = ParamEnv::empty(); + let layout = tcx.layout_of(param_env.and(ty)).map_err(|layout| EvalErrorKind::Layout(layout))?; + let size = layout.size.bits(); + let amt = 128 - size; + // truncate (shift left to drop out leftover values, shift right to fill with zeroes) + Ok((value << amt) >> amt) +} diff --git a/src/test/ui/const-eval/const_signed_pat.rs b/src/test/ui/const-eval/const_signed_pat.rs new file mode 100644 index 00000000000..f53d6f3fa0a --- /dev/null +++ b/src/test/ui/const-eval/const_signed_pat.rs @@ -0,0 +1,19 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-pass + +fn main() { + const MIN: i8 = -5; + match 5i8 { + MIN...-1 => {}, + _ => {}, + } +}