Auto merge of #49210 - oli-obk:pango_crash, r=eddyb

Fix the conversion between bit representations and i128 representations

fixes #49181

the `Discr` type now encodes the bit representation instead of `i128` or `u128` casted to `u128`.

r? @eddyb
This commit is contained in:
bors 2018-03-22 20:02:14 +00:00
commit 52f7e8836c
4 changed files with 66 additions and 38 deletions

View file

@ -1544,11 +1544,17 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
}
let (mut min, mut max) = (i128::max_value(), i128::min_value());
let discr_type = def.repr.discr_type();
let bits = Integer::from_attr(tcx, discr_type).size().bits();
for (i, discr) in def.discriminants(tcx).enumerate() {
if variants[i].iter().any(|f| f.abi == Abi::Uninhabited) {
continue;
}
let x = discr.val as i128;
let mut x = discr.val as i128;
if discr_type.is_signed() {
// sign extend the raw representation to be an i128
x = (x << (128 - bits)) >> (128 - bits);
}
if x < min { min = x; }
if x > max { max = x; }
}

View file

@ -1887,7 +1887,6 @@ impl<'a, 'gcx, 'tcx> AdtDef {
) -> Option<Discr<'tcx>> {
let param_env = ParamEnv::empty();
let repr_type = self.repr.discr_type();
let bit_size = layout::Integer::from_attr(tcx, repr_type).size().bits();
let substs = Substs::identity_for_item(tcx.global_tcx(), expr_did);
let instance = ty::Instance::new(expr_did, substs);
let cid = GlobalId {
@ -1897,25 +1896,13 @@ impl<'a, 'gcx, 'tcx> AdtDef {
match tcx.const_eval(param_env.and(cid)) {
Ok(&ty::Const {
val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))),
..
ty,
}) => {
trace!("discriminants: {} ({:?})", b, repr_type);
let ty = repr_type.to_ty(tcx);
if repr_type.is_signed() {
let val = b as i128;
// sign extend to i128
let amt = 128 - bit_size;
let val = (val << amt) >> amt;
Some(Discr {
val: val as u128,
ty,
})
} else {
Some(Discr {
val: b,
ty,
})
}
Some(Discr {
val: b,
ty,
})
},
Ok(&ty::Const {
val: ConstVal::Value(other),

View file

@ -39,16 +39,24 @@ use syntax_pos::{Span, DUMMY_SP};
#[derive(Copy, Clone, Debug)]
pub struct Discr<'tcx> {
/// bit representation of the discriminant, so `-128i8` is `0xFF_u128`
pub val: u128,
pub ty: Ty<'tcx>
}
impl<'tcx> fmt::Display for Discr<'tcx> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
if self.ty.is_signed() {
write!(fmt, "{}", self.val as i128)
} else {
write!(fmt, "{}", self.val)
match self.ty.sty {
ty::TyInt(ity) => {
let bits = ty::tls::with(|tcx| {
Integer::from_attr(tcx, SignedInt(ity)).size().bits()
});
let x = self.val as i128;
// sign extend the raw representation to be an i128
let x = (x << (128 - bits)) >> (128 - bits);
write!(fmt, "{}", x)
},
_ => write!(fmt, "{}", self.val),
}
}
}
@ -64,15 +72,18 @@ impl<'tcx> Discr<'tcx> {
TyUint(uty) => (Integer::from_attr(tcx, UnsignedInt(uty)), false),
_ => bug!("non integer discriminant"),
};
let bit_size = int.size().bits();
let amt = 128 - bit_size;
if signed {
let (min, max) = match int {
Integer::I8 => (i8::min_value() as i128, i8::max_value() as i128),
Integer::I16 => (i16::min_value() as i128, i16::max_value() as i128),
Integer::I32 => (i32::min_value() as i128, i32::max_value() as i128),
Integer::I64 => (i64::min_value() as i128, i64::max_value() as i128),
Integer::I128 => (i128::min_value(), i128::max_value()),
let sext = |u| {
let i = u as i128;
(i << amt) >> amt
};
let val = self.val as i128;
let min = sext(1_u128 << (bit_size - 1));
let max = i128::max_value() >> amt;
let val = sext(self.val);
assert!(n < (i128::max_value() as u128));
let n = n as i128;
let oflo = val > max - n;
let val = if oflo {
@ -80,22 +91,19 @@ impl<'tcx> Discr<'tcx> {
} else {
val + n
};
// zero the upper bits
let val = val as u128;
let val = (val << amt) >> amt;
(Self {
val: val as u128,
ty: self.ty,
}, oflo)
} else {
let (min, max) = match int {
Integer::I8 => (u8::min_value() as u128, u8::max_value() as u128),
Integer::I16 => (u16::min_value() as u128, u16::max_value() as u128),
Integer::I32 => (u32::min_value() as u128, u32::max_value() as u128),
Integer::I64 => (u64::min_value() as u128, u64::max_value() as u128),
Integer::I128 => (u128::min_value(), u128::max_value()),
};
let max = u128::max_value() >> amt;
let val = self.val;
let oflo = val > max - n;
let val = if oflo {
min + (n - (max - val) - 1)
n - (max - val) - 1
} else {
val + n
};

View file

@ -0,0 +1,27 @@
// 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.
// https://github.com/rust-lang/rust/issues/49181
#[derive(Eq, PartialEq)]
#[repr(i8)]
pub enum A {
B = -1,
C = 1,
}
pub const D: A = A::B;
fn main() {
match A::C {
D => {},
_ => {}
}
}