Skip to content

Commit

Permalink
Auto merge of #49210 - oli-obk:pango_crash, r=eddyb
Browse files Browse the repository at this point in the history
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
  • Loading branch information
bors committed Mar 22, 2018
2 parents 5092c6b + b272749 commit 52f7e88
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 38 deletions.
8 changes: 7 additions & 1 deletion src/librustc/ty/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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; }
}
Expand Down
23 changes: 5 additions & 18 deletions src/librustc/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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),
Expand Down
46 changes: 27 additions & 19 deletions src/librustc/ty/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
}
}
}
Expand All @@ -64,38 +72,38 @@ 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 {
min + (n - (max - val) - 1)
} 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
};
Expand Down
27 changes: 27 additions & 0 deletions src/test/run-pass/ctfe/signed_enum_discr.rs
Original file line number Diff line number Diff line change
@@ -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 => {},
_ => {}
}
}

0 comments on commit 52f7e88

Please sign in to comment.