Sign extend constants in range patterns
This commit is contained in:
parent
883bf4ba2e
commit
b22c9c01fb
@ -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<bool, ErrorReported> {
|
||||
fn constructor_covered_by_range<'a, 'tcx>(
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
ctor: &Constructor,
|
||||
from: &ConstVal, to: &ConstVal,
|
||||
end: RangeEnd,
|
||||
ty: Ty<'tcx>,
|
||||
) -> Result<bool, ErrorReported> {
|
||||
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![]),
|
||||
|
@ -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<Ordering> {
|
||||
pub fn compare_const_vals<'a, 'tcx>(
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
a: &ConstVal,
|
||||
b: &ConstVal,
|
||||
ty: Ty<'tcx>,
|
||||
) -> Option<Ordering> {
|
||||
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<Ordering
|
||||
// FIXME(oli-obk): report cmp errors?
|
||||
l.try_cmp(r).ok()
|
||||
},
|
||||
ty::TyInt(_) => 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)),
|
||||
}
|
||||
},
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
19
src/test/ui/const-eval/const_signed_pat.rs
Normal file
19
src/test/ui/const-eval/const_signed_pat.rs
Normal file
@ -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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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 => {},
|
||||
_ => {},
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user