Auto merge of #39456 - nagisa:mir-switchint-everywhere, r=nikomatsakis
[MIR] SwitchInt Everywhere Something I've been meaning to do for a very long while. This PR essentially gets rid of 3 kinds of conditional branching and only keeps the most general one - `SwitchInt`. Primary benefits are such that dealing with MIR now does not involve dealing with 3 different ways to do conditional control flow. On the other hand, constructing a `SwitchInt` currently requires more code than what previously was necessary to build an equivalent `If` terminator. Something trivially "fixable" with some constructor methods somewhere (MIR needs stuff like that badly in general). Some timings (tl;dr: slightly faster^1 (unexpected), but also uses slightly more memory at peak (expected)): ^1: Not sure if the speed benefits are because of LLVM liking the generated code better or the compiler itself getting compiled better. Either way, its a net benefit. The CORE and SYNTAX timings done for compilation without optimisation. ``` AFTER: Building stage1 std artifacts (x86_64-unknown-linux-gnu -> x86_64-unknown-linux-gnu) Finished release [optimized] target(s) in 31.50 secs Finished release [optimized] target(s) in 31.42 secs Building stage1 compiler artifacts (x86_64-unknown-linux-gnu -> x86_64-unknown-linux-gnu) Finished release [optimized] target(s) in 439.56 secs Finished release [optimized] target(s) in 435.15 secs CORE: 99% (24.81 real, 0.13 kernel, 24.57 user); 358536k resident CORE: 99% (24.56 real, 0.15 kernel, 24.36 user); 359168k resident SYNTAX: 99% (49.98 real, 0.48 kernel, 49.42 user); 653416k resident SYNTAX: 99% (50.07 real, 0.58 kernel, 49.43 user); 653604k resident BEFORE: Building stage1 std artifacts (x86_64-unknown-linux-gnu -> x86_64-unknown-linux-gnu) Finished release [optimized] target(s) in 31.84 secs Building stage1 compiler artifacts (x86_64-unknown-linux-gnu -> x86_64-unknown-linux-gnu) Finished release [optimized] target(s) in 451.17 secs CORE: 99% (24.66 real, 0.20 kernel, 24.38 user); 351096k resident CORE: 99% (24.36 real, 0.17 kernel, 24.18 user); 352284k resident SYNTAX: 99% (52.24 real, 0.56 kernel, 51.66 user); 645544k resident SYNTAX: 99% (51.55 real, 0.48 kernel, 50.99 user); 646428k resident ``` cc @nikomatsakis @eddyb
This commit is contained in:
commit
05a7f25cc4
|
@ -14,6 +14,7 @@ use std::rc::Rc;
|
||||||
use hir::def_id::DefId;
|
use hir::def_id::DefId;
|
||||||
use rustc_const_math::*;
|
use rustc_const_math::*;
|
||||||
use self::ConstVal::*;
|
use self::ConstVal::*;
|
||||||
|
pub use rustc_const_math::ConstInt;
|
||||||
|
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
|
@ -48,4 +49,14 @@ impl ConstVal {
|
||||||
Char(..) => "char",
|
Char(..) => "char",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn to_const_int(&self) -> Option<ConstInt> {
|
||||||
|
match *self {
|
||||||
|
ConstVal::Integral(i) => Some(i),
|
||||||
|
ConstVal::Bool(true) => Some(ConstInt::Infer(1)),
|
||||||
|
ConstVal::Bool(false) => Some(ConstInt::Infer(0)),
|
||||||
|
ConstVal::Char(ch) => Some(ConstInt::U32(ch as u32)),
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -453,36 +453,30 @@ pub enum TerminatorKind<'tcx> {
|
||||||
target: BasicBlock,
|
target: BasicBlock,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// jump to branch 0 if this lvalue evaluates to true
|
|
||||||
If {
|
|
||||||
cond: Operand<'tcx>,
|
|
||||||
targets: (BasicBlock, BasicBlock),
|
|
||||||
},
|
|
||||||
|
|
||||||
/// lvalue evaluates to some enum; jump depending on the branch
|
|
||||||
Switch {
|
|
||||||
discr: Lvalue<'tcx>,
|
|
||||||
adt_def: &'tcx AdtDef,
|
|
||||||
targets: Vec<BasicBlock>,
|
|
||||||
},
|
|
||||||
|
|
||||||
/// operand evaluates to an integer; jump depending on its value
|
/// operand evaluates to an integer; jump depending on its value
|
||||||
/// to one of the targets, and otherwise fallback to `otherwise`
|
/// to one of the targets, and otherwise fallback to `otherwise`
|
||||||
SwitchInt {
|
SwitchInt {
|
||||||
/// discriminant value being tested
|
/// discriminant value being tested
|
||||||
discr: Lvalue<'tcx>,
|
discr: Operand<'tcx>,
|
||||||
|
|
||||||
/// type of value being tested
|
/// type of value being tested
|
||||||
switch_ty: Ty<'tcx>,
|
switch_ty: Ty<'tcx>,
|
||||||
|
|
||||||
/// Possible values. The locations to branch to in each case
|
/// Possible values. The locations to branch to in each case
|
||||||
/// are found in the corresponding indices from the `targets` vector.
|
/// are found in the corresponding indices from the `targets` vector.
|
||||||
values: Vec<ConstVal>,
|
values: Cow<'tcx, [ConstInt]>,
|
||||||
|
|
||||||
/// Possible branch sites. The length of this vector should be
|
/// Possible branch sites. The last element of this vector is used
|
||||||
/// equal to the length of the `values` vector plus 1 -- the
|
/// for the otherwise branch, so values.len() == targets.len() + 1
|
||||||
/// extra item is the block to branch to if none of the values
|
/// should hold.
|
||||||
/// fit.
|
// This invariant is quite non-obvious and also could be improved.
|
||||||
|
// One way to make this invariant is to have something like this instead:
|
||||||
|
//
|
||||||
|
// branches: Vec<(ConstInt, BasicBlock)>,
|
||||||
|
// otherwise: Option<BasicBlock> // exhaustive if None
|
||||||
|
//
|
||||||
|
// However we’ve decided to keep this as-is until we figure a case
|
||||||
|
// where some other approach seems to be strictly better than other.
|
||||||
targets: Vec<BasicBlock>,
|
targets: Vec<BasicBlock>,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -546,12 +540,21 @@ impl<'tcx> Terminator<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> TerminatorKind<'tcx> {
|
impl<'tcx> TerminatorKind<'tcx> {
|
||||||
|
pub fn if_<'a, 'gcx>(tcx: ty::TyCtxt<'a, 'gcx, 'tcx>, cond: Operand<'tcx>,
|
||||||
|
t: BasicBlock, f: BasicBlock) -> TerminatorKind<'tcx> {
|
||||||
|
static BOOL_SWITCH_FALSE: &'static [ConstInt] = &[ConstInt::Infer(0)];
|
||||||
|
TerminatorKind::SwitchInt {
|
||||||
|
discr: cond,
|
||||||
|
switch_ty: tcx.types.bool,
|
||||||
|
values: From::from(BOOL_SWITCH_FALSE),
|
||||||
|
targets: vec![f, t],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn successors(&self) -> Cow<[BasicBlock]> {
|
pub fn successors(&self) -> Cow<[BasicBlock]> {
|
||||||
use self::TerminatorKind::*;
|
use self::TerminatorKind::*;
|
||||||
match *self {
|
match *self {
|
||||||
Goto { target: ref b } => slice::ref_slice(b).into_cow(),
|
Goto { target: ref b } => slice::ref_slice(b).into_cow(),
|
||||||
If { targets: (b1, b2), .. } => vec![b1, b2].into_cow(),
|
|
||||||
Switch { targets: ref b, .. } => b[..].into_cow(),
|
|
||||||
SwitchInt { targets: ref b, .. } => b[..].into_cow(),
|
SwitchInt { targets: ref b, .. } => b[..].into_cow(),
|
||||||
Resume => (&[]).into_cow(),
|
Resume => (&[]).into_cow(),
|
||||||
Return => (&[]).into_cow(),
|
Return => (&[]).into_cow(),
|
||||||
|
@ -580,8 +583,6 @@ impl<'tcx> TerminatorKind<'tcx> {
|
||||||
use self::TerminatorKind::*;
|
use self::TerminatorKind::*;
|
||||||
match *self {
|
match *self {
|
||||||
Goto { target: ref mut b } => vec![b],
|
Goto { target: ref mut b } => vec![b],
|
||||||
If { targets: (ref mut b1, ref mut b2), .. } => vec![b1, b2],
|
|
||||||
Switch { targets: ref mut b, .. } => b.iter_mut().collect(),
|
|
||||||
SwitchInt { targets: ref mut b, .. } => b.iter_mut().collect(),
|
SwitchInt { targets: ref mut b, .. } => b.iter_mut().collect(),
|
||||||
Resume => Vec::new(),
|
Resume => Vec::new(),
|
||||||
Return => Vec::new(),
|
Return => Vec::new(),
|
||||||
|
@ -659,8 +660,6 @@ impl<'tcx> TerminatorKind<'tcx> {
|
||||||
use self::TerminatorKind::*;
|
use self::TerminatorKind::*;
|
||||||
match *self {
|
match *self {
|
||||||
Goto { .. } => write!(fmt, "goto"),
|
Goto { .. } => write!(fmt, "goto"),
|
||||||
If { cond: ref lv, .. } => write!(fmt, "if({:?})", lv),
|
|
||||||
Switch { discr: ref lv, .. } => write!(fmt, "switch({:?})", lv),
|
|
||||||
SwitchInt { discr: ref lv, .. } => write!(fmt, "switchInt({:?})", lv),
|
SwitchInt { discr: ref lv, .. } => write!(fmt, "switchInt({:?})", lv),
|
||||||
Return => write!(fmt, "return"),
|
Return => write!(fmt, "return"),
|
||||||
Resume => write!(fmt, "resume"),
|
Resume => write!(fmt, "resume"),
|
||||||
|
@ -710,18 +709,11 @@ impl<'tcx> TerminatorKind<'tcx> {
|
||||||
match *self {
|
match *self {
|
||||||
Return | Resume | Unreachable => vec![],
|
Return | Resume | Unreachable => vec![],
|
||||||
Goto { .. } => vec!["".into()],
|
Goto { .. } => vec!["".into()],
|
||||||
If { .. } => vec!["true".into(), "false".into()],
|
|
||||||
Switch { ref adt_def, .. } => {
|
|
||||||
adt_def.variants
|
|
||||||
.iter()
|
|
||||||
.map(|variant| variant.name.to_string().into())
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
SwitchInt { ref values, .. } => {
|
SwitchInt { ref values, .. } => {
|
||||||
values.iter()
|
values.iter()
|
||||||
.map(|const_val| {
|
.map(|const_val| {
|
||||||
let mut buf = String::new();
|
let mut buf = String::new();
|
||||||
fmt_const_val(&mut buf, const_val).unwrap();
|
fmt_const_val(&mut buf, &ConstVal::Integral(*const_val)).unwrap();
|
||||||
buf.into()
|
buf.into()
|
||||||
})
|
})
|
||||||
.chain(iter::once(String::from("otherwise").into()))
|
.chain(iter::once(String::from("otherwise").into()))
|
||||||
|
@ -997,6 +989,12 @@ pub enum Rvalue<'tcx> {
|
||||||
|
|
||||||
UnaryOp(UnOp, Operand<'tcx>),
|
UnaryOp(UnOp, Operand<'tcx>),
|
||||||
|
|
||||||
|
/// Read the discriminant of an ADT.
|
||||||
|
///
|
||||||
|
/// Undefined (i.e. no effort is made to make it defined, but there’s no reason why it cannot
|
||||||
|
/// be defined to return, say, a 0) if ADT is not an enum.
|
||||||
|
Discriminant(Lvalue<'tcx>),
|
||||||
|
|
||||||
/// Creates an *uninitialized* Box
|
/// Creates an *uninitialized* Box
|
||||||
Box(Ty<'tcx>),
|
Box(Ty<'tcx>),
|
||||||
|
|
||||||
|
@ -1111,6 +1109,7 @@ impl<'tcx> Debug for Rvalue<'tcx> {
|
||||||
write!(fmt, "Checked{:?}({:?}, {:?})", op, a, b)
|
write!(fmt, "Checked{:?}({:?}, {:?})", op, a, b)
|
||||||
}
|
}
|
||||||
UnaryOp(ref op, ref a) => write!(fmt, "{:?}({:?})", op, a),
|
UnaryOp(ref op, ref a) => write!(fmt, "{:?}({:?})", op, a),
|
||||||
|
Discriminant(ref lval) => write!(fmt, "discriminant({:?})", lval),
|
||||||
Box(ref t) => write!(fmt, "Box({:?})", t),
|
Box(ref t) => write!(fmt, "Box({:?})", t),
|
||||||
InlineAsm { ref asm, ref outputs, ref inputs } => {
|
InlineAsm { ref asm, ref outputs, ref inputs } => {
|
||||||
write!(fmt, "asm!({:?} : {:?} : {:?})", asm, outputs, inputs)
|
write!(fmt, "asm!({:?} : {:?} : {:?})", asm, outputs, inputs)
|
||||||
|
|
|
@ -18,6 +18,7 @@ use ty::subst::{Subst, Substs};
|
||||||
use ty::{self, AdtDef, Ty, TyCtxt};
|
use ty::{self, AdtDef, Ty, TyCtxt};
|
||||||
use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
|
use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
|
||||||
use hir;
|
use hir;
|
||||||
|
use ty::util::IntTypeExt;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub enum LvalueTy<'tcx> {
|
pub enum LvalueTy<'tcx> {
|
||||||
|
@ -135,15 +136,15 @@ impl<'tcx> Lvalue<'tcx> {
|
||||||
impl<'tcx> Rvalue<'tcx> {
|
impl<'tcx> Rvalue<'tcx> {
|
||||||
pub fn ty<'a, 'gcx>(&self, mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<Ty<'tcx>>
|
pub fn ty<'a, 'gcx>(&self, mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<Ty<'tcx>>
|
||||||
{
|
{
|
||||||
match self {
|
match *self {
|
||||||
&Rvalue::Use(ref operand) => Some(operand.ty(mir, tcx)),
|
Rvalue::Use(ref operand) => Some(operand.ty(mir, tcx)),
|
||||||
&Rvalue::Repeat(ref operand, ref count) => {
|
Rvalue::Repeat(ref operand, ref count) => {
|
||||||
let op_ty = operand.ty(mir, tcx);
|
let op_ty = operand.ty(mir, tcx);
|
||||||
let count = count.value.as_u64(tcx.sess.target.uint_type);
|
let count = count.value.as_u64(tcx.sess.target.uint_type);
|
||||||
assert_eq!(count as usize as u64, count);
|
assert_eq!(count as usize as u64, count);
|
||||||
Some(tcx.mk_array(op_ty, count as usize))
|
Some(tcx.mk_array(op_ty, count as usize))
|
||||||
}
|
}
|
||||||
&Rvalue::Ref(reg, bk, ref lv) => {
|
Rvalue::Ref(reg, bk, ref lv) => {
|
||||||
let lv_ty = lv.ty(mir, tcx).to_ty(tcx);
|
let lv_ty = lv.ty(mir, tcx).to_ty(tcx);
|
||||||
Some(tcx.mk_ref(reg,
|
Some(tcx.mk_ref(reg,
|
||||||
ty::TypeAndMut {
|
ty::TypeAndMut {
|
||||||
|
@ -152,27 +153,37 @@ impl<'tcx> Rvalue<'tcx> {
|
||||||
}
|
}
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
&Rvalue::Len(..) => Some(tcx.types.usize),
|
Rvalue::Len(..) => Some(tcx.types.usize),
|
||||||
&Rvalue::Cast(.., ty) => Some(ty),
|
Rvalue::Cast(.., ty) => Some(ty),
|
||||||
&Rvalue::BinaryOp(op, ref lhs, ref rhs) => {
|
Rvalue::BinaryOp(op, ref lhs, ref rhs) => {
|
||||||
let lhs_ty = lhs.ty(mir, tcx);
|
let lhs_ty = lhs.ty(mir, tcx);
|
||||||
let rhs_ty = rhs.ty(mir, tcx);
|
let rhs_ty = rhs.ty(mir, tcx);
|
||||||
Some(op.ty(tcx, lhs_ty, rhs_ty))
|
Some(op.ty(tcx, lhs_ty, rhs_ty))
|
||||||
}
|
}
|
||||||
&Rvalue::CheckedBinaryOp(op, ref lhs, ref rhs) => {
|
Rvalue::CheckedBinaryOp(op, ref lhs, ref rhs) => {
|
||||||
let lhs_ty = lhs.ty(mir, tcx);
|
let lhs_ty = lhs.ty(mir, tcx);
|
||||||
let rhs_ty = rhs.ty(mir, tcx);
|
let rhs_ty = rhs.ty(mir, tcx);
|
||||||
let ty = op.ty(tcx, lhs_ty, rhs_ty);
|
let ty = op.ty(tcx, lhs_ty, rhs_ty);
|
||||||
let ty = tcx.intern_tup(&[ty, tcx.types.bool], false);
|
let ty = tcx.intern_tup(&[ty, tcx.types.bool], false);
|
||||||
Some(ty)
|
Some(ty)
|
||||||
}
|
}
|
||||||
&Rvalue::UnaryOp(_, ref operand) => {
|
Rvalue::UnaryOp(_, ref operand) => {
|
||||||
Some(operand.ty(mir, tcx))
|
Some(operand.ty(mir, tcx))
|
||||||
}
|
}
|
||||||
&Rvalue::Box(t) => {
|
Rvalue::Discriminant(ref lval) => {
|
||||||
|
let ty = lval.ty(mir, tcx).to_ty(tcx);
|
||||||
|
if let ty::TyAdt(adt_def, _) = ty.sty {
|
||||||
|
Some(adt_def.discr_ty.to_ty(tcx))
|
||||||
|
} else {
|
||||||
|
// Undefined behaviour, bug for now; may want to return something for
|
||||||
|
// the `discriminant` intrinsic later.
|
||||||
|
bug!("Rvalue::Discriminant on Lvalue of type {:?}", ty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Rvalue::Box(t) => {
|
||||||
Some(tcx.mk_box(t))
|
Some(tcx.mk_box(t))
|
||||||
}
|
}
|
||||||
&Rvalue::Aggregate(ref ak, ref ops) => {
|
Rvalue::Aggregate(ref ak, ref ops) => {
|
||||||
match *ak {
|
match *ak {
|
||||||
AggregateKind::Array => {
|
AggregateKind::Array => {
|
||||||
if let Some(operand) = ops.get(0) {
|
if let Some(operand) = ops.get(0) {
|
||||||
|
@ -196,7 +207,7 @@ impl<'tcx> Rvalue<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&Rvalue::InlineAsm { .. } => None
|
Rvalue::InlineAsm { .. } => None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,6 @@ use ty::subst::Substs;
|
||||||
use ty::{ClosureSubsts, Region, Ty};
|
use ty::{ClosureSubsts, Region, Ty};
|
||||||
use mir::*;
|
use mir::*;
|
||||||
use rustc_const_math::ConstUsize;
|
use rustc_const_math::ConstUsize;
|
||||||
use rustc_data_structures::tuple_slice::TupleSlice;
|
|
||||||
use rustc_data_structures::indexed_vec::Idx;
|
use rustc_data_structures::indexed_vec::Idx;
|
||||||
use syntax_pos::Span;
|
use syntax_pos::Span;
|
||||||
|
|
||||||
|
@ -224,6 +223,12 @@ macro_rules! make_mir_visitor {
|
||||||
self.super_const_val(const_val);
|
self.super_const_val(const_val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn visit_const_int(&mut self,
|
||||||
|
const_int: &ConstInt,
|
||||||
|
_: Location) {
|
||||||
|
self.super_const_int(const_int);
|
||||||
|
}
|
||||||
|
|
||||||
fn visit_const_usize(&mut self,
|
fn visit_const_usize(&mut self,
|
||||||
const_usize: & $($mutability)* ConstUsize,
|
const_usize: & $($mutability)* ConstUsize,
|
||||||
_: Location) {
|
_: Location) {
|
||||||
|
@ -363,31 +368,14 @@ macro_rules! make_mir_visitor {
|
||||||
self.visit_branch(block, target);
|
self.visit_branch(block, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
TerminatorKind::If { ref $($mutability)* cond,
|
|
||||||
ref $($mutability)* targets } => {
|
|
||||||
self.visit_operand(cond, source_location);
|
|
||||||
for &target in targets.as_slice() {
|
|
||||||
self.visit_branch(block, target);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TerminatorKind::Switch { ref $($mutability)* discr,
|
|
||||||
adt_def: _,
|
|
||||||
ref targets } => {
|
|
||||||
self.visit_lvalue(discr, LvalueContext::Inspect, source_location);
|
|
||||||
for &target in targets {
|
|
||||||
self.visit_branch(block, target);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TerminatorKind::SwitchInt { ref $($mutability)* discr,
|
TerminatorKind::SwitchInt { ref $($mutability)* discr,
|
||||||
ref $($mutability)* switch_ty,
|
ref $($mutability)* switch_ty,
|
||||||
ref $($mutability)* values,
|
ref values,
|
||||||
ref targets } => {
|
ref targets } => {
|
||||||
self.visit_lvalue(discr, LvalueContext::Inspect, source_location);
|
self.visit_operand(discr, source_location);
|
||||||
self.visit_ty(switch_ty);
|
self.visit_ty(switch_ty);
|
||||||
for value in values {
|
for value in &values[..] {
|
||||||
self.visit_const_val(value, source_location);
|
self.visit_const_int(value, source_location);
|
||||||
}
|
}
|
||||||
for &target in targets {
|
for &target in targets {
|
||||||
self.visit_branch(block, target);
|
self.visit_branch(block, target);
|
||||||
|
@ -506,6 +494,10 @@ macro_rules! make_mir_visitor {
|
||||||
self.visit_operand(op, location);
|
self.visit_operand(op, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Rvalue::Discriminant(ref $($mutability)* lvalue) => {
|
||||||
|
self.visit_lvalue(lvalue, LvalueContext::Inspect, location);
|
||||||
|
}
|
||||||
|
|
||||||
Rvalue::Box(ref $($mutability)* ty) => {
|
Rvalue::Box(ref $($mutability)* ty) => {
|
||||||
self.visit_ty(ty);
|
self.visit_ty(ty);
|
||||||
}
|
}
|
||||||
|
@ -712,10 +704,13 @@ macro_rules! make_mir_visitor {
|
||||||
_substs: & $($mutability)* ClosureSubsts<'tcx>) {
|
_substs: & $($mutability)* ClosureSubsts<'tcx>) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn super_const_val(&mut self, _substs: & $($mutability)* ConstVal) {
|
fn super_const_val(&mut self, _const_val: & $($mutability)* ConstVal) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn super_const_usize(&mut self, _substs: & $($mutability)* ConstUsize) {
|
fn super_const_int(&mut self, _const_int: &ConstInt) {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn super_const_usize(&mut self, _const_usize: & $($mutability)* ConstUsize) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convenience methods
|
// Convenience methods
|
||||||
|
|
|
@ -673,10 +673,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||||
pub fn alloc_adt_def(self,
|
pub fn alloc_adt_def(self,
|
||||||
did: DefId,
|
did: DefId,
|
||||||
kind: AdtKind,
|
kind: AdtKind,
|
||||||
|
discr_ty: Option<attr::IntType>,
|
||||||
variants: Vec<ty::VariantDef>,
|
variants: Vec<ty::VariantDef>,
|
||||||
repr: ReprOptions)
|
repr: ReprOptions)
|
||||||
-> &'gcx ty::AdtDef {
|
-> &'gcx ty::AdtDef {
|
||||||
let def = ty::AdtDef::new(self, did, kind, variants, repr);
|
let discr_ty = discr_ty.unwrap_or(attr::UnsignedInt(ast::UintTy::U8));
|
||||||
|
let def = ty::AdtDef::new(self, did, kind, discr_ty, variants, repr);
|
||||||
self.global_arenas.adt_def.alloc(def)
|
self.global_arenas.adt_def.alloc(def)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,6 @@ use ty::{self, Ty, TyCtxt, TypeFoldable, ReprOptions};
|
||||||
use syntax::ast::{FloatTy, IntTy, UintTy};
|
use syntax::ast::{FloatTy, IntTy, UintTy};
|
||||||
use syntax::attr;
|
use syntax::attr;
|
||||||
use syntax_pos::DUMMY_SP;
|
use syntax_pos::DUMMY_SP;
|
||||||
use rustc_const_math::ConstInt;
|
|
||||||
|
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
@ -1183,11 +1182,7 @@ impl<'a, 'gcx, 'tcx> Layout {
|
||||||
i64::min_value(),
|
i64::min_value(),
|
||||||
true);
|
true);
|
||||||
for v in &def.variants {
|
for v in &def.variants {
|
||||||
let x = match v.disr_val.erase_type() {
|
let x = v.disr_val as i128 as i64;
|
||||||
ConstInt::InferSigned(i) => i as i64,
|
|
||||||
ConstInt::Infer(i) => i as u64 as i64,
|
|
||||||
_ => bug!()
|
|
||||||
};
|
|
||||||
if x == 0 { non_zero = false; }
|
if x == 0 { non_zero = false; }
|
||||||
if x < min { min = x; }
|
if x < min { min = x; }
|
||||||
if x > max { max = x; }
|
if x > max { max = x; }
|
||||||
|
@ -1195,9 +1190,7 @@ impl<'a, 'gcx, 'tcx> Layout {
|
||||||
|
|
||||||
// FIXME: should handle i128? signed-value based impl is weird and hard to
|
// FIXME: should handle i128? signed-value based impl is weird and hard to
|
||||||
// grok.
|
// grok.
|
||||||
let (discr, signed) = Integer::repr_discr(tcx, ty, &def.repr,
|
let (discr, signed) = Integer::repr_discr(tcx, ty, &def.repr, min, max);
|
||||||
min,
|
|
||||||
max);
|
|
||||||
return success(CEnum {
|
return success(CEnum {
|
||||||
discr: discr,
|
discr: discr,
|
||||||
signed: signed,
|
signed: signed,
|
||||||
|
@ -1247,7 +1240,7 @@ impl<'a, 'gcx, 'tcx> Layout {
|
||||||
// non-empty body, explicit discriminants should have
|
// non-empty body, explicit discriminants should have
|
||||||
// been rejected by a checker before this point.
|
// been rejected by a checker before this point.
|
||||||
for (i, v) in def.variants.iter().enumerate() {
|
for (i, v) in def.variants.iter().enumerate() {
|
||||||
if i as u128 != v.disr_val.to_u128_unchecked() {
|
if i as u128 != v.disr_val {
|
||||||
bug!("non-C-like enum {} with specified discriminants",
|
bug!("non-C-like enum {} with specified discriminants",
|
||||||
tcx.item_path_str(def.did));
|
tcx.item_path_str(def.did));
|
||||||
}
|
}
|
||||||
|
@ -1315,7 +1308,6 @@ impl<'a, 'gcx, 'tcx> Layout {
|
||||||
let discr_max = (variants.len() - 1) as i64;
|
let discr_max = (variants.len() - 1) as i64;
|
||||||
assert!(discr_max >= 0);
|
assert!(discr_max >= 0);
|
||||||
let (min_ity, _) = Integer::repr_discr(tcx, ty, &def.repr, 0, discr_max);
|
let (min_ity, _) = Integer::repr_discr(tcx, ty, &def.repr, 0, discr_max);
|
||||||
|
|
||||||
let mut align = dl.aggregate_align;
|
let mut align = dl.aggregate_align;
|
||||||
let mut size = Size::from_bytes(0);
|
let mut size = Size::from_bytes(0);
|
||||||
|
|
||||||
|
@ -1356,6 +1348,23 @@ impl<'a, 'gcx, 'tcx> Layout {
|
||||||
return Err(LayoutError::SizeOverflow(ty));
|
return Err(LayoutError::SizeOverflow(ty));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let typeck_ity = Integer::from_attr(dl, def.discr_ty);
|
||||||
|
if typeck_ity < min_ity {
|
||||||
|
// It is a bug if Layout decided on a greater discriminant size than typeck for
|
||||||
|
// some reason at this point (based on values discriminant can take on). Mostly
|
||||||
|
// because this discriminant will be loaded, and then stored into variable of
|
||||||
|
// type calculated by typeck. Consider such case (a bug): typeck decided on
|
||||||
|
// byte-sized discriminant, but layout thinks we need a 16-bit to store all
|
||||||
|
// discriminant values. That would be a bug, because then, in trans, in order
|
||||||
|
// to store this 16-bit discriminant into 8-bit sized temporary some of the
|
||||||
|
// space necessary to represent would have to be discarded (or layout is wrong
|
||||||
|
// on thinking it needs 16 bits)
|
||||||
|
bug!("layout decided on a larger discriminant type ({:?}) than typeck ({:?})",
|
||||||
|
min_ity, typeck_ity);
|
||||||
|
// However, it is fine to make discr type however large (as an optimisation)
|
||||||
|
// after this point – we’ll just truncate the value we load in trans.
|
||||||
|
}
|
||||||
|
|
||||||
// Check to see if we should use a different type for the
|
// Check to see if we should use a different type for the
|
||||||
// discriminant. We can safely use a type with the same size
|
// discriminant. We can safely use a type with the same size
|
||||||
// as the alignment of the first field of each variant.
|
// as the alignment of the first field of each variant.
|
||||||
|
|
|
@ -45,7 +45,6 @@ use syntax::attr;
|
||||||
use syntax::symbol::{Symbol, InternedString};
|
use syntax::symbol::{Symbol, InternedString};
|
||||||
use syntax_pos::{DUMMY_SP, Span};
|
use syntax_pos::{DUMMY_SP, Span};
|
||||||
|
|
||||||
use rustc_const_math::ConstInt;
|
|
||||||
use rustc_data_structures::accumulate_vec::IntoIter as AccIntoIter;
|
use rustc_data_structures::accumulate_vec::IntoIter as AccIntoIter;
|
||||||
|
|
||||||
use hir;
|
use hir;
|
||||||
|
@ -96,7 +95,7 @@ mod flags;
|
||||||
mod structural_impls;
|
mod structural_impls;
|
||||||
mod sty;
|
mod sty;
|
||||||
|
|
||||||
pub type Disr = ConstInt;
|
pub type Disr = u128;
|
||||||
|
|
||||||
// Data types
|
// Data types
|
||||||
|
|
||||||
|
@ -1325,6 +1324,12 @@ pub struct FieldDef {
|
||||||
/// table.
|
/// table.
|
||||||
pub struct AdtDef {
|
pub struct AdtDef {
|
||||||
pub did: DefId,
|
pub did: DefId,
|
||||||
|
/// Type of the discriminant
|
||||||
|
///
|
||||||
|
/// Note, that this is the type specified in `repr()` or a default type of some sort, and might
|
||||||
|
/// not match the actual type that layout algorithm decides to use when translating this type
|
||||||
|
/// into LLVM. That being said, layout algorithm may not use a type larger than specified here.
|
||||||
|
pub discr_ty: attr::IntType,
|
||||||
pub variants: Vec<VariantDef>,
|
pub variants: Vec<VariantDef>,
|
||||||
destructor: Cell<Option<DefId>>,
|
destructor: Cell<Option<DefId>>,
|
||||||
flags: Cell<AdtFlags>,
|
flags: Cell<AdtFlags>,
|
||||||
|
@ -1387,6 +1392,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
|
||||||
fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||||
did: DefId,
|
did: DefId,
|
||||||
kind: AdtKind,
|
kind: AdtKind,
|
||||||
|
discr_ty: attr::IntType,
|
||||||
variants: Vec<VariantDef>,
|
variants: Vec<VariantDef>,
|
||||||
repr: ReprOptions) -> Self {
|
repr: ReprOptions) -> Self {
|
||||||
let mut flags = AdtFlags::NO_ADT_FLAGS;
|
let mut flags = AdtFlags::NO_ADT_FLAGS;
|
||||||
|
@ -1410,6 +1416,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
|
||||||
}
|
}
|
||||||
AdtDef {
|
AdtDef {
|
||||||
did: did,
|
did: did,
|
||||||
|
discr_ty: discr_ty,
|
||||||
variants: variants,
|
variants: variants,
|
||||||
flags: Cell::new(flags),
|
flags: Cell::new(flags),
|
||||||
destructor: Cell::new(None),
|
destructor: Cell::new(None),
|
||||||
|
|
|
@ -23,7 +23,6 @@ use ty::TypeVariants::*;
|
||||||
use util::nodemap::FxHashMap;
|
use util::nodemap::FxHashMap;
|
||||||
use middle::lang_items;
|
use middle::lang_items;
|
||||||
|
|
||||||
use rustc_const_math::{ConstInt, ConstIsize, ConstUsize};
|
|
||||||
use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult};
|
use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult};
|
||||||
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
@ -37,84 +36,20 @@ use syntax_pos::Span;
|
||||||
use hir;
|
use hir;
|
||||||
|
|
||||||
pub trait IntTypeExt {
|
pub trait IntTypeExt {
|
||||||
fn to_ty<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Ty<'tcx>;
|
fn to_ty<'a, 'gcx: 'a+'tcx, 'tcx: 'a>(self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx>;
|
||||||
fn disr_incr<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, val: Option<Disr>)
|
fn initial_discriminant<'a, 'tcx>(&self, _: TyCtxt<'a, 'tcx, 'tcx>) -> Disr;
|
||||||
-> Option<Disr>;
|
|
||||||
fn assert_ty_matches(&self, val: Disr);
|
|
||||||
fn initial_discriminant<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Disr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntTypeExt for attr::IntType {
|
impl IntTypeExt for attr::IntType {
|
||||||
fn to_ty<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Ty<'tcx> {
|
fn to_ty<'a, 'gcx: 'a+'tcx, 'tcx: 'a>(self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> {
|
||||||
match *self {
|
match self {
|
||||||
SignedInt(ast::IntTy::I8) => tcx.types.i8,
|
SignedInt(i) => tcx.mk_mach_int(i),
|
||||||
SignedInt(ast::IntTy::I16) => tcx.types.i16,
|
UnsignedInt(i) => tcx.mk_mach_uint(i),
|
||||||
SignedInt(ast::IntTy::I32) => tcx.types.i32,
|
|
||||||
SignedInt(ast::IntTy::I64) => tcx.types.i64,
|
|
||||||
SignedInt(ast::IntTy::I128) => tcx.types.i128,
|
|
||||||
SignedInt(ast::IntTy::Is) => tcx.types.isize,
|
|
||||||
UnsignedInt(ast::UintTy::U8) => tcx.types.u8,
|
|
||||||
UnsignedInt(ast::UintTy::U16) => tcx.types.u16,
|
|
||||||
UnsignedInt(ast::UintTy::U32) => tcx.types.u32,
|
|
||||||
UnsignedInt(ast::UintTy::U64) => tcx.types.u64,
|
|
||||||
UnsignedInt(ast::UintTy::U128) => tcx.types.u128,
|
|
||||||
UnsignedInt(ast::UintTy::Us) => tcx.types.usize,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn initial_discriminant<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Disr {
|
fn initial_discriminant<'a, 'tcx>(&self, _: TyCtxt<'a, 'tcx, 'tcx>) -> Disr {
|
||||||
match *self {
|
0
|
||||||
SignedInt(ast::IntTy::I8) => ConstInt::I8(0),
|
|
||||||
SignedInt(ast::IntTy::I16) => ConstInt::I16(0),
|
|
||||||
SignedInt(ast::IntTy::I32) => ConstInt::I32(0),
|
|
||||||
SignedInt(ast::IntTy::I64) => ConstInt::I64(0),
|
|
||||||
SignedInt(ast::IntTy::I128) => ConstInt::I128(0),
|
|
||||||
SignedInt(ast::IntTy::Is) => match tcx.sess.target.int_type {
|
|
||||||
ast::IntTy::I16 => ConstInt::Isize(ConstIsize::Is16(0)),
|
|
||||||
ast::IntTy::I32 => ConstInt::Isize(ConstIsize::Is32(0)),
|
|
||||||
ast::IntTy::I64 => ConstInt::Isize(ConstIsize::Is64(0)),
|
|
||||||
_ => bug!(),
|
|
||||||
},
|
|
||||||
UnsignedInt(ast::UintTy::U8) => ConstInt::U8(0),
|
|
||||||
UnsignedInt(ast::UintTy::U16) => ConstInt::U16(0),
|
|
||||||
UnsignedInt(ast::UintTy::U32) => ConstInt::U32(0),
|
|
||||||
UnsignedInt(ast::UintTy::U64) => ConstInt::U64(0),
|
|
||||||
UnsignedInt(ast::UintTy::U128) => ConstInt::U128(0),
|
|
||||||
UnsignedInt(ast::UintTy::Us) => match tcx.sess.target.uint_type {
|
|
||||||
ast::UintTy::U16 => ConstInt::Usize(ConstUsize::Us16(0)),
|
|
||||||
ast::UintTy::U32 => ConstInt::Usize(ConstUsize::Us32(0)),
|
|
||||||
ast::UintTy::U64 => ConstInt::Usize(ConstUsize::Us64(0)),
|
|
||||||
_ => bug!(),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn assert_ty_matches(&self, val: Disr) {
|
|
||||||
match (*self, val) {
|
|
||||||
(SignedInt(ast::IntTy::I8), ConstInt::I8(_)) => {},
|
|
||||||
(SignedInt(ast::IntTy::I16), ConstInt::I16(_)) => {},
|
|
||||||
(SignedInt(ast::IntTy::I32), ConstInt::I32(_)) => {},
|
|
||||||
(SignedInt(ast::IntTy::I64), ConstInt::I64(_)) => {},
|
|
||||||
(SignedInt(ast::IntTy::I128), ConstInt::I128(_)) => {},
|
|
||||||
(SignedInt(ast::IntTy::Is), ConstInt::Isize(_)) => {},
|
|
||||||
(UnsignedInt(ast::UintTy::U8), ConstInt::U8(_)) => {},
|
|
||||||
(UnsignedInt(ast::UintTy::U16), ConstInt::U16(_)) => {},
|
|
||||||
(UnsignedInt(ast::UintTy::U32), ConstInt::U32(_)) => {},
|
|
||||||
(UnsignedInt(ast::UintTy::U64), ConstInt::U64(_)) => {},
|
|
||||||
(UnsignedInt(ast::UintTy::U128), ConstInt::U128(_)) => {},
|
|
||||||
(UnsignedInt(ast::UintTy::Us), ConstInt::Usize(_)) => {},
|
|
||||||
_ => bug!("disr type mismatch: {:?} vs {:?}", self, val),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn disr_incr<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, val: Option<Disr>)
|
|
||||||
-> Option<Disr> {
|
|
||||||
if let Some(val) = val {
|
|
||||||
self.assert_ty_matches(val);
|
|
||||||
(val + ConstInt::Infer(1)).ok()
|
|
||||||
} else {
|
|
||||||
Some(self.initial_discriminant(tcx))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -454,11 +454,6 @@ impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D>
|
||||||
self.propagate_bits_into_entry_set_for(in_out, changed, target);
|
self.propagate_bits_into_entry_set_for(in_out, changed, target);
|
||||||
self.propagate_bits_into_entry_set_for(in_out, changed, unwind);
|
self.propagate_bits_into_entry_set_for(in_out, changed, unwind);
|
||||||
}
|
}
|
||||||
mir::TerminatorKind::If { ref targets, .. } => {
|
|
||||||
self.propagate_bits_into_entry_set_for(in_out, changed, &targets.0);
|
|
||||||
self.propagate_bits_into_entry_set_for(in_out, changed, &targets.1);
|
|
||||||
}
|
|
||||||
mir::TerminatorKind::Switch { ref targets, .. } |
|
|
||||||
mir::TerminatorKind::SwitchInt { ref targets, .. } => {
|
mir::TerminatorKind::SwitchInt { ref targets, .. } => {
|
||||||
for target in targets {
|
for target in targets {
|
||||||
self.propagate_bits_into_entry_set_for(in_out, changed, target);
|
self.propagate_bits_into_entry_set_for(in_out, changed, target);
|
||||||
|
|
|
@ -17,9 +17,10 @@ use super::{DropFlagState, MoveDataParamEnv};
|
||||||
use super::patch::MirPatch;
|
use super::patch::MirPatch;
|
||||||
use rustc::ty::{self, Ty, TyCtxt};
|
use rustc::ty::{self, Ty, TyCtxt};
|
||||||
use rustc::ty::subst::{Kind, Subst, Substs};
|
use rustc::ty::subst::{Kind, Subst, Substs};
|
||||||
|
use rustc::ty::util::IntTypeExt;
|
||||||
use rustc::mir::*;
|
use rustc::mir::*;
|
||||||
use rustc::mir::transform::{Pass, MirPass, MirSource};
|
use rustc::mir::transform::{Pass, MirPass, MirSource};
|
||||||
use rustc::middle::const_val::ConstVal;
|
use rustc::middle::const_val::{ConstVal, ConstInt};
|
||||||
use rustc::middle::lang_items;
|
use rustc::middle::lang_items;
|
||||||
use rustc::util::nodemap::FxHashMap;
|
use rustc::util::nodemap::FxHashMap;
|
||||||
use rustc_data_structures::indexed_set::IdxSetBuf;
|
use rustc_data_structures::indexed_set::IdxSetBuf;
|
||||||
|
@ -619,48 +620,11 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
|
||||||
self.elaborated_drop_block(&inner_c)
|
self.elaborated_drop_block(&inner_c)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn open_drop_for_variant<'a>(&mut self,
|
|
||||||
c: &DropCtxt<'a, 'tcx>,
|
|
||||||
drop_block: &mut Option<BasicBlock>,
|
|
||||||
adt: &'tcx ty::AdtDef,
|
|
||||||
substs: &'tcx Substs<'tcx>,
|
|
||||||
variant_index: usize)
|
|
||||||
-> BasicBlock
|
|
||||||
{
|
|
||||||
let subpath = super::move_path_children_matching(
|
|
||||||
self.move_data(), c.path, |proj| match proj {
|
|
||||||
&Projection {
|
|
||||||
elem: ProjectionElem::Downcast(_, idx), ..
|
|
||||||
} => idx == variant_index,
|
|
||||||
_ => false
|
|
||||||
});
|
|
||||||
|
|
||||||
if let Some(variant_path) = subpath {
|
|
||||||
let base_lv = c.lvalue.clone().elem(
|
|
||||||
ProjectionElem::Downcast(adt, variant_index)
|
|
||||||
);
|
|
||||||
let fields = self.move_paths_for_fields(
|
|
||||||
&base_lv,
|
|
||||||
variant_path,
|
|
||||||
&adt.variants[variant_index],
|
|
||||||
substs);
|
|
||||||
self.drop_ladder(c, fields)
|
|
||||||
} else {
|
|
||||||
// variant not found - drop the entire enum
|
|
||||||
if let None = *drop_block {
|
|
||||||
*drop_block = Some(self.complete_drop(c, true));
|
|
||||||
}
|
|
||||||
return drop_block.unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn open_drop_for_adt<'a>(&mut self, c: &DropCtxt<'a, 'tcx>,
|
fn open_drop_for_adt<'a>(&mut self, c: &DropCtxt<'a, 'tcx>,
|
||||||
adt: &'tcx ty::AdtDef, substs: &'tcx Substs<'tcx>)
|
adt: &'tcx ty::AdtDef, substs: &'tcx Substs<'tcx>)
|
||||||
-> BasicBlock {
|
-> BasicBlock {
|
||||||
debug!("open_drop_for_adt({:?}, {:?}, {:?})", c, adt, substs);
|
debug!("open_drop_for_adt({:?}, {:?}, {:?})", c, adt, substs);
|
||||||
|
|
||||||
let mut drop_block = None;
|
|
||||||
|
|
||||||
match adt.variants.len() {
|
match adt.variants.len() {
|
||||||
1 => {
|
1 => {
|
||||||
let fields = self.move_paths_for_fields(
|
let fields = self.move_paths_for_fields(
|
||||||
|
@ -672,12 +636,43 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
|
||||||
self.drop_ladder(c, fields)
|
self.drop_ladder(c, fields)
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let variant_drops : Vec<BasicBlock> =
|
let mut values = Vec::with_capacity(adt.variants.len());
|
||||||
(0..adt.variants.len()).map(|i| {
|
let mut blocks = Vec::with_capacity(adt.variants.len());
|
||||||
self.open_drop_for_variant(c, &mut drop_block,
|
let mut otherwise = None;
|
||||||
adt, substs, i)
|
for (variant_index, variant) in adt.variants.iter().enumerate() {
|
||||||
}).collect();
|
let discr = ConstInt::new_inttype(variant.disr_val, adt.discr_ty,
|
||||||
|
self.tcx.sess.target.uint_type,
|
||||||
|
self.tcx.sess.target.int_type).unwrap();
|
||||||
|
let subpath = super::move_path_children_matching(
|
||||||
|
self.move_data(), c.path, |proj| match proj {
|
||||||
|
&Projection {
|
||||||
|
elem: ProjectionElem::Downcast(_, idx), ..
|
||||||
|
} => idx == variant_index,
|
||||||
|
_ => false
|
||||||
|
});
|
||||||
|
if let Some(variant_path) = subpath {
|
||||||
|
let base_lv = c.lvalue.clone().elem(
|
||||||
|
ProjectionElem::Downcast(adt, variant_index)
|
||||||
|
);
|
||||||
|
let fields = self.move_paths_for_fields(
|
||||||
|
&base_lv,
|
||||||
|
variant_path,
|
||||||
|
&adt.variants[variant_index],
|
||||||
|
substs);
|
||||||
|
values.push(discr);
|
||||||
|
blocks.push(self.drop_ladder(c, fields));
|
||||||
|
} else {
|
||||||
|
// variant not found - drop the entire enum
|
||||||
|
if let None = otherwise {
|
||||||
|
otherwise = Some(self.complete_drop(c, true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(block) = otherwise {
|
||||||
|
blocks.push(block);
|
||||||
|
} else {
|
||||||
|
values.pop();
|
||||||
|
}
|
||||||
// If there are multiple variants, then if something
|
// If there are multiple variants, then if something
|
||||||
// is present within the enum the discriminant, tracked
|
// is present within the enum the discriminant, tracked
|
||||||
// by the rest path, must be initialized.
|
// by the rest path, must be initialized.
|
||||||
|
@ -685,14 +680,27 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
|
||||||
// Additionally, we do not want to switch on the
|
// Additionally, we do not want to switch on the
|
||||||
// discriminant after it is free-ed, because that
|
// discriminant after it is free-ed, because that
|
||||||
// way lies only trouble.
|
// way lies only trouble.
|
||||||
|
let discr_ty = adt.discr_ty.to_ty(self.tcx);
|
||||||
let switch_block = self.new_block(
|
let discr = Lvalue::Local(self.patch.new_temp(discr_ty));
|
||||||
c, c.is_cleanup, TerminatorKind::Switch {
|
let switch_block = self.patch.new_block(BasicBlockData {
|
||||||
discr: c.lvalue.clone(),
|
statements: vec![
|
||||||
adt_def: adt,
|
Statement {
|
||||||
targets: variant_drops
|
source_info: c.source_info,
|
||||||
|
kind: StatementKind::Assign(discr.clone(),
|
||||||
|
Rvalue::Discriminant(c.lvalue.clone()))
|
||||||
|
}
|
||||||
|
],
|
||||||
|
terminator: Some(Terminator {
|
||||||
|
source_info: c.source_info,
|
||||||
|
kind: TerminatorKind::SwitchInt {
|
||||||
|
discr: Operand::Consume(discr),
|
||||||
|
switch_ty: discr_ty,
|
||||||
|
values: From::from(values),
|
||||||
|
targets: blocks,
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
is_cleanup: c.is_cleanup,
|
||||||
});
|
});
|
||||||
|
|
||||||
self.drop_flag_test_block(c, switch_block)
|
self.drop_flag_test_block(c, switch_block)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -813,10 +821,8 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
|
||||||
(true, false) => on_set,
|
(true, false) => on_set,
|
||||||
(true, true) => {
|
(true, true) => {
|
||||||
let flag = self.drop_flag(c.path).unwrap();
|
let flag = self.drop_flag(c.path).unwrap();
|
||||||
self.new_block(c, is_cleanup, TerminatorKind::If {
|
let term = TerminatorKind::if_(self.tcx, Operand::Consume(flag), on_set, on_unset);
|
||||||
cond: Operand::Consume(flag),
|
self.new_block(c, is_cleanup, term)
|
||||||
targets: (on_set, on_unset)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -435,6 +435,7 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Rvalue::Ref(..) |
|
Rvalue::Ref(..) |
|
||||||
|
Rvalue::Discriminant(..) |
|
||||||
Rvalue::Len(..) |
|
Rvalue::Len(..) |
|
||||||
Rvalue::InlineAsm { .. } => {}
|
Rvalue::InlineAsm { .. } => {}
|
||||||
Rvalue::Box(..) => {
|
Rvalue::Box(..) => {
|
||||||
|
@ -463,10 +464,8 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
|
||||||
self.gather_move(loc, &Lvalue::Local(RETURN_POINTER));
|
self.gather_move(loc, &Lvalue::Local(RETURN_POINTER));
|
||||||
}
|
}
|
||||||
|
|
||||||
TerminatorKind::If { .. } |
|
|
||||||
TerminatorKind::Assert { .. } |
|
TerminatorKind::Assert { .. } |
|
||||||
TerminatorKind::SwitchInt { .. } |
|
TerminatorKind::SwitchInt { .. } => {
|
||||||
TerminatorKind::Switch { .. } => {
|
|
||||||
// branching terminators - these don't move anything
|
// branching terminators - these don't move anything
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -77,6 +77,14 @@ mod ibounds {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ConstInt {
|
impl ConstInt {
|
||||||
|
pub fn new_inttype(val: u128, ty: IntType, usize_ty: UintTy, isize_ty: IntTy)
|
||||||
|
-> Option<ConstInt> {
|
||||||
|
match ty {
|
||||||
|
IntType::SignedInt(i) => ConstInt::new_signed(val as i128, i, isize_ty),
|
||||||
|
IntType::UnsignedInt(i) => ConstInt::new_unsigned(val, i, usize_ty),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Creates a new unsigned ConstInt with matching type while also checking that overflow does
|
/// Creates a new unsigned ConstInt with matching type while also checking that overflow does
|
||||||
/// not happen.
|
/// not happen.
|
||||||
pub fn new_unsigned(val: u128, ty: UintTy, usize_ty: UintTy) -> Option<ConstInt> {
|
pub fn new_unsigned(val: u128, ty: UintTy, usize_ty: UintTy) -> Option<ConstInt> {
|
||||||
|
|
|
@ -30,6 +30,10 @@ impl BitVector {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn count(&self) -> usize {
|
||||||
|
self.data.iter().map(|e| e.count_ones() as usize).sum()
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn contains(&self, bit: usize) -> bool {
|
pub fn contains(&self, bit: usize) -> bool {
|
||||||
let (word, mask) = word_mask(bit);
|
let (word, mask) = word_mask(bit);
|
||||||
|
|
|
@ -1084,10 +1084,10 @@ extern "C" {
|
||||||
DestTy: TypeRef,
|
DestTy: TypeRef,
|
||||||
Name: *const c_char)
|
Name: *const c_char)
|
||||||
-> ValueRef;
|
-> ValueRef;
|
||||||
pub fn LLVMBuildIntCast(B: BuilderRef,
|
pub fn LLVMRustBuildIntCast(B: BuilderRef,
|
||||||
Val: ValueRef,
|
Val: ValueRef,
|
||||||
DestTy: TypeRef,
|
DestTy: TypeRef,
|
||||||
Name: *const c_char)
|
IsSized: bool)
|
||||||
-> ValueRef;
|
-> ValueRef;
|
||||||
pub fn LLVMBuildFPCast(B: BuilderRef,
|
pub fn LLVMBuildFPCast(B: BuilderRef,
|
||||||
Val: ValueRef,
|
Val: ValueRef,
|
||||||
|
|
|
@ -25,8 +25,6 @@ use rustc::session::Session;
|
||||||
use rustc::ty::{self, Ty, TyCtxt};
|
use rustc::ty::{self, Ty, TyCtxt};
|
||||||
use rustc::ty::subst::Substs;
|
use rustc::ty::subst::Substs;
|
||||||
|
|
||||||
use rustc_const_math::ConstInt;
|
|
||||||
|
|
||||||
use rustc::mir::Mir;
|
use rustc::mir::Mir;
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
@ -435,7 +433,7 @@ impl<'tcx> EntryKind<'tcx> {
|
||||||
EntryKind::Mod(_) => Def::Mod(did),
|
EntryKind::Mod(_) => Def::Mod(did),
|
||||||
EntryKind::Variant(_) => Def::Variant(did),
|
EntryKind::Variant(_) => Def::Variant(did),
|
||||||
EntryKind::Trait(_) => Def::Trait(did),
|
EntryKind::Trait(_) => Def::Trait(did),
|
||||||
EntryKind::Enum(_) => Def::Enum(did),
|
EntryKind::Enum(..) => Def::Enum(did),
|
||||||
EntryKind::MacroDef(_) => Def::Macro(did),
|
EntryKind::MacroDef(_) => Def::Macro(did),
|
||||||
|
|
||||||
EntryKind::ForeignMod |
|
EntryKind::ForeignMod |
|
||||||
|
@ -535,7 +533,7 @@ impl<'a, 'tcx> CrateMetadata {
|
||||||
vis: f.visibility.decode(self)
|
vis: f.visibility.decode(self)
|
||||||
}
|
}
|
||||||
}).collect(),
|
}).collect(),
|
||||||
disr_val: ConstInt::Infer(data.disr),
|
disr_val: data.disr,
|
||||||
ctor_kind: data.ctor_kind,
|
ctor_kind: data.ctor_kind,
|
||||||
}, data.struct_ctor)
|
}, data.struct_ctor)
|
||||||
}
|
}
|
||||||
|
@ -546,8 +544,14 @@ impl<'a, 'tcx> CrateMetadata {
|
||||||
-> &'tcx ty::AdtDef {
|
-> &'tcx ty::AdtDef {
|
||||||
let item = self.entry(item_id);
|
let item = self.entry(item_id);
|
||||||
let did = self.local_def_id(item_id);
|
let did = self.local_def_id(item_id);
|
||||||
|
let (kind, ty) = match item.kind {
|
||||||
|
EntryKind::Enum(dt, _) => (ty::AdtKind::Enum, Some(dt.decode(self))),
|
||||||
|
EntryKind::Struct(_, _) => (ty::AdtKind::Struct, None),
|
||||||
|
EntryKind::Union(_, _) => (ty::AdtKind::Union, None),
|
||||||
|
_ => bug!("get_adt_def called on a non-ADT {:?}", did),
|
||||||
|
};
|
||||||
let mut ctor_index = None;
|
let mut ctor_index = None;
|
||||||
let variants = if let EntryKind::Enum(_) = item.kind {
|
let variants = if let ty::AdtKind::Enum = kind {
|
||||||
item.children
|
item.children
|
||||||
.decode(self)
|
.decode(self)
|
||||||
.map(|index| {
|
.map(|index| {
|
||||||
|
@ -562,13 +566,13 @@ impl<'a, 'tcx> CrateMetadata {
|
||||||
vec![variant]
|
vec![variant]
|
||||||
};
|
};
|
||||||
let (kind, repr) = match item.kind {
|
let (kind, repr) = match item.kind {
|
||||||
EntryKind::Enum(repr) => (ty::AdtKind::Enum, repr),
|
EntryKind::Enum(_, repr) => (ty::AdtKind::Enum, repr),
|
||||||
EntryKind::Struct(_, repr) => (ty::AdtKind::Struct, repr),
|
EntryKind::Struct(_, repr) => (ty::AdtKind::Struct, repr),
|
||||||
EntryKind::Union(_, repr) => (ty::AdtKind::Union, repr),
|
EntryKind::Union(_, repr) => (ty::AdtKind::Union, repr),
|
||||||
_ => bug!("get_adt_def called on a non-ADT {:?}", did),
|
_ => bug!("get_adt_def called on a non-ADT {:?}", did),
|
||||||
};
|
};
|
||||||
|
|
||||||
let adt = tcx.alloc_adt_def(did, kind, variants, repr);
|
let adt = tcx.alloc_adt_def(did, kind, ty, variants, repr);
|
||||||
if let Some(ctor_index) = ctor_index {
|
if let Some(ctor_index) = ctor_index {
|
||||||
// Make adt definition available through constructor id as well.
|
// Make adt definition available through constructor id as well.
|
||||||
tcx.adt_defs.borrow_mut().insert(self.local_def_id(ctor_index), adt);
|
tcx.adt_defs.borrow_mut().insert(self.local_def_id(ctor_index), adt);
|
||||||
|
|
|
@ -261,7 +261,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||||
|
|
||||||
let data = VariantData {
|
let data = VariantData {
|
||||||
ctor_kind: variant.ctor_kind,
|
ctor_kind: variant.ctor_kind,
|
||||||
disr: variant.disr_val.to_u128_unchecked(),
|
disr: variant.disr_val,
|
||||||
struct_ctor: None,
|
struct_ctor: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -388,7 +388,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||||
|
|
||||||
let data = VariantData {
|
let data = VariantData {
|
||||||
ctor_kind: variant.ctor_kind,
|
ctor_kind: variant.ctor_kind,
|
||||||
disr: variant.disr_val.to_u128_unchecked(),
|
disr: variant.disr_val,
|
||||||
struct_ctor: Some(def_id.index),
|
struct_ctor: Some(def_id.index),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -661,7 +661,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
hir::ItemForeignMod(_) => EntryKind::ForeignMod,
|
hir::ItemForeignMod(_) => EntryKind::ForeignMod,
|
||||||
hir::ItemTy(..) => EntryKind::Type,
|
hir::ItemTy(..) => EntryKind::Type,
|
||||||
hir::ItemEnum(..) => EntryKind::Enum(get_repr_options(&tcx, def_id)),
|
hir::ItemEnum(..) => EntryKind::Enum(self.lazy(&tcx.lookup_adt_def(def_id).discr_ty),
|
||||||
|
get_repr_options(&tcx, def_id)),
|
||||||
hir::ItemStruct(ref struct_def, _) => {
|
hir::ItemStruct(ref struct_def, _) => {
|
||||||
let variant = tcx.lookup_adt_def(def_id).struct_variant();
|
let variant = tcx.lookup_adt_def(def_id).struct_variant();
|
||||||
|
|
||||||
|
@ -678,7 +679,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||||
|
|
||||||
EntryKind::Struct(self.lazy(&VariantData {
|
EntryKind::Struct(self.lazy(&VariantData {
|
||||||
ctor_kind: variant.ctor_kind,
|
ctor_kind: variant.ctor_kind,
|
||||||
disr: variant.disr_val.to_u128_unchecked(),
|
disr: variant.disr_val,
|
||||||
struct_ctor: struct_ctor,
|
struct_ctor: struct_ctor,
|
||||||
}), repr_options)
|
}), repr_options)
|
||||||
}
|
}
|
||||||
|
@ -688,7 +689,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||||
|
|
||||||
EntryKind::Union(self.lazy(&VariantData {
|
EntryKind::Union(self.lazy(&VariantData {
|
||||||
ctor_kind: variant.ctor_kind,
|
ctor_kind: variant.ctor_kind,
|
||||||
disr: variant.disr_val.to_u128_unchecked(),
|
disr: variant.disr_val,
|
||||||
struct_ctor: None,
|
struct_ctor: None,
|
||||||
}), repr_options)
|
}), repr_options)
|
||||||
}
|
}
|
||||||
|
|
|
@ -228,7 +228,7 @@ pub enum EntryKind<'tcx> {
|
||||||
ForeignMutStatic,
|
ForeignMutStatic,
|
||||||
ForeignMod,
|
ForeignMod,
|
||||||
Type,
|
Type,
|
||||||
Enum(ReprOptions),
|
Enum(Lazy<attr::IntType>, ReprOptions),
|
||||||
Field,
|
Field,
|
||||||
Variant(Lazy<VariantData>),
|
Variant(Lazy<VariantData>),
|
||||||
Struct(Lazy<VariantData>, ReprOptions),
|
Struct(Lazy<VariantData>, ReprOptions),
|
||||||
|
|
|
@ -69,10 +69,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||||
|
|
||||||
let mut then_block = this.cfg.start_new_block();
|
let mut then_block = this.cfg.start_new_block();
|
||||||
let mut else_block = this.cfg.start_new_block();
|
let mut else_block = this.cfg.start_new_block();
|
||||||
this.cfg.terminate(block, source_info, TerminatorKind::If {
|
let term = TerminatorKind::if_(this.hir.tcx(), operand, then_block, else_block);
|
||||||
cond: operand,
|
this.cfg.terminate(block, source_info, term);
|
||||||
targets: (then_block, else_block)
|
|
||||||
});
|
|
||||||
|
|
||||||
unpack!(then_block = this.into(destination, then_block, then_expr));
|
unpack!(then_block = this.into(destination, then_block, then_expr));
|
||||||
else_block = if let Some(else_expr) = else_expr {
|
else_block = if let Some(else_expr) = else_expr {
|
||||||
|
@ -114,14 +112,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||||
LogicalOp::And => (else_block, false_block),
|
LogicalOp::And => (else_block, false_block),
|
||||||
LogicalOp::Or => (true_block, else_block),
|
LogicalOp::Or => (true_block, else_block),
|
||||||
};
|
};
|
||||||
this.cfg.terminate(block, source_info,
|
let term = TerminatorKind::if_(this.hir.tcx(), lhs, blocks.0, blocks.1);
|
||||||
TerminatorKind::If { cond: lhs, targets: blocks });
|
this.cfg.terminate(block, source_info, term);
|
||||||
|
|
||||||
let rhs = unpack!(else_block = this.as_operand(else_block, rhs));
|
let rhs = unpack!(else_block = this.as_operand(else_block, rhs));
|
||||||
this.cfg.terminate(else_block, source_info, TerminatorKind::If {
|
let term = TerminatorKind::if_(this.hir.tcx(), rhs, true_block, false_block);
|
||||||
cond: rhs,
|
this.cfg.terminate(else_block, source_info, term);
|
||||||
targets: (true_block, false_block)
|
|
||||||
});
|
|
||||||
|
|
||||||
this.cfg.push_assign_constant(
|
this.cfg.push_assign_constant(
|
||||||
true_block, source_info, destination,
|
true_block, source_info, destination,
|
||||||
|
@ -179,11 +175,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||||
let cond = unpack!(
|
let cond = unpack!(
|
||||||
loop_block_end = this.as_operand(loop_block, cond_expr));
|
loop_block_end = this.as_operand(loop_block, cond_expr));
|
||||||
body_block = this.cfg.start_new_block();
|
body_block = this.cfg.start_new_block();
|
||||||
this.cfg.terminate(loop_block_end, source_info,
|
let term = TerminatorKind::if_(this.hir.tcx(), cond,
|
||||||
TerminatorKind::If {
|
body_block, exit_block);
|
||||||
cond: cond,
|
this.cfg.terminate(loop_block_end, source_info, term);
|
||||||
targets: (body_block, exit_block)
|
|
||||||
});
|
|
||||||
|
|
||||||
// if the test is false, there's no `break` to assign `destination`, so
|
// if the test is false, there's no `break` to assign `destination`, so
|
||||||
// we have to do it; this overwrites any `break`-assigned value but it's
|
// we have to do it; this overwrites any `break`-assigned value but it's
|
||||||
|
|
|
@ -673,8 +673,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||||
let cond = unpack!(block = self.as_operand(block, guard));
|
let cond = unpack!(block = self.as_operand(block, guard));
|
||||||
let otherwise = self.cfg.start_new_block();
|
let otherwise = self.cfg.start_new_block();
|
||||||
self.cfg.terminate(block, source_info,
|
self.cfg.terminate(block, source_info,
|
||||||
TerminatorKind::If { cond: cond,
|
TerminatorKind::if_(self.hir.tcx(), cond, arm_block, otherwise));
|
||||||
targets: (arm_block, otherwise)});
|
|
||||||
Some(otherwise)
|
Some(otherwise)
|
||||||
} else {
|
} else {
|
||||||
let source_info = self.source_info(candidate.span);
|
let source_info = self.source_info(candidate.span);
|
||||||
|
|
|
@ -20,8 +20,9 @@ use build::matches::{Candidate, MatchPair, Test, TestKind};
|
||||||
use hair::*;
|
use hair::*;
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc_data_structures::bitvec::BitVector;
|
use rustc_data_structures::bitvec::BitVector;
|
||||||
use rustc::middle::const_val::ConstVal;
|
use rustc::middle::const_val::{ConstVal, ConstInt};
|
||||||
use rustc::ty::{self, Ty};
|
use rustc::ty::{self, Ty};
|
||||||
|
use rustc::ty::util::IntTypeExt;
|
||||||
use rustc::mir::*;
|
use rustc::mir::*;
|
||||||
use rustc::hir::RangeEnd;
|
use rustc::hir::RangeEnd;
|
||||||
use syntax_pos::Span;
|
use syntax_pos::Span;
|
||||||
|
@ -182,53 +183,62 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||||
let source_info = self.source_info(test.span);
|
let source_info = self.source_info(test.span);
|
||||||
match test.kind {
|
match test.kind {
|
||||||
TestKind::Switch { adt_def, ref variants } => {
|
TestKind::Switch { adt_def, ref variants } => {
|
||||||
|
// Variants is a BitVec of indexes into adt_def.variants.
|
||||||
let num_enum_variants = self.hir.num_variants(adt_def);
|
let num_enum_variants = self.hir.num_variants(adt_def);
|
||||||
|
let used_variants = variants.count();
|
||||||
let mut otherwise_block = None;
|
let mut otherwise_block = None;
|
||||||
let target_blocks: Vec<_> = (0..num_enum_variants).map(|i| {
|
let mut target_blocks = Vec::with_capacity(num_enum_variants);
|
||||||
if variants.contains(i) {
|
let mut targets = Vec::with_capacity(used_variants + 1);
|
||||||
self.cfg.start_new_block()
|
let mut values = Vec::with_capacity(used_variants);
|
||||||
|
let tcx = self.hir.tcx();
|
||||||
|
for (idx, variant) in adt_def.variants.iter().enumerate() {
|
||||||
|
target_blocks.place_back() <- if variants.contains(idx) {
|
||||||
|
let discr = ConstInt::new_inttype(variant.disr_val, adt_def.discr_ty,
|
||||||
|
tcx.sess.target.uint_type,
|
||||||
|
tcx.sess.target.int_type).unwrap();
|
||||||
|
values.push(discr);
|
||||||
|
*(targets.place_back() <- self.cfg.start_new_block())
|
||||||
} else {
|
} else {
|
||||||
if otherwise_block.is_none() {
|
if otherwise_block.is_none() {
|
||||||
otherwise_block = Some(self.cfg.start_new_block());
|
otherwise_block = Some(self.cfg.start_new_block());
|
||||||
}
|
}
|
||||||
otherwise_block.unwrap()
|
otherwise_block.unwrap()
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}).collect();
|
if let Some(otherwise_block) = otherwise_block {
|
||||||
debug!("num_enum_variants: {}, num tested variants: {}, variants: {:?}",
|
targets.push(otherwise_block);
|
||||||
num_enum_variants, variants.iter().count(), variants);
|
} else {
|
||||||
self.cfg.terminate(block, source_info, TerminatorKind::Switch {
|
values.pop();
|
||||||
discr: lvalue.clone(),
|
}
|
||||||
adt_def: adt_def,
|
debug!("num_enum_variants: {}, tested variants: {:?}, variants: {:?}",
|
||||||
targets: target_blocks.clone()
|
num_enum_variants, values, variants);
|
||||||
|
let discr_ty = adt_def.discr_ty.to_ty(tcx);
|
||||||
|
let discr = self.temp(discr_ty);
|
||||||
|
self.cfg.push_assign(block, source_info, &discr,
|
||||||
|
Rvalue::Discriminant(lvalue.clone()));
|
||||||
|
assert_eq!(values.len() + 1, targets.len());
|
||||||
|
self.cfg.terminate(block, source_info, TerminatorKind::SwitchInt {
|
||||||
|
discr: Operand::Consume(discr),
|
||||||
|
switch_ty: discr_ty,
|
||||||
|
values: From::from(values),
|
||||||
|
targets: targets
|
||||||
});
|
});
|
||||||
target_blocks
|
target_blocks
|
||||||
}
|
}
|
||||||
|
|
||||||
TestKind::SwitchInt { switch_ty, ref options, indices: _ } => {
|
TestKind::SwitchInt { switch_ty, ref options, indices: _ } => {
|
||||||
let (targets, term) = match switch_ty.sty {
|
let (ret, terminator) = if switch_ty.sty == ty::TyBool {
|
||||||
// If we're matching on boolean we can
|
|
||||||
// use the If TerminatorKind instead
|
|
||||||
ty::TyBool => {
|
|
||||||
assert!(options.len() > 0 && options.len() <= 2);
|
assert!(options.len() > 0 && options.len() <= 2);
|
||||||
|
let (true_bb, false_bb) = (self.cfg.start_new_block(),
|
||||||
let (true_bb, else_bb) =
|
|
||||||
(self.cfg.start_new_block(),
|
|
||||||
self.cfg.start_new_block());
|
self.cfg.start_new_block());
|
||||||
|
let ret = match &options[0] {
|
||||||
let targets = match &options[0] {
|
&ConstVal::Bool(true) => vec![true_bb, false_bb],
|
||||||
&ConstVal::Bool(true) => vec![true_bb, else_bb],
|
&ConstVal::Bool(false) => vec![false_bb, true_bb],
|
||||||
&ConstVal::Bool(false) => vec![else_bb, true_bb],
|
|
||||||
v => span_bug!(test.span, "expected boolean value but got {:?}", v)
|
v => span_bug!(test.span, "expected boolean value but got {:?}", v)
|
||||||
};
|
};
|
||||||
|
(ret, TerminatorKind::if_(self.hir.tcx(), Operand::Consume(lvalue.clone()),
|
||||||
(targets,
|
true_bb, false_bb))
|
||||||
TerminatorKind::If {
|
} else {
|
||||||
cond: Operand::Consume(lvalue.clone()),
|
|
||||||
targets: (true_bb, else_bb)
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
// The switch may be inexhaustive so we
|
// The switch may be inexhaustive so we
|
||||||
// add a catch all block
|
// add a catch all block
|
||||||
let otherwise = self.cfg.start_new_block();
|
let otherwise = self.cfg.start_new_block();
|
||||||
|
@ -237,19 +247,18 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||||
.map(|_| self.cfg.start_new_block())
|
.map(|_| self.cfg.start_new_block())
|
||||||
.chain(Some(otherwise))
|
.chain(Some(otherwise))
|
||||||
.collect();
|
.collect();
|
||||||
|
let values: Vec<_> = options.iter().map(|v|
|
||||||
(targets.clone(),
|
v.to_const_int().expect("switching on integral")
|
||||||
TerminatorKind::SwitchInt {
|
).collect();
|
||||||
discr: lvalue.clone(),
|
(targets.clone(), TerminatorKind::SwitchInt {
|
||||||
|
discr: Operand::Consume(lvalue.clone()),
|
||||||
switch_ty: switch_ty,
|
switch_ty: switch_ty,
|
||||||
values: options.clone(),
|
values: From::from(values),
|
||||||
targets: targets
|
targets: targets,
|
||||||
})
|
})
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
self.cfg.terminate(block, source_info, terminator);
|
||||||
self.cfg.terminate(block, source_info, term);
|
ret
|
||||||
targets
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TestKind::Eq { ref value, mut ty } => {
|
TestKind::Eq { ref value, mut ty } => {
|
||||||
|
@ -314,11 +323,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||||
|
|
||||||
// check the result
|
// check the result
|
||||||
let block = self.cfg.start_new_block();
|
let block = self.cfg.start_new_block();
|
||||||
self.cfg.terminate(eq_block, source_info, TerminatorKind::If {
|
self.cfg.terminate(eq_block, source_info,
|
||||||
cond: Operand::Consume(eq_result),
|
TerminatorKind::if_(self.hir.tcx(),
|
||||||
targets: (block, fail),
|
Operand::Consume(eq_result),
|
||||||
});
|
block, fail));
|
||||||
|
|
||||||
vec![block, fail]
|
vec![block, fail]
|
||||||
} else {
|
} else {
|
||||||
let block = self.compare(block, fail, test.span, BinOp::Eq, expect, val);
|
let block = self.compare(block, fail, test.span, BinOp::Eq, expect, val);
|
||||||
|
@ -360,14 +368,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||||
Operand::Consume(expected)));
|
Operand::Consume(expected)));
|
||||||
|
|
||||||
// branch based on result
|
// branch based on result
|
||||||
let target_blocks: Vec<_> = vec![self.cfg.start_new_block(),
|
let (false_bb, true_bb) = (self.cfg.start_new_block(),
|
||||||
self.cfg.start_new_block()];
|
self.cfg.start_new_block());
|
||||||
self.cfg.terminate(block, source_info, TerminatorKind::If {
|
self.cfg.terminate(block, source_info,
|
||||||
cond: Operand::Consume(result),
|
TerminatorKind::if_(self.hir.tcx(), Operand::Consume(result),
|
||||||
targets: (target_blocks[0], target_blocks[1])
|
true_bb, false_bb));
|
||||||
});
|
vec![true_bb, false_bb]
|
||||||
|
|
||||||
target_blocks
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -389,11 +395,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||||
|
|
||||||
// branch based on result
|
// branch based on result
|
||||||
let target_block = self.cfg.start_new_block();
|
let target_block = self.cfg.start_new_block();
|
||||||
self.cfg.terminate(block, source_info, TerminatorKind::If {
|
self.cfg.terminate(block, source_info,
|
||||||
cond: Operand::Consume(result),
|
TerminatorKind::if_(self.hir.tcx(), Operand::Consume(result),
|
||||||
targets: (target_block, fail_block)
|
target_block, fail_block));
|
||||||
});
|
|
||||||
|
|
||||||
target_block
|
target_block
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -134,7 +134,8 @@ pub enum ExprKind<'tcx> {
|
||||||
op: LogicalOp,
|
op: LogicalOp,
|
||||||
lhs: ExprRef<'tcx>,
|
lhs: ExprRef<'tcx>,
|
||||||
rhs: ExprRef<'tcx>,
|
rhs: ExprRef<'tcx>,
|
||||||
},
|
}, // NOT overloaded!
|
||||||
|
// LogicalOp is distinct from BinaryOp because of lazy evaluation of the operands.
|
||||||
Unary {
|
Unary {
|
||||||
op: UnOp,
|
op: UnOp,
|
||||||
arg: ExprRef<'tcx>,
|
arg: ExprRef<'tcx>,
|
||||||
|
|
|
@ -26,6 +26,8 @@ Rust MIR: a lowered representation of Rust. Also: an experiment!
|
||||||
#![feature(rustc_diagnostic_macros)]
|
#![feature(rustc_diagnostic_macros)]
|
||||||
#![feature(rustc_private)]
|
#![feature(rustc_private)]
|
||||||
#![feature(staged_api)]
|
#![feature(staged_api)]
|
||||||
|
#![feature(placement_in_syntax)]
|
||||||
|
#![feature(collection_placement)]
|
||||||
|
|
||||||
#[macro_use] extern crate log;
|
#[macro_use] extern crate log;
|
||||||
extern crate graphviz as dot;
|
extern crate graphviz as dot;
|
||||||
|
|
|
@ -28,8 +28,6 @@ impl<'tcx> MutVisitor<'tcx> for NoLandingPads {
|
||||||
TerminatorKind::Resume |
|
TerminatorKind::Resume |
|
||||||
TerminatorKind::Return |
|
TerminatorKind::Return |
|
||||||
TerminatorKind::Unreachable |
|
TerminatorKind::Unreachable |
|
||||||
TerminatorKind::If { .. } |
|
|
||||||
TerminatorKind::Switch { .. } |
|
|
||||||
TerminatorKind::SwitchInt { .. } => {
|
TerminatorKind::SwitchInt { .. } => {
|
||||||
/* nothing to do */
|
/* nothing to do */
|
||||||
},
|
},
|
||||||
|
|
|
@ -394,8 +394,6 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
|
||||||
return Qualif::empty();
|
return Qualif::empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
TerminatorKind::If {..} |
|
|
||||||
TerminatorKind::Switch {..} |
|
|
||||||
TerminatorKind::SwitchInt {..} |
|
TerminatorKind::SwitchInt {..} |
|
||||||
TerminatorKind::DropAndReplace { .. } |
|
TerminatorKind::DropAndReplace { .. } |
|
||||||
TerminatorKind::Resume |
|
TerminatorKind::Resume |
|
||||||
|
@ -739,6 +737,14 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Rvalue::Discriminant(..) => {
|
||||||
|
// FIXME discriminant
|
||||||
|
self.add(Qualif::NOT_CONST);
|
||||||
|
if self.mode != Mode::Fn {
|
||||||
|
bug!("implement discriminant const qualify");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Rvalue::Box(_) => {
|
Rvalue::Box(_) => {
|
||||||
self.add(Qualif::NOT_CONST);
|
self.add(Qualif::NOT_CONST);
|
||||||
if self.mode != Mode::Fn {
|
if self.mode != Mode::Fn {
|
||||||
|
|
|
@ -209,8 +209,6 @@ impl<'a, 'tcx: 'a> CfgSimplifier<'a, 'tcx> {
|
||||||
// turn a branch with all successors identical to a goto
|
// turn a branch with all successors identical to a goto
|
||||||
fn simplify_branch(&mut self, terminator: &mut Terminator<'tcx>) -> bool {
|
fn simplify_branch(&mut self, terminator: &mut Terminator<'tcx>) -> bool {
|
||||||
match terminator.kind {
|
match terminator.kind {
|
||||||
TerminatorKind::If { .. } |
|
|
||||||
TerminatorKind::Switch { .. } |
|
|
||||||
TerminatorKind::SwitchInt { .. } => {},
|
TerminatorKind::SwitchInt { .. } => {},
|
||||||
_ => return false
|
_ => return false
|
||||||
};
|
};
|
||||||
|
|
|
@ -30,26 +30,30 @@ impl<'l, 'tcx> MirPass<'tcx> for SimplifyBranches<'l> {
|
||||||
for block in mir.basic_blocks_mut() {
|
for block in mir.basic_blocks_mut() {
|
||||||
let terminator = block.terminator_mut();
|
let terminator = block.terminator_mut();
|
||||||
terminator.kind = match terminator.kind {
|
terminator.kind = match terminator.kind {
|
||||||
TerminatorKind::If { ref targets, cond: Operand::Constant(Constant {
|
TerminatorKind::SwitchInt { discr: Operand::Constant(Constant {
|
||||||
literal: Literal::Value {
|
literal: Literal::Value { ref value }, ..
|
||||||
value: ConstVal::Bool(cond)
|
}), ref values, ref targets, .. } => {
|
||||||
}, ..
|
if let Some(ref constint) = value.to_const_int() {
|
||||||
}) } => {
|
let (otherwise, targets) = targets.split_last().unwrap();
|
||||||
if cond {
|
let mut ret = TerminatorKind::Goto { target: *otherwise };
|
||||||
TerminatorKind::Goto { target: targets.0 }
|
for (v, t) in values.iter().zip(targets.iter()) {
|
||||||
|
if v == constint {
|
||||||
|
ret = TerminatorKind::Goto { target: *t };
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ret
|
||||||
} else {
|
} else {
|
||||||
TerminatorKind::Goto { target: targets.1 }
|
continue
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
|
||||||
TerminatorKind::Assert { target, cond: Operand::Constant(Constant {
|
TerminatorKind::Assert { target, cond: Operand::Constant(Constant {
|
||||||
literal: Literal::Value {
|
literal: Literal::Value {
|
||||||
value: ConstVal::Bool(cond)
|
value: ConstVal::Bool(cond)
|
||||||
}, ..
|
}, ..
|
||||||
}), expected, .. } if cond == expected => {
|
}), expected, .. } if cond == expected => {
|
||||||
TerminatorKind::Goto { target: target }
|
TerminatorKind::Goto { target: target }
|
||||||
}
|
},
|
||||||
|
|
||||||
_ => continue
|
_ => continue
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -423,18 +423,8 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
||||||
lv_ty, rv_ty, terr);
|
lv_ty, rv_ty, terr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TerminatorKind::If { ref cond, .. } => {
|
|
||||||
let cond_ty = cond.ty(mir, tcx);
|
|
||||||
match cond_ty.sty {
|
|
||||||
ty::TyBool => {}
|
|
||||||
_ => {
|
|
||||||
span_mirbug!(self, term, "bad If ({:?}, not bool", cond_ty);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TerminatorKind::SwitchInt { ref discr, switch_ty, .. } => {
|
TerminatorKind::SwitchInt { ref discr, switch_ty, .. } => {
|
||||||
let discr_ty = discr.ty(mir, tcx).to_ty(tcx);
|
let discr_ty = discr.ty(mir, tcx);
|
||||||
if let Err(terr) = self.sub_types(discr_ty, switch_ty) {
|
if let Err(terr) = self.sub_types(discr_ty, switch_ty) {
|
||||||
span_mirbug!(self, term, "bad SwitchInt ({:?} on {:?}): {:?}",
|
span_mirbug!(self, term, "bad SwitchInt ({:?} on {:?}): {:?}",
|
||||||
switch_ty, discr_ty, terr);
|
switch_ty, discr_ty, terr);
|
||||||
|
@ -446,19 +436,6 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
||||||
}
|
}
|
||||||
// FIXME: check the values
|
// FIXME: check the values
|
||||||
}
|
}
|
||||||
TerminatorKind::Switch { ref discr, adt_def, ref targets } => {
|
|
||||||
let discr_ty = discr.ty(mir, tcx).to_ty(tcx);
|
|
||||||
match discr_ty.sty {
|
|
||||||
ty::TyAdt(def, _) if def.is_enum() &&
|
|
||||||
def == adt_def &&
|
|
||||||
adt_def.variants.len() == targets.len()
|
|
||||||
=> {},
|
|
||||||
_ => {
|
|
||||||
span_mirbug!(self, term, "bad Switch ({:?} on {:?})",
|
|
||||||
adt_def, discr_ty);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TerminatorKind::Call { ref func, ref args, ref destination, .. } => {
|
TerminatorKind::Call { ref func, ref args, ref destination, .. } => {
|
||||||
let func_ty = func.ty(mir, tcx);
|
let func_ty = func.ty(mir, tcx);
|
||||||
debug!("check_terminator: call, func_ty={:?}", func_ty);
|
debug!("check_terminator: call, func_ty={:?}", func_ty);
|
||||||
|
@ -603,11 +580,6 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
||||||
match block.terminator().kind {
|
match block.terminator().kind {
|
||||||
TerminatorKind::Goto { target } =>
|
TerminatorKind::Goto { target } =>
|
||||||
self.assert_iscleanup(mir, block, target, is_cleanup),
|
self.assert_iscleanup(mir, block, target, is_cleanup),
|
||||||
TerminatorKind::If { targets: (on_true, on_false), .. } => {
|
|
||||||
self.assert_iscleanup(mir, block, on_true, is_cleanup);
|
|
||||||
self.assert_iscleanup(mir, block, on_false, is_cleanup);
|
|
||||||
}
|
|
||||||
TerminatorKind::Switch { ref targets, .. } |
|
|
||||||
TerminatorKind::SwitchInt { ref targets, .. } => {
|
TerminatorKind::SwitchInt { ref targets, .. } => {
|
||||||
for target in targets {
|
for target in targets {
|
||||||
self.assert_iscleanup(mir, block, *target, is_cleanup);
|
self.assert_iscleanup(mir, block, *target, is_cleanup);
|
||||||
|
|
|
@ -148,8 +148,6 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> {
|
||||||
self.record("TerminatorKind", kind);
|
self.record("TerminatorKind", kind);
|
||||||
self.record(match *kind {
|
self.record(match *kind {
|
||||||
TerminatorKind::Goto { .. } => "TerminatorKind::Goto",
|
TerminatorKind::Goto { .. } => "TerminatorKind::Goto",
|
||||||
TerminatorKind::If { .. } => "TerminatorKind::If",
|
|
||||||
TerminatorKind::Switch { .. } => "TerminatorKind::Switch",
|
|
||||||
TerminatorKind::SwitchInt { .. } => "TerminatorKind::SwitchInt",
|
TerminatorKind::SwitchInt { .. } => "TerminatorKind::SwitchInt",
|
||||||
TerminatorKind::Resume => "TerminatorKind::Resume",
|
TerminatorKind::Resume => "TerminatorKind::Resume",
|
||||||
TerminatorKind::Return => "TerminatorKind::Return",
|
TerminatorKind::Return => "TerminatorKind::Return",
|
||||||
|
@ -186,6 +184,7 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> {
|
||||||
Rvalue::BinaryOp(..) => "Rvalue::BinaryOp",
|
Rvalue::BinaryOp(..) => "Rvalue::BinaryOp",
|
||||||
Rvalue::CheckedBinaryOp(..) => "Rvalue::CheckedBinaryOp",
|
Rvalue::CheckedBinaryOp(..) => "Rvalue::CheckedBinaryOp",
|
||||||
Rvalue::UnaryOp(..) => "Rvalue::UnaryOp",
|
Rvalue::UnaryOp(..) => "Rvalue::UnaryOp",
|
||||||
|
Rvalue::Discriminant(..) => "Rvalue::Discriminant",
|
||||||
Rvalue::Box(..) => "Rvalue::Box",
|
Rvalue::Box(..) => "Rvalue::Box",
|
||||||
Rvalue::Aggregate(ref kind, ref _operands) => {
|
Rvalue::Aggregate(ref kind, ref _operands) => {
|
||||||
// AggregateKind is not distinguished by visit API, so
|
// AggregateKind is not distinguished by visit API, so
|
||||||
|
|
|
@ -318,7 +318,7 @@ pub fn trans_get_discr<'a, 'tcx>(
|
||||||
};
|
};
|
||||||
match cast_to {
|
match cast_to {
|
||||||
None => val,
|
None => val,
|
||||||
Some(llty) => if is_discr_signed(&l) { bcx.sext(val, llty) } else { bcx.zext(val, llty) }
|
Some(llty) => bcx.intcast(val, llty, is_discr_signed(&l))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -536,7 +536,7 @@ pub fn call_memcpy<'a, 'tcx>(b: &Builder<'a, 'tcx>,
|
||||||
let memcpy = ccx.get_intrinsic(&key);
|
let memcpy = ccx.get_intrinsic(&key);
|
||||||
let src_ptr = b.pointercast(src, Type::i8p(ccx));
|
let src_ptr = b.pointercast(src, Type::i8p(ccx));
|
||||||
let dst_ptr = b.pointercast(dst, Type::i8p(ccx));
|
let dst_ptr = b.pointercast(dst, Type::i8p(ccx));
|
||||||
let size = b.intcast(n_bytes, ccx.int_type());
|
let size = b.intcast(n_bytes, ccx.int_type(), false);
|
||||||
let align = C_i32(ccx, align as i32);
|
let align = C_i32(ccx, align as i32);
|
||||||
let volatile = C_bool(ccx, false);
|
let volatile = C_bool(ccx, false);
|
||||||
b.call(memcpy, &[dst_ptr, src_ptr, size, align, volatile], None);
|
b.call(memcpy, &[dst_ptr, src_ptr, size, align, volatile], None);
|
||||||
|
|
|
@ -780,10 +780,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn intcast(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
|
pub fn intcast(&self, val: ValueRef, dest_ty: Type, is_signed: bool) -> ValueRef {
|
||||||
self.count_insn("intcast");
|
self.count_insn("intcast");
|
||||||
unsafe {
|
unsafe {
|
||||||
llvm::LLVMBuildIntCast(self.llbuilder, val, dest_ty.to_ref(), noname())
|
llvm::LLVMRustBuildIntCast(self.llbuilder, val, dest_ty.to_ref(), is_signed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1476,7 +1476,7 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||||
DIB(cx),
|
DIB(cx),
|
||||||
name.as_ptr(),
|
name.as_ptr(),
|
||||||
// FIXME: what if enumeration has i128 discriminant?
|
// FIXME: what if enumeration has i128 discriminant?
|
||||||
v.disr_val.to_u128_unchecked() as u64)
|
v.disr_val as u64)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
|
@ -27,7 +27,7 @@ impl ::std::ops::BitAnd for Disr {
|
||||||
impl From<::rustc::ty::Disr> for Disr {
|
impl From<::rustc::ty::Disr> for Disr {
|
||||||
fn from(i: ::rustc::ty::Disr) -> Disr {
|
fn from(i: ::rustc::ty::Disr) -> Disr {
|
||||||
// FIXME: what if discr has 128 bit discr?
|
// FIXME: what if discr has 128 bit discr?
|
||||||
Disr(i.to_u128_unchecked() as u64)
|
Disr(i as u64)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -156,10 +156,10 @@ impl<'mir, 'a, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'tcx> {
|
||||||
|
|
||||||
LvalueContext::StorageLive |
|
LvalueContext::StorageLive |
|
||||||
LvalueContext::StorageDead |
|
LvalueContext::StorageDead |
|
||||||
|
LvalueContext::Inspect |
|
||||||
LvalueContext::Consume => {}
|
LvalueContext::Consume => {}
|
||||||
|
|
||||||
LvalueContext::Store |
|
LvalueContext::Store |
|
||||||
LvalueContext::Inspect |
|
|
||||||
LvalueContext::Borrow { .. } |
|
LvalueContext::Borrow { .. } |
|
||||||
LvalueContext::Projection(..) => {
|
LvalueContext::Projection(..) => {
|
||||||
self.mark_as_lvalue(index);
|
self.mark_as_lvalue(index);
|
||||||
|
@ -204,8 +204,6 @@ pub fn cleanup_kinds<'a, 'tcx>(mir: &mir::Mir<'tcx>) -> IndexVec<mir::BasicBlock
|
||||||
TerminatorKind::Resume |
|
TerminatorKind::Resume |
|
||||||
TerminatorKind::Return |
|
TerminatorKind::Return |
|
||||||
TerminatorKind::Unreachable |
|
TerminatorKind::Unreachable |
|
||||||
TerminatorKind::If { .. } |
|
|
||||||
TerminatorKind::Switch { .. } |
|
|
||||||
TerminatorKind::SwitchInt { .. } => {
|
TerminatorKind::SwitchInt { .. } => {
|
||||||
/* nothing to do */
|
/* nothing to do */
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,17 +11,16 @@
|
||||||
use llvm::{self, ValueRef, BasicBlockRef};
|
use llvm::{self, ValueRef, BasicBlockRef};
|
||||||
use rustc_const_eval::{ErrKind, ConstEvalErr, note_const_eval_err};
|
use rustc_const_eval::{ErrKind, ConstEvalErr, note_const_eval_err};
|
||||||
use rustc::middle::lang_items;
|
use rustc::middle::lang_items;
|
||||||
|
use rustc::middle::const_val::ConstInt;
|
||||||
use rustc::ty::{self, layout, TypeFoldable};
|
use rustc::ty::{self, layout, TypeFoldable};
|
||||||
use rustc::mir;
|
use rustc::mir;
|
||||||
use abi::{Abi, FnType, ArgType};
|
use abi::{Abi, FnType, ArgType};
|
||||||
use adt;
|
|
||||||
use base::{self, Lifetime};
|
use base::{self, Lifetime};
|
||||||
use callee::{Callee, CalleeData, Fn, Intrinsic, NamedTupleConstructor, Virtual};
|
use callee::{Callee, CalleeData, Fn, Intrinsic, NamedTupleConstructor, Virtual};
|
||||||
use builder::Builder;
|
use builder::Builder;
|
||||||
use common::{self, Funclet};
|
use common::{self, Funclet};
|
||||||
use common::{C_bool, C_str_slice, C_struct, C_u32, C_undef};
|
use common::{C_bool, C_str_slice, C_struct, C_u32, C_undef};
|
||||||
use consts;
|
use consts;
|
||||||
use Disr;
|
|
||||||
use machine::{llalign_of_min, llbitsize_of_real};
|
use machine::{llalign_of_min, llbitsize_of_real};
|
||||||
use meth;
|
use meth;
|
||||||
use type_of::{self, align_of};
|
use type_of::{self, align_of};
|
||||||
|
@ -29,7 +28,6 @@ use glue;
|
||||||
use type_::Type;
|
use type_::Type;
|
||||||
|
|
||||||
use rustc_data_structures::indexed_vec::IndexVec;
|
use rustc_data_structures::indexed_vec::IndexVec;
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
|
||||||
use syntax::symbol::Symbol;
|
use syntax::symbol::Symbol;
|
||||||
|
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
|
@ -136,61 +134,27 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
||||||
funclet_br(self, bcx, target);
|
funclet_br(self, bcx, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
mir::TerminatorKind::If { ref cond, targets: (true_bb, false_bb) } => {
|
|
||||||
let cond = self.trans_operand(&bcx, cond);
|
|
||||||
|
|
||||||
let lltrue = llblock(self, true_bb);
|
|
||||||
let llfalse = llblock(self, false_bb);
|
|
||||||
bcx.cond_br(cond.immediate(), lltrue, llfalse);
|
|
||||||
}
|
|
||||||
|
|
||||||
mir::TerminatorKind::Switch { ref discr, ref adt_def, ref targets } => {
|
|
||||||
let discr_lvalue = self.trans_lvalue(&bcx, discr);
|
|
||||||
let ty = discr_lvalue.ty.to_ty(bcx.tcx());
|
|
||||||
let discr = adt::trans_get_discr(
|
|
||||||
&bcx, ty, discr_lvalue.llval, discr_lvalue.alignment,
|
|
||||||
None, true);
|
|
||||||
|
|
||||||
let mut bb_hist = FxHashMap();
|
|
||||||
for target in targets {
|
|
||||||
*bb_hist.entry(target).or_insert(0) += 1;
|
|
||||||
}
|
|
||||||
let (default_bb, default_blk) = match bb_hist.iter().max_by_key(|&(_, c)| c) {
|
|
||||||
// If a single target basic blocks is predominant, promote that to be the
|
|
||||||
// default case for the switch instruction to reduce the size of the generated
|
|
||||||
// code. This is especially helpful in cases like an if-let on a huge enum.
|
|
||||||
// Note: This optimization is only valid for exhaustive matches.
|
|
||||||
Some((&&bb, &c)) if c > targets.len() / 2 => {
|
|
||||||
(Some(bb), llblock(self, bb))
|
|
||||||
}
|
|
||||||
// We're generating an exhaustive switch, so the else branch
|
|
||||||
// can't be hit. Branching to an unreachable instruction
|
|
||||||
// lets LLVM know this
|
|
||||||
_ => (None, self.unreachable_block())
|
|
||||||
};
|
|
||||||
let switch = bcx.switch(discr, default_blk, targets.len());
|
|
||||||
assert_eq!(adt_def.variants.len(), targets.len());
|
|
||||||
for (adt_variant, &target) in adt_def.variants.iter().zip(targets) {
|
|
||||||
if default_bb != Some(target) {
|
|
||||||
let llbb = llblock(self, target);
|
|
||||||
let llval = adt::trans_case(&bcx, ty, Disr::from(adt_variant.disr_val));
|
|
||||||
bcx.add_case(switch, llval, llbb)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mir::TerminatorKind::SwitchInt { ref discr, switch_ty, ref values, ref targets } => {
|
mir::TerminatorKind::SwitchInt { ref discr, switch_ty, ref values, ref targets } => {
|
||||||
|
let discr = self.trans_operand(&bcx, discr);
|
||||||
|
if switch_ty == bcx.tcx().types.bool {
|
||||||
|
let lltrue = llblock(self, targets[0]);
|
||||||
|
let llfalse = llblock(self, targets[1]);
|
||||||
|
if let [ConstInt::Infer(0)] = values[..] {
|
||||||
|
bcx.cond_br(discr.immediate(), llfalse, lltrue);
|
||||||
|
} else {
|
||||||
|
bcx.cond_br(discr.immediate(), lltrue, llfalse);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
let (otherwise, targets) = targets.split_last().unwrap();
|
let (otherwise, targets) = targets.split_last().unwrap();
|
||||||
let lv = self.trans_lvalue(&bcx, discr);
|
let switch = bcx.switch(discr.immediate(),
|
||||||
let discr = bcx.load(lv.llval, lv.alignment.to_align());
|
llblock(self, *otherwise), values.len());
|
||||||
let discr = base::to_immediate(&bcx, discr, switch_ty);
|
|
||||||
let switch = bcx.switch(discr, llblock(self, *otherwise), values.len());
|
|
||||||
for (value, target) in values.iter().zip(targets) {
|
for (value, target) in values.iter().zip(targets) {
|
||||||
let val = Const::from_constval(bcx.ccx, value.clone(), switch_ty);
|
let val = Const::from_constint(bcx.ccx, value);
|
||||||
let llbb = llblock(self, *target);
|
let llbb = llblock(self, *target);
|
||||||
bcx.add_case(switch, val.llval, llbb)
|
bcx.add_case(switch, val.llval, llbb)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mir::TerminatorKind::Return => {
|
mir::TerminatorKind::Return => {
|
||||||
let ret = self.fn_ty.ret;
|
let ret = self.fn_ty.ret;
|
||||||
|
|
|
@ -61,6 +61,33 @@ impl<'tcx> Const<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn from_constint<'a>(ccx: &CrateContext<'a, 'tcx>, ci: &ConstInt)
|
||||||
|
-> Const<'tcx> {
|
||||||
|
let tcx = ccx.tcx();
|
||||||
|
let (llval, ty) = match *ci {
|
||||||
|
I8(v) => (C_integral(Type::i8(ccx), v as u64, true), tcx.types.i8),
|
||||||
|
I16(v) => (C_integral(Type::i16(ccx), v as u64, true), tcx.types.i16),
|
||||||
|
I32(v) => (C_integral(Type::i32(ccx), v as u64, true), tcx.types.i32),
|
||||||
|
I64(v) => (C_integral(Type::i64(ccx), v as u64, true), tcx.types.i64),
|
||||||
|
I128(v) => (C_big_integral(Type::i128(ccx), v as u128), tcx.types.i128),
|
||||||
|
Isize(v) => {
|
||||||
|
let i = v.as_i64(ccx.tcx().sess.target.int_type);
|
||||||
|
(C_integral(Type::int(ccx), i as u64, true), tcx.types.isize)
|
||||||
|
},
|
||||||
|
U8(v) => (C_integral(Type::i8(ccx), v as u64, false), tcx.types.u8),
|
||||||
|
U16(v) => (C_integral(Type::i16(ccx), v as u64, false), tcx.types.u16),
|
||||||
|
U32(v) => (C_integral(Type::i32(ccx), v as u64, false), tcx.types.u32),
|
||||||
|
U64(v) => (C_integral(Type::i64(ccx), v, false), tcx.types.u64),
|
||||||
|
U128(v) => (C_big_integral(Type::i128(ccx), v), tcx.types.u128),
|
||||||
|
Usize(v) => {
|
||||||
|
let u = v.as_u64(ccx.tcx().sess.target.uint_type);
|
||||||
|
(C_integral(Type::int(ccx), u, false), tcx.types.usize)
|
||||||
|
},
|
||||||
|
Infer(_) | InferSigned(_) => bug!("MIR must not use `{:?}`", ci),
|
||||||
|
};
|
||||||
|
Const { llval: llval, ty: ty }
|
||||||
|
}
|
||||||
|
|
||||||
/// Translate ConstVal into a LLVM constant value.
|
/// Translate ConstVal into a LLVM constant value.
|
||||||
pub fn from_constval<'a>(ccx: &CrateContext<'a, 'tcx>,
|
pub fn from_constval<'a>(ccx: &CrateContext<'a, 'tcx>,
|
||||||
cv: ConstVal,
|
cv: ConstVal,
|
||||||
|
@ -72,26 +99,7 @@ impl<'tcx> Const<'tcx> {
|
||||||
ConstVal::Float(F64(v)) => C_floating_f64(v, llty),
|
ConstVal::Float(F64(v)) => C_floating_f64(v, llty),
|
||||||
ConstVal::Float(FInfer {..}) => bug!("MIR must not use `{:?}`", cv),
|
ConstVal::Float(FInfer {..}) => bug!("MIR must not use `{:?}`", cv),
|
||||||
ConstVal::Bool(v) => C_bool(ccx, v),
|
ConstVal::Bool(v) => C_bool(ccx, v),
|
||||||
ConstVal::Integral(I8(v)) => C_integral(Type::i8(ccx), v as u64, true),
|
ConstVal::Integral(ref i) => return Const::from_constint(ccx, i),
|
||||||
ConstVal::Integral(I16(v)) => C_integral(Type::i16(ccx), v as u64, true),
|
|
||||||
ConstVal::Integral(I32(v)) => C_integral(Type::i32(ccx), v as u64, true),
|
|
||||||
ConstVal::Integral(I64(v)) => C_integral(Type::i64(ccx), v as u64, true),
|
|
||||||
ConstVal::Integral(I128(v)) => C_big_integral(Type::i128(ccx), v as u128),
|
|
||||||
ConstVal::Integral(Isize(v)) => {
|
|
||||||
let i = v.as_i64(ccx.tcx().sess.target.int_type);
|
|
||||||
C_integral(Type::int(ccx), i as u64, true)
|
|
||||||
},
|
|
||||||
ConstVal::Integral(U8(v)) => C_integral(Type::i8(ccx), v as u64, false),
|
|
||||||
ConstVal::Integral(U16(v)) => C_integral(Type::i16(ccx), v as u64, false),
|
|
||||||
ConstVal::Integral(U32(v)) => C_integral(Type::i32(ccx), v as u64, false),
|
|
||||||
ConstVal::Integral(U64(v)) => C_integral(Type::i64(ccx), v, false),
|
|
||||||
ConstVal::Integral(U128(v)) => C_big_integral(Type::i128(ccx), v),
|
|
||||||
ConstVal::Integral(Usize(v)) => {
|
|
||||||
let u = v.as_u64(ccx.tcx().sess.target.uint_type);
|
|
||||||
C_integral(Type::int(ccx), u, false)
|
|
||||||
},
|
|
||||||
ConstVal::Integral(Infer(_)) |
|
|
||||||
ConstVal::Integral(InferSigned(_)) => bug!("MIR must not use `{:?}`", cv),
|
|
||||||
ConstVal::Str(ref v) => C_str_slice(ccx, v.clone()),
|
ConstVal::Str(ref v) => C_str_slice(ccx, v.clone()),
|
||||||
ConstVal::ByteStr(ref v) => consts::addr_of(ccx, C_bytes(ccx, v), 1, "byte_str"),
|
ConstVal::ByteStr(ref v) => consts::addr_of(ccx, C_bytes(ccx, v), 1, "byte_str"),
|
||||||
ConstVal::Struct(_) | ConstVal::Tuple(_) |
|
ConstVal::Struct(_) | ConstVal::Tuple(_) |
|
||||||
|
|
|
@ -286,17 +286,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
||||||
|
|
||||||
let newval = match (r_t_in, r_t_out) {
|
let newval = match (r_t_in, r_t_out) {
|
||||||
(CastTy::Int(_), CastTy::Int(_)) => {
|
(CastTy::Int(_), CastTy::Int(_)) => {
|
||||||
let srcsz = ll_t_in.int_width();
|
bcx.intcast(llval, ll_t_out, signed)
|
||||||
let dstsz = ll_t_out.int_width();
|
|
||||||
if srcsz == dstsz {
|
|
||||||
bcx.bitcast(llval, ll_t_out)
|
|
||||||
} else if srcsz > dstsz {
|
|
||||||
bcx.trunc(llval, ll_t_out)
|
|
||||||
} else if signed {
|
|
||||||
bcx.sext(llval, ll_t_out)
|
|
||||||
} else {
|
|
||||||
bcx.zext(llval, ll_t_out)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
(CastTy::Float, CastTy::Float) => {
|
(CastTy::Float, CastTy::Float) => {
|
||||||
let srcsz = ll_t_in.float_width();
|
let srcsz = ll_t_in.float_width();
|
||||||
|
@ -433,6 +423,19 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mir::Rvalue::Discriminant(ref lvalue) => {
|
||||||
|
let discr_lvalue = self.trans_lvalue(&bcx, lvalue);
|
||||||
|
let enum_ty = discr_lvalue.ty.to_ty(bcx.tcx());
|
||||||
|
let discr_ty = rvalue.ty(&*self.mir, bcx.tcx()).unwrap();
|
||||||
|
let discr_type = type_of::immediate_type_of(bcx.ccx, discr_ty);
|
||||||
|
let discr = adt::trans_get_discr(&bcx, enum_ty, discr_lvalue.llval,
|
||||||
|
discr_lvalue.alignment, Some(discr_type), true);
|
||||||
|
(bcx, OperandRef {
|
||||||
|
val: OperandValue::Immediate(discr),
|
||||||
|
ty: discr_ty
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
mir::Rvalue::Box(content_ty) => {
|
mir::Rvalue::Box(content_ty) => {
|
||||||
let content_ty: Ty<'tcx> = self.monomorphize(&content_ty);
|
let content_ty: Ty<'tcx> = self.monomorphize(&content_ty);
|
||||||
let llty = type_of::type_of(bcx.ccx, content_ty);
|
let llty = type_of::type_of(bcx.ccx, content_ty);
|
||||||
|
@ -661,6 +664,7 @@ pub fn rvalue_creates_operand(rvalue: &mir::Rvalue) -> bool {
|
||||||
mir::Rvalue::BinaryOp(..) |
|
mir::Rvalue::BinaryOp(..) |
|
||||||
mir::Rvalue::CheckedBinaryOp(..) |
|
mir::Rvalue::CheckedBinaryOp(..) |
|
||||||
mir::Rvalue::UnaryOp(..) |
|
mir::Rvalue::UnaryOp(..) |
|
||||||
|
mir::Rvalue::Discriminant(..) |
|
||||||
mir::Rvalue::Box(..) |
|
mir::Rvalue::Box(..) |
|
||||||
mir::Rvalue::Use(..) =>
|
mir::Rvalue::Use(..) =>
|
||||||
true,
|
true,
|
||||||
|
|
|
@ -1004,9 +1004,8 @@ fn convert_struct_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||||
let did = ccx.tcx.hir.local_def_id(it.id);
|
let did = ccx.tcx.hir.local_def_id(it.id);
|
||||||
// Use separate constructor id for unit/tuple structs and reuse did for braced structs.
|
// Use separate constructor id for unit/tuple structs and reuse did for braced structs.
|
||||||
let ctor_id = if !def.is_struct() { Some(ccx.tcx.hir.local_def_id(def.id())) } else { None };
|
let ctor_id = if !def.is_struct() { Some(ccx.tcx.hir.local_def_id(def.id())) } else { None };
|
||||||
let variants = vec![convert_struct_variant(ccx, ctor_id.unwrap_or(did), it.name,
|
let variants = vec![convert_struct_variant(ccx, ctor_id.unwrap_or(did), it.name, 0, def)];
|
||||||
ConstInt::Infer(0), def)];
|
let adt = ccx.tcx.alloc_adt_def(did, AdtKind::Struct, None, variants,
|
||||||
let adt = ccx.tcx.alloc_adt_def(did, AdtKind::Struct, variants,
|
|
||||||
ReprOptions::new(&ccx.tcx, did));
|
ReprOptions::new(&ccx.tcx, did));
|
||||||
if let Some(ctor_id) = ctor_id {
|
if let Some(ctor_id) = ctor_id {
|
||||||
// Make adt definition available through constructor id as well.
|
// Make adt definition available through constructor id as well.
|
||||||
|
@ -1023,15 +1022,15 @@ fn convert_union_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||||
-> &'tcx ty::AdtDef
|
-> &'tcx ty::AdtDef
|
||||||
{
|
{
|
||||||
let did = ccx.tcx.hir.local_def_id(it.id);
|
let did = ccx.tcx.hir.local_def_id(it.id);
|
||||||
let variants = vec![convert_struct_variant(ccx, did, it.name, ConstInt::Infer(0), def)];
|
let variants = vec![convert_struct_variant(ccx, did, it.name, 0, def)];
|
||||||
|
let adt = ccx.tcx.alloc_adt_def(did, AdtKind::Union, None, variants,
|
||||||
let adt = ccx.tcx.alloc_adt_def(did, AdtKind::Union, variants, ReprOptions::new(&ccx.tcx, did));
|
ReprOptions::new(&ccx.tcx, did));
|
||||||
ccx.tcx.adt_defs.borrow_mut().insert(did, adt);
|
ccx.tcx.adt_defs.borrow_mut().insert(did, adt);
|
||||||
adt
|
adt
|
||||||
}
|
}
|
||||||
|
|
||||||
fn evaluate_disr_expr(ccx: &CrateCtxt, repr_ty: attr::IntType, body: hir::BodyId)
|
fn evaluate_disr_expr(ccx: &CrateCtxt, repr_ty: attr::IntType, body: hir::BodyId)
|
||||||
-> Option<ty::Disr> {
|
-> Option<ConstInt> {
|
||||||
let e = &ccx.tcx.hir.body(body).value;
|
let e = &ccx.tcx.hir.body(body).value;
|
||||||
debug!("disr expr, checking {}", ccx.tcx.hir.node_to_pretty_string(e.id));
|
debug!("disr expr, checking {}", ccx.tcx.hir.node_to_pretty_string(e.id));
|
||||||
|
|
||||||
|
@ -1046,7 +1045,8 @@ fn convert_union_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||||
let hint = UncheckedExprHint(ty_hint);
|
let hint = UncheckedExprHint(ty_hint);
|
||||||
match ConstContext::new(ccx.tcx, body).eval(e, hint) {
|
match ConstContext::new(ccx.tcx, body).eval(e, hint) {
|
||||||
Ok(ConstVal::Integral(i)) => {
|
Ok(ConstVal::Integral(i)) => {
|
||||||
// FIXME: eval should return an error if the hint is wrong
|
// FIXME: eval should return an error if the hint does not match the type of the body.
|
||||||
|
// i.e. eventually the match below would not exist.
|
||||||
match (repr_ty, i) {
|
match (repr_ty, i) {
|
||||||
(attr::SignedInt(ast::IntTy::I8), ConstInt::I8(_)) |
|
(attr::SignedInt(ast::IntTy::I8), ConstInt::I8(_)) |
|
||||||
(attr::SignedInt(ast::IntTy::I16), ConstInt::I16(_)) |
|
(attr::SignedInt(ast::IntTy::I16), ConstInt::I16(_)) |
|
||||||
|
@ -1059,7 +1059,8 @@ fn convert_union_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||||
(attr::UnsignedInt(ast::UintTy::U32), ConstInt::U32(_)) |
|
(attr::UnsignedInt(ast::UintTy::U32), ConstInt::U32(_)) |
|
||||||
(attr::UnsignedInt(ast::UintTy::U64), ConstInt::U64(_)) |
|
(attr::UnsignedInt(ast::UintTy::U64), ConstInt::U64(_)) |
|
||||||
(attr::UnsignedInt(ast::UintTy::U128), ConstInt::U128(_)) |
|
(attr::UnsignedInt(ast::UintTy::U128), ConstInt::U128(_)) |
|
||||||
(attr::UnsignedInt(ast::UintTy::Us), ConstInt::Usize(_)) => Some(i),
|
(attr::UnsignedInt(ast::UintTy::Us), ConstInt::Usize(_)) =>
|
||||||
|
Some(i),
|
||||||
(_, i) => {
|
(_, i) => {
|
||||||
print_err(ConstVal::Integral(i));
|
print_err(ConstVal::Integral(i));
|
||||||
None
|
None
|
||||||
|
@ -1090,13 +1091,17 @@ fn convert_enum_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||||
let did = tcx.hir.local_def_id(it.id);
|
let did = tcx.hir.local_def_id(it.id);
|
||||||
let repr_hints = tcx.lookup_repr_hints(did);
|
let repr_hints = tcx.lookup_repr_hints(did);
|
||||||
let repr_type = tcx.enum_repr_type(repr_hints.get(0));
|
let repr_type = tcx.enum_repr_type(repr_hints.get(0));
|
||||||
let initial = repr_type.initial_discriminant(tcx);
|
let initial = ConstInt::new_inttype(repr_type.initial_discriminant(tcx), repr_type,
|
||||||
let mut prev_disr = None::<ty::Disr>;
|
tcx.sess.target.uint_type, tcx.sess.target.int_type)
|
||||||
|
.unwrap();
|
||||||
|
let mut prev_disr = None::<ConstInt>;
|
||||||
let variants = def.variants.iter().map(|v| {
|
let variants = def.variants.iter().map(|v| {
|
||||||
let wrapped_disr = prev_disr.map_or(initial, |d| d.wrap_incr());
|
let wrapped_disr = prev_disr.map_or(initial, |d| d.wrap_incr());
|
||||||
let disr = if let Some(e) = v.node.disr_expr {
|
let disr = if let Some(e) = v.node.disr_expr {
|
||||||
|
// FIXME: i128 discriminants
|
||||||
evaluate_disr_expr(ccx, repr_type, e)
|
evaluate_disr_expr(ccx, repr_type, e)
|
||||||
} else if let Some(disr) = repr_type.disr_incr(tcx, prev_disr) {
|
} else if let Some(disr) = prev_disr.map_or(Some(initial),
|
||||||
|
|v| (v + ConstInt::Infer(1)).ok()) {
|
||||||
Some(disr)
|
Some(disr)
|
||||||
} else {
|
} else {
|
||||||
struct_span_err!(tcx.sess, v.span, E0370,
|
struct_span_err!(tcx.sess, v.span, E0370,
|
||||||
|
@ -1108,12 +1113,11 @@ fn convert_enum_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||||
None
|
None
|
||||||
}.unwrap_or(wrapped_disr);
|
}.unwrap_or(wrapped_disr);
|
||||||
prev_disr = Some(disr);
|
prev_disr = Some(disr);
|
||||||
|
|
||||||
let did = tcx.hir.local_def_id(v.node.data.id());
|
let did = tcx.hir.local_def_id(v.node.data.id());
|
||||||
convert_struct_variant(ccx, did, v.node.name, disr, &v.node.data)
|
convert_struct_variant(ccx, did, v.node.name, disr.to_u128_unchecked(), &v.node.data)
|
||||||
}).collect();
|
}).collect();
|
||||||
|
let adt = tcx.alloc_adt_def(did, AdtKind::Enum, Some(repr_type), variants,
|
||||||
let adt = tcx.alloc_adt_def(did, AdtKind::Enum, variants, ReprOptions::new(&ccx.tcx, did));
|
ReprOptions::new(&ccx.tcx, did));
|
||||||
tcx.adt_defs.borrow_mut().insert(did, adt);
|
tcx.adt_defs.borrow_mut().insert(did, adt);
|
||||||
adt
|
adt
|
||||||
}
|
}
|
||||||
|
|
|
@ -567,6 +567,34 @@ impl<T:Decodable> Decodable for Vec<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a, T:Encodable> Encodable for Cow<'a, [T]>
|
||||||
|
where [T]: ToOwned<Owned = Vec<T>>
|
||||||
|
{
|
||||||
|
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
|
||||||
|
s.emit_seq(self.len(), |s| {
|
||||||
|
for (i, e) in self.iter().enumerate() {
|
||||||
|
s.emit_seq_elt(i, |s| e.encode(s))?
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T:Decodable+ToOwned> Decodable for Cow<'static, [T]>
|
||||||
|
where [T]: ToOwned<Owned = Vec<T>>
|
||||||
|
{
|
||||||
|
fn decode<D: Decoder>(d: &mut D) -> Result<Cow<'static, [T]>, D::Error> {
|
||||||
|
d.read_seq(|d, len| {
|
||||||
|
let mut v = Vec::with_capacity(len);
|
||||||
|
for i in 0..len {
|
||||||
|
v.push(d.read_seq_elt(i, |d| Decodable::decode(d))?);
|
||||||
|
}
|
||||||
|
Ok(Cow::Owned(v))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
impl<T:Encodable> Encodable for Option<T> {
|
impl<T:Encodable> Encodable for Option<T> {
|
||||||
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
|
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
|
||||||
s.emit_option(|s| {
|
s.emit_option(|s| {
|
||||||
|
|
|
@ -1316,6 +1316,12 @@ extern "C" LLVMRustVisibility LLVMRustGetVisibility(LLVMValueRef V) {
|
||||||
return toRust(LLVMGetVisibility(V));
|
return toRust(LLVMGetVisibility(V));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Oh hey, a binding that makes sense for once? (because LLVM’s own do not)
|
||||||
|
extern "C" LLVMValueRef LLVMRustBuildIntCast(LLVMBuilderRef B, LLVMValueRef Val,
|
||||||
|
LLVMTypeRef DestTy, bool isSigned) {
|
||||||
|
return wrap(unwrap(B)->CreateIntCast(unwrap(Val), unwrap(DestTy), isSigned, ""));
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" void LLVMRustSetVisibility(LLVMValueRef V,
|
extern "C" void LLVMRustSetVisibility(LLVMValueRef V,
|
||||||
LLVMRustVisibility RustVisibility) {
|
LLVMRustVisibility RustVisibility) {
|
||||||
LLVMSetVisibility(V, fromRust(RustVisibility));
|
LLVMSetVisibility(V, fromRust(RustVisibility));
|
||||||
|
|
|
@ -20,9 +20,13 @@ pub enum E {
|
||||||
// CHECK-LABEL: @exhaustive_match
|
// CHECK-LABEL: @exhaustive_match
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub fn exhaustive_match(e: E) {
|
pub fn exhaustive_match(e: E) {
|
||||||
// CHECK: switch{{.*}}, label %[[DEFAULT:[a-zA-Z0-9_]+]]
|
// CHECK: switch{{.*}}, label %[[OTHERWISE:[a-zA-Z0-9_]+]] [
|
||||||
// CHECK: [[DEFAULT]]:
|
// CHECK-NEXT: i[[TY:[0-9]+]] [[DISCR:[0-9]+]], label %[[TRUE:[a-zA-Z0-9_]+]]
|
||||||
// CHECK-NEXT: unreachable
|
// CHECK-NEXT: ]
|
||||||
|
// CHECK: [[TRUE]]:
|
||||||
|
// CHECK-NEXT: br label %[[EXIT:[a-zA-Z0-9_]+]]
|
||||||
|
// CHECK: [[OTHERWISE]]:
|
||||||
|
// CHECK-NEXT: br label %[[EXIT:[a-zA-Z0-9_]+]]
|
||||||
match e {
|
match e {
|
||||||
E::A => (),
|
E::A => (),
|
||||||
E::B => (),
|
E::B => (),
|
||||||
|
|
|
@ -9,10 +9,10 @@
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
enum Enum {
|
enum Enum {
|
||||||
P = 3, //~ NOTE first use of `3isize`
|
P = 3, //~ NOTE first use of `3`
|
||||||
X = 3,
|
X = 3,
|
||||||
//~^ ERROR discriminant value `3isize` already exists
|
//~^ ERROR discriminant value `3` already exists
|
||||||
//~| NOTE enum already has `3isize`
|
//~| NOTE enum already has `3`
|
||||||
Y = 5
|
Y = 5
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,20 +12,20 @@ const N: isize = 1;
|
||||||
|
|
||||||
enum Foo {
|
enum Foo {
|
||||||
A = 1,
|
A = 1,
|
||||||
//~^ NOTE first use of `1isize`
|
//~^ NOTE first use of `1`
|
||||||
//~| NOTE first use of `1isize`
|
//~| NOTE first use of `1`
|
||||||
//~| NOTE first use of `1isize`
|
//~| NOTE first use of `1`
|
||||||
B = 1,
|
B = 1,
|
||||||
//~^ ERROR discriminant value `1isize` already exists
|
//~^ ERROR discriminant value `1` already exists
|
||||||
//~| NOTE enum already has `1isize`
|
//~| NOTE enum already has `1`
|
||||||
C = 0,
|
C = 0,
|
||||||
D,
|
D,
|
||||||
//~^ ERROR discriminant value `1isize` already exists
|
//~^ ERROR discriminant value `1` already exists
|
||||||
//~| NOTE enum already has `1isize`
|
//~| NOTE enum already has `1`
|
||||||
|
|
||||||
E = N,
|
E = N,
|
||||||
//~^ ERROR discriminant value `1isize` already exists
|
//~^ ERROR discriminant value `1` already exists
|
||||||
//~| NOTE enum already has `1isize`
|
//~| NOTE enum already has `1`
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ fn main() {
|
||||||
// END RUST SOURCE
|
// END RUST SOURCE
|
||||||
// START rustc.node4.SimplifyBranches.initial-before.mir
|
// START rustc.node4.SimplifyBranches.initial-before.mir
|
||||||
// bb0: {
|
// bb0: {
|
||||||
// if(const false) -> [true: bb1, false: bb2];
|
// switchInt(const false) -> [0: bb2, otherwise: bb1];
|
||||||
// }
|
// }
|
||||||
// END rustc.node4.SimplifyBranches.initial-before.mir
|
// END rustc.node4.SimplifyBranches.initial-before.mir
|
||||||
// START rustc.node4.SimplifyBranches.initial-after.mir
|
// START rustc.node4.SimplifyBranches.initial-after.mir
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
// aux-build:plugin.rs
|
// aux-build:plugin.rs
|
||||||
|
// ignore-stage1
|
||||||
|
|
||||||
#![feature(proc_macro)]
|
#![feature(proc_macro)]
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
error: proc-macro derive panicked
|
error: proc-macro derive panicked
|
||||||
--> $DIR/issue-36935.rs:17:15
|
--> $DIR/issue-36935.rs:18:15
|
||||||
|
|
|
|
||||||
17 | #[derive(Foo, Bar)]
|
18 | #[derive(Foo, Bar)]
|
||||||
| ^^^
|
| ^^^
|
||||||
|
|
|
|
||||||
= help: message: lolnope
|
= help: message: lolnope
|
||||||
|
|
Loading…
Reference in New Issue